[v1] RISC-V: Support vfadd static rounding mode by mode switching

Message ID 20230629014014.3676175-1-pan2.li@intel.com
State Unresolved
Headers
Series [v1] RISC-V: Support vfadd static rounding mode by mode switching |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Li, Pan2 via Gcc-patches June 29, 2023, 1:40 a.m. UTC
  From: Pan Li <pan2.li@intel.com>

This patch would like to support the vfadd static round mode similar to
the fixed-point. Then the related fsrm instructions will be inserted
correlatively.

Please *NOTE* this PATCH doesn't cover anything about FRM dynamic mode,
it will be implemented in the underlying PATCH(s).

Signed-off-by: Pan Li <pan2.li@intel.com>

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_emit_mode_set): Add emit for FRM.
	(riscv_mode_needed): Likewise.
	(riscv_entity_mode_after): Likewise.
	(riscv_mode_after): Likewise.
	(riscv_mode_entry): Likewise.
	(riscv_mode_exit): Likewise.
	* config/riscv/riscv.h (NUM_MODES_FOR_MODE_SWITCHING): Add number
	for FRM.
	* config/riscv/riscv.md: Add FRM register.
	* config/riscv/vector-iterators.md: Add FRM type.
	* config/riscv/vector.md (frm_mode): Define new attr for FRM mode.
	(fsrm): Define new insn for fsrm instruction.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-1.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-insert-2.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-insert-3.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-insert-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-insert-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 52 ++++++++++++++----
 gcc/config/riscv/riscv.h                      |  4 +-
 gcc/config/riscv/riscv.md                     |  4 +-
 gcc/config/riscv/vector-iterators.md          |  2 +
 gcc/config/riscv/vector.md                    | 53 +++++++++++++++++++
 .../riscv/rvv/base/float-point-frm-insert-1.c | 31 +++++++++++
 .../riscv/rvv/base/float-point-frm-insert-2.c | 14 +++++
 .../riscv/rvv/base/float-point-frm-insert-3.c | 14 +++++
 .../riscv/rvv/base/float-point-frm-insert-4.c | 23 ++++++++
 .../riscv/rvv/base/float-point-frm-insert-5.c | 23 ++++++++
 10 files changed, 206 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
  

Comments

juzhe.zhong@rivai.ai June 29, 2023, 2:23 a.m. UTC | #1
LGTM



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-06-29 09:40
To: gcc-patches
CC: juzhe.zhong; kito.cheng; pan2.li; yanzhang.wang; jeffreyalaw
Subject: [PATCH v1] RISC-V: Support vfadd static rounding mode by mode switching
From: Pan Li <pan2.li@intel.com>
 
This patch would like to support the vfadd static round mode similar to
the fixed-point. Then the related fsrm instructions will be inserted
correlatively.
 
Please *NOTE* this PATCH doesn't cover anything about FRM dynamic mode,
it will be implemented in the underlying PATCH(s).
 
Signed-off-by: Pan Li <pan2.li@intel.com>
 
gcc/ChangeLog:
 
* config/riscv/riscv.cc (riscv_emit_mode_set): Add emit for FRM.
(riscv_mode_needed): Likewise.
(riscv_entity_mode_after): Likewise.
(riscv_mode_after): Likewise.
(riscv_mode_entry): Likewise.
(riscv_mode_exit): Likewise.
* config/riscv/riscv.h (NUM_MODES_FOR_MODE_SWITCHING): Add number
for FRM.
* config/riscv/riscv.md: Add FRM register.
* config/riscv/vector-iterators.md: Add FRM type.
* config/riscv/vector.md (frm_mode): Define new attr for FRM mode.
(fsrm): Define new insn for fsrm instruction.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/float-point-frm-insert-1.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-insert-2.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-insert-3.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-insert-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-insert-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 52 ++++++++++++++----
gcc/config/riscv/riscv.h                      |  4 +-
gcc/config/riscv/riscv.md                     |  4 +-
gcc/config/riscv/vector-iterators.md          |  2 +
gcc/config/riscv/vector.md                    | 53 +++++++++++++++++++
.../riscv/rvv/base/float-point-frm-insert-1.c | 31 +++++++++++
.../riscv/rvv/base/float-point-frm-insert-2.c | 14 +++++
.../riscv/rvv/base/float-point-frm-insert-3.c | 14 +++++
.../riscv/rvv/base/float-point-frm-insert-4.c | 23 ++++++++
.../riscv/rvv/base/float-point-frm-insert-5.c | 23 ++++++++
10 files changed, 206 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 280aa0b33b9..e4dc8115e69 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7669,6 +7669,16 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
       if (mode != VXRM_MODE_NONE && mode != prev_mode)
emit_insn (gen_vxrmsi (gen_int_mode (mode, SImode)));
       break;
+    case RISCV_FRM:
+      if (mode != FRM_MODE_NONE && mode != prev_mode)
+ {
+   rtx scaler = gen_reg_rtx (SImode);
+   rtx imm = gen_int_mode (mode, SImode);
+
+   emit_insn (gen_movsi (scaler, imm));
+   emit_insn (gen_fsrm (scaler, scaler));
+ }
+      break;
     default:
       gcc_unreachable ();
     }
@@ -7680,11 +7690,14 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
static int
riscv_mode_needed (int entity, rtx_insn *insn)
{
+  int code = recog_memoized (insn);
+
   switch (entity)
     {
     case RISCV_VXRM:
-      return recog_memoized (insn) >= 0 ? get_attr_vxrm_mode (insn)
- : VXRM_MODE_NONE;
+      return code >= 0 ? get_attr_vxrm_mode (insn) : VXRM_MODE_NONE;
+    case RISCV_FRM:
+      return code >= 0 ? get_attr_frm_mode (insn) : FRM_MODE_NONE;
     default:
       gcc_unreachable ();
     }
@@ -7715,6 +7728,21 @@ global_state_unknown_p (rtx_insn *insn, unsigned int regno)
   return false;
}
+static int
+riscv_entity_mode_after (int regnum, rtx_insn *insn, int mode,
+ int (*get_attr_mode) (rtx_insn *), int default_mode)
+{
+  if (global_state_unknown_p (insn, regnum))
+    return default_mode;
+  else if (recog_memoized (insn) < 0)
+    return mode;
+
+  rtx reg = gen_rtx_REG (SImode, regnum);
+  bool mentioned_p = reg_mentioned_p (reg, PATTERN (insn));
+
+  return mentioned_p ? get_attr_mode (insn): mode;
+}
+
/* Return the mode that an insn results in.  */
static int
@@ -7723,15 +7751,13 @@ riscv_mode_after (int entity, int mode, rtx_insn *insn)
   switch (entity)
     {
     case RISCV_VXRM:
-      if (global_state_unknown_p (insn, VXRM_REGNUM))
- return VXRM_MODE_NONE;
-      else if (recog_memoized (insn) >= 0)
- return reg_mentioned_p (gen_rtx_REG (SImode, VXRM_REGNUM),
- PATTERN (insn))
- ? get_attr_vxrm_mode (insn)
- : mode;
-      else
- return mode;
+      return riscv_entity_mode_after (VXRM_REGNUM, insn, mode,
+       (int (*)(rtx_insn *)) get_attr_vxrm_mode,
+       VXRM_MODE_NONE);
+    case RISCV_FRM:
+      return riscv_entity_mode_after (FRM_REGNUM, insn, mode,
+       (int (*)(rtx_insn *)) get_attr_frm_mode,
+       FRM_MODE_NONE);
     default:
       gcc_unreachable ();
     }
@@ -7747,6 +7773,8 @@ riscv_mode_entry (int entity)
     {
     case RISCV_VXRM:
       return VXRM_MODE_NONE;
+    case RISCV_FRM:
+      return FRM_MODE_NONE;
     default:
       gcc_unreachable ();
     }
@@ -7762,6 +7790,8 @@ riscv_mode_exit (int entity)
     {
     case RISCV_VXRM:
       return VXRM_MODE_NONE;
+    case RISCV_FRM:
+      return FRM_MODE_NONE;
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index bfd9b7551bc..83dcac165b5 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -849,7 +849,7 @@ typedef struct {
   "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", \
   "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", \
   "fs8", "fs9", "fs10","fs11","ft8", "ft9", "ft10","ft11", \
-  "arg", "frame", "vl", "vtype", "vxrm", "N/A", "N/A", "N/A",   \
+  "arg", "frame", "vl", "vtype", "vxrm", "frm", "N/A", "N/A",   \
   "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
   "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
   "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
@@ -1113,6 +1113,6 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
/* Mode switching (Lazy code motion) for RVV rounding mode instructions.  */
#define OPTIMIZE_MODE_SWITCHING(ENTITY) (TARGET_VECTOR)
-#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE}
+#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, FRM_MODE_NONE}
#endif /* ! GCC_RISCV_H */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 565e8cd27cd..4cd8b9d7c77 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -282,6 +282,7 @@ (define_attr "ext_enabled" "no,yes"
;; rdvlenb     vector byte length vlenb csrr read
;; rdvl        vector length vl csrr read
;; wrvxrm      vector fixed-point rounding mode write
+;; wrfrm       vector floating-point rounding mode write
;; vsetvl      vector configuration-setting instrucions
;; 7. Vector Loads and Stores
;; vlde        vector unit-stride load instructions
@@ -385,7 +386,8 @@ (define_attr "type"
    mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
    fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip,rotate,
    clmul,min,max,minu,maxu,clz,ctz,cpop,
-   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,vsetvl,vlde,vste,vldm,vstm,vlds,vsts,
+   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,wrfrm,vsetvl,
+   vlde,vste,vldm,vstm,vlds,vsts,
    vldux,vldox,vstux,vstox,vldff,vldr,vstr,
    vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,
    vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax,
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 26c1bb7a3d6..50f39b84b24 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -82,6 +82,8 @@ (define_c_enum "unspec" [
   UNSPEC_VCOMPRESS
   UNSPEC_VLEFF
   UNSPEC_MODIFY_VL
+
+  UNSPEC_FSRM
])
(define_mode_iterator V [
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 674e602dec6..fadd9071c6d 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -462,6 +462,38 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
(const_string "rod")]
(const_string "none")))
+;; Defines rounding mode of an floating-point operation.
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,none"
+  (cond
+    [
+      (eq_attr "type" "vfalu")
+      (cond
+ [
+   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
+   (const_string "rne")
+
+   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RTZ")
+   (const_string "rtz")
+
+   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
+   (const_string "rdn")
+
+   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RUP")
+   (const_string "rup")
+
+   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RMM")
+   (const_string "rmm")
+
+   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
+   (const_string "rdn")
+ ]
+ (const_string "none")
+      )
+    ]
+    (const_string "none")
+  )
+)
+
;; -----------------------------------------------------------------
;; ---- Miscellaneous Operations
;; -----------------------------------------------------------------
@@ -538,6 +570,27 @@ (define_insn "vxrmsi"
   [(set_attr "type" "wrvxrm")
    (set_attr "mode" "SI")])
+;; Set FRM
+(define_insn "fsrm"
+  [
+    (set
+      (reg:SI FRM_REGNUM)
+      (unspec:SI
+ [
+   (match_operand:SI 0 "register_operand" "=&r")
+   (match_operand:SI 1 "register_operand" "r")
+ ] UNSPEC_FSRM
+      )
+    )
+  ]
+  "TARGET_VECTOR"
+  "fsrm\t%0,%1"
+  [
+    (set_attr "type" "wrfrm")
+    (set_attr "mode" "SI")
+  ]
+)
+
;; -----------------------------------------------------------------
;; ---- Moves Operations
;; -----------------------------------------------------------------
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
new file mode 100644
index 00000000000..732e0305a3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+typedef float float32_t;
+
+vfloat32m1_t
+test_riscv_vfadd_vv_f32m1_rm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
+  return __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
+}
+
+vfloat32m1_t
+test_vfadd_vv_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, vfloat32m1_t op2,
+ size_t vl) {
+  return __riscv_vfadd_vv_f32m1_m_rm(mask, op1, op2, 1, vl);
+}
+
+vfloat32m1_t
+test_vfadd_vf_f32m1_rm(vfloat32m1_t op1, float32_t op2, size_t vl) {
+  return __riscv_vfadd_vf_f32m1_rm(op1, op2, 2, vl);
+}
+
+vfloat32m1_t
+test_vfadd_vf_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, float32_t op2,
+ size_t vl) {
+  return __riscv_vfadd_vf_f32m1_m_rm(mask, op1, op2, 3, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
new file mode 100644
index 00000000000..72e5d2084b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
+  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
+  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
+  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 0, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
new file mode 100644
index 00000000000..c9e8d0a6eaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
+  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
+  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
+  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 1, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
new file mode 100644
index 00000000000..a288e0be628
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
+      size_t count) {
+  vfloat32m1_t tmp = op1, result;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  for (int i = 0; i < count; i++) {
+    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 1, vl + i);
+    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
+  }
+
+  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
new file mode 100644
index 00000000000..bb77a6efc62
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
+      size_t count) {
+  vfloat32m1_t tmp = op1, result;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  for (int i = 0; i < count; i++) {
+    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 2, vl + i);
+    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
+  }
+
+  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 3 } } */
-- 
2.34.1
  
Kito Cheng June 29, 2023, 2:34 a.m. UTC | #2
LGTM, thanks :)

On Thu, Jun 29, 2023 at 10:24 AM juzhe.zhong@rivai.ai
<juzhe.zhong@rivai.ai> wrote:
>
> LGTM
>
> ________________________________
> juzhe.zhong@rivai.ai
>
>
> From: pan2.li
> Date: 2023-06-29 09:40
> To: gcc-patches
> CC: juzhe.zhong; kito.cheng; pan2.li; yanzhang.wang; jeffreyalaw
> Subject: [PATCH v1] RISC-V: Support vfadd static rounding mode by mode switching
> From: Pan Li <pan2.li@intel.com>
>
> This patch would like to support the vfadd static round mode similar to
> the fixed-point. Then the related fsrm instructions will be inserted
> correlatively.
>
> Please *NOTE* this PATCH doesn't cover anything about FRM dynamic mode,
> it will be implemented in the underlying PATCH(s).
>
> Signed-off-by: Pan Li <pan2.li@intel.com>
>
> gcc/ChangeLog:
>
> * config/riscv/riscv.cc (riscv_emit_mode_set): Add emit for FRM.
> (riscv_mode_needed): Likewise.
> (riscv_entity_mode_after): Likewise.
> (riscv_mode_after): Likewise.
> (riscv_mode_entry): Likewise.
> (riscv_mode_exit): Likewise.
> * config/riscv/riscv.h (NUM_MODES_FOR_MODE_SWITCHING): Add number
> for FRM.
> * config/riscv/riscv.md: Add FRM register.
> * config/riscv/vector-iterators.md: Add FRM type.
> * config/riscv/vector.md (frm_mode): Define new attr for FRM mode.
> (fsrm): Define new insn for fsrm instruction.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/riscv/rvv/base/float-point-frm-insert-1.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-2.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-3.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-4.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-5.c: New test.
> ---
> gcc/config/riscv/riscv.cc                     | 52 ++++++++++++++----
> gcc/config/riscv/riscv.h                      |  4 +-
> gcc/config/riscv/riscv.md                     |  4 +-
> gcc/config/riscv/vector-iterators.md          |  2 +
> gcc/config/riscv/vector.md                    | 53 +++++++++++++++++++
> .../riscv/rvv/base/float-point-frm-insert-1.c | 31 +++++++++++
> .../riscv/rvv/base/float-point-frm-insert-2.c | 14 +++++
> .../riscv/rvv/base/float-point-frm-insert-3.c | 14 +++++
> .../riscv/rvv/base/float-point-frm-insert-4.c | 23 ++++++++
> .../riscv/rvv/base/float-point-frm-insert-5.c | 23 ++++++++
> 10 files changed, 206 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 280aa0b33b9..e4dc8115e69 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -7669,6 +7669,16 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
>        if (mode != VXRM_MODE_NONE && mode != prev_mode)
> emit_insn (gen_vxrmsi (gen_int_mode (mode, SImode)));
>        break;
> +    case RISCV_FRM:
> +      if (mode != FRM_MODE_NONE && mode != prev_mode)
> + {
> +   rtx scaler = gen_reg_rtx (SImode);
> +   rtx imm = gen_int_mode (mode, SImode);
> +
> +   emit_insn (gen_movsi (scaler, imm));
> +   emit_insn (gen_fsrm (scaler, scaler));
> + }
> +      break;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7680,11 +7690,14 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
> static int
> riscv_mode_needed (int entity, rtx_insn *insn)
> {
> +  int code = recog_memoized (insn);
> +
>    switch (entity)
>      {
>      case RISCV_VXRM:
> -      return recog_memoized (insn) >= 0 ? get_attr_vxrm_mode (insn)
> - : VXRM_MODE_NONE;
> +      return code >= 0 ? get_attr_vxrm_mode (insn) : VXRM_MODE_NONE;
> +    case RISCV_FRM:
> +      return code >= 0 ? get_attr_frm_mode (insn) : FRM_MODE_NONE;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7715,6 +7728,21 @@ global_state_unknown_p (rtx_insn *insn, unsigned int regno)
>    return false;
> }
> +static int
> +riscv_entity_mode_after (int regnum, rtx_insn *insn, int mode,
> + int (*get_attr_mode) (rtx_insn *), int default_mode)
> +{
> +  if (global_state_unknown_p (insn, regnum))
> +    return default_mode;
> +  else if (recog_memoized (insn) < 0)
> +    return mode;
> +
> +  rtx reg = gen_rtx_REG (SImode, regnum);
> +  bool mentioned_p = reg_mentioned_p (reg, PATTERN (insn));
> +
> +  return mentioned_p ? get_attr_mode (insn): mode;
> +}
> +
> /* Return the mode that an insn results in.  */
> static int
> @@ -7723,15 +7751,13 @@ riscv_mode_after (int entity, int mode, rtx_insn *insn)
>    switch (entity)
>      {
>      case RISCV_VXRM:
> -      if (global_state_unknown_p (insn, VXRM_REGNUM))
> - return VXRM_MODE_NONE;
> -      else if (recog_memoized (insn) >= 0)
> - return reg_mentioned_p (gen_rtx_REG (SImode, VXRM_REGNUM),
> - PATTERN (insn))
> - ? get_attr_vxrm_mode (insn)
> - : mode;
> -      else
> - return mode;
> +      return riscv_entity_mode_after (VXRM_REGNUM, insn, mode,
> +       (int (*)(rtx_insn *)) get_attr_vxrm_mode,
> +       VXRM_MODE_NONE);
> +    case RISCV_FRM:
> +      return riscv_entity_mode_after (FRM_REGNUM, insn, mode,
> +       (int (*)(rtx_insn *)) get_attr_frm_mode,
> +       FRM_MODE_NONE);
>      default:
>        gcc_unreachable ();
>      }
> @@ -7747,6 +7773,8 @@ riscv_mode_entry (int entity)
>      {
>      case RISCV_VXRM:
>        return VXRM_MODE_NONE;
> +    case RISCV_FRM:
> +      return FRM_MODE_NONE;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7762,6 +7790,8 @@ riscv_mode_exit (int entity)
>      {
>      case RISCV_VXRM:
>        return VXRM_MODE_NONE;
> +    case RISCV_FRM:
> +      return FRM_MODE_NONE;
>      default:
>        gcc_unreachable ();
>      }
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index bfd9b7551bc..83dcac165b5 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -849,7 +849,7 @@ typedef struct {
>    "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", \
>    "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", \
>    "fs8", "fs9", "fs10","fs11","ft8", "ft9", "ft10","ft11", \
> -  "arg", "frame", "vl", "vtype", "vxrm", "N/A", "N/A", "N/A",   \
> +  "arg", "frame", "vl", "vtype", "vxrm", "frm", "N/A", "N/A",   \
>    "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
>    "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
>    "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
> @@ -1113,6 +1113,6 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
> /* Mode switching (Lazy code motion) for RVV rounding mode instructions.  */
> #define OPTIMIZE_MODE_SWITCHING(ENTITY) (TARGET_VECTOR)
> -#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE}
> +#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, FRM_MODE_NONE}
> #endif /* ! GCC_RISCV_H */
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 565e8cd27cd..4cd8b9d7c77 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -282,6 +282,7 @@ (define_attr "ext_enabled" "no,yes"
> ;; rdvlenb     vector byte length vlenb csrr read
> ;; rdvl        vector length vl csrr read
> ;; wrvxrm      vector fixed-point rounding mode write
> +;; wrfrm       vector floating-point rounding mode write
> ;; vsetvl      vector configuration-setting instrucions
> ;; 7. Vector Loads and Stores
> ;; vlde        vector unit-stride load instructions
> @@ -385,7 +386,8 @@ (define_attr "type"
>     mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
>     fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip,rotate,
>     clmul,min,max,minu,maxu,clz,ctz,cpop,
> -   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,vsetvl,vlde,vste,vldm,vstm,vlds,vsts,
> +   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,wrfrm,vsetvl,
> +   vlde,vste,vldm,vstm,vlds,vsts,
>     vldux,vldox,vstux,vstox,vldff,vldr,vstr,
>     vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,
>     vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax,
> diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
> index 26c1bb7a3d6..50f39b84b24 100644
> --- a/gcc/config/riscv/vector-iterators.md
> +++ b/gcc/config/riscv/vector-iterators.md
> @@ -82,6 +82,8 @@ (define_c_enum "unspec" [
>    UNSPEC_VCOMPRESS
>    UNSPEC_VLEFF
>    UNSPEC_MODIFY_VL
> +
> +  UNSPEC_FSRM
> ])
> (define_mode_iterator V [
> diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
> index 674e602dec6..fadd9071c6d 100644
> --- a/gcc/config/riscv/vector.md
> +++ b/gcc/config/riscv/vector.md
> @@ -462,6 +462,38 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
> (const_string "rod")]
> (const_string "none")))
> +;; Defines rounding mode of an floating-point operation.
> +(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,none"
> +  (cond
> +    [
> +      (eq_attr "type" "vfalu")
> +      (cond
> + [
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
> +   (const_string "rne")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RTZ")
> +   (const_string "rtz")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
> +   (const_string "rdn")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RUP")
> +   (const_string "rup")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RMM")
> +   (const_string "rmm")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
> +   (const_string "rdn")
> + ]
> + (const_string "none")
> +      )
> +    ]
> +    (const_string "none")
> +  )
> +)
> +
> ;; -----------------------------------------------------------------
> ;; ---- Miscellaneous Operations
> ;; -----------------------------------------------------------------
> @@ -538,6 +570,27 @@ (define_insn "vxrmsi"
>    [(set_attr "type" "wrvxrm")
>     (set_attr "mode" "SI")])
> +;; Set FRM
> +(define_insn "fsrm"
> +  [
> +    (set
> +      (reg:SI FRM_REGNUM)
> +      (unspec:SI
> + [
> +   (match_operand:SI 0 "register_operand" "=&r")
> +   (match_operand:SI 1 "register_operand" "r")
> + ] UNSPEC_FSRM
> +      )
> +    )
> +  ]
> +  "TARGET_VECTOR"
> +  "fsrm\t%0,%1"
> +  [
> +    (set_attr "type" "wrfrm")
> +    (set_attr "mode" "SI")
> +  ]
> +)
> +
> ;; -----------------------------------------------------------------
> ;; ---- Moves Operations
> ;; -----------------------------------------------------------------
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
> new file mode 100644
> index 00000000000..732e0305a3d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +typedef float float32_t;
> +
> +vfloat32m1_t
> +test_riscv_vfadd_vv_f32m1_rm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
> +  return __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
> +}
> +
> +vfloat32m1_t
> +test_vfadd_vv_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, vfloat32m1_t op2,
> + size_t vl) {
> +  return __riscv_vfadd_vv_f32m1_m_rm(mask, op1, op2, 1, vl);
> +}
> +
> +vfloat32m1_t
> +test_vfadd_vf_f32m1_rm(vfloat32m1_t op1, float32_t op2, size_t vl) {
> +  return __riscv_vfadd_vf_f32m1_rm(op1, op2, 2, vl);
> +}
> +
> +vfloat32m1_t
> +test_vfadd_vf_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, float32_t op2,
> + size_t vl) {
> +  return __riscv_vfadd_vf_f32m1_m_rm(mask, op1, op2, 3, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 4 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 4 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
> new file mode 100644
> index 00000000000..72e5d2084b3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
> +  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
> +  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
> +  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 0, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
> new file mode 100644
> index 00000000000..c9e8d0a6eaf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
> +  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
> +  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
> +  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 1, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 2 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
> new file mode 100644
> index 00000000000..a288e0be628
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
> +      size_t count) {
> +  vfloat32m1_t tmp = op1, result;
> +
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +
> +  for (int i = 0; i < count; i++) {
> +    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 1, vl + i);
> +    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
> +  }
> +
> +  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
> new file mode 100644
> index 00000000000..bb77a6efc62
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
> +      size_t count) {
> +  vfloat32m1_t tmp = op1, result;
> +
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +
> +  for (int i = 0; i < count; i++) {
> +    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 2, vl + i);
> +    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
> +  }
> +
> +  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 3 } } */
> --
> 2.34.1
>
>
  
Li, Pan2 via Gcc-patches June 29, 2023, 4:14 a.m. UTC | #3
Committed, thanks Kito and Juzhe.

pan

-----Original Message-----
From: Kito Cheng <kito.cheng@sifive.com> 
Sent: Thursday, June 29, 2023 10:34 AM
To: juzhe.zhong@rivai.ai
Cc: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>; jeffreyalaw <jeffreyalaw@gmail.com>
Subject: Re: [PATCH v1] RISC-V: Support vfadd static rounding mode by mode switching

LGTM, thanks :)

On Thu, Jun 29, 2023 at 10:24 AM juzhe.zhong@rivai.ai
<juzhe.zhong@rivai.ai> wrote:
>
> LGTM
>
> ________________________________
> juzhe.zhong@rivai.ai
>
>
> From: pan2.li
> Date: 2023-06-29 09:40
> To: gcc-patches
> CC: juzhe.zhong; kito.cheng; pan2.li; yanzhang.wang; jeffreyalaw
> Subject: [PATCH v1] RISC-V: Support vfadd static rounding mode by mode switching
> From: Pan Li <pan2.li@intel.com>
>
> This patch would like to support the vfadd static round mode similar to
> the fixed-point. Then the related fsrm instructions will be inserted
> correlatively.
>
> Please *NOTE* this PATCH doesn't cover anything about FRM dynamic mode,
> it will be implemented in the underlying PATCH(s).
>
> Signed-off-by: Pan Li <pan2.li@intel.com>
>
> gcc/ChangeLog:
>
> * config/riscv/riscv.cc (riscv_emit_mode_set): Add emit for FRM.
> (riscv_mode_needed): Likewise.
> (riscv_entity_mode_after): Likewise.
> (riscv_mode_after): Likewise.
> (riscv_mode_entry): Likewise.
> (riscv_mode_exit): Likewise.
> * config/riscv/riscv.h (NUM_MODES_FOR_MODE_SWITCHING): Add number
> for FRM.
> * config/riscv/riscv.md: Add FRM register.
> * config/riscv/vector-iterators.md: Add FRM type.
> * config/riscv/vector.md (frm_mode): Define new attr for FRM mode.
> (fsrm): Define new insn for fsrm instruction.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/riscv/rvv/base/float-point-frm-insert-1.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-2.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-3.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-4.c: New test.
> * gcc.target/riscv/rvv/base/float-point-frm-insert-5.c: New test.
> ---
> gcc/config/riscv/riscv.cc                     | 52 ++++++++++++++----
> gcc/config/riscv/riscv.h                      |  4 +-
> gcc/config/riscv/riscv.md                     |  4 +-
> gcc/config/riscv/vector-iterators.md          |  2 +
> gcc/config/riscv/vector.md                    | 53 +++++++++++++++++++
> .../riscv/rvv/base/float-point-frm-insert-1.c | 31 +++++++++++
> .../riscv/rvv/base/float-point-frm-insert-2.c | 14 +++++
> .../riscv/rvv/base/float-point-frm-insert-3.c | 14 +++++
> .../riscv/rvv/base/float-point-frm-insert-4.c | 23 ++++++++
> .../riscv/rvv/base/float-point-frm-insert-5.c | 23 ++++++++
> 10 files changed, 206 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
>
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 280aa0b33b9..e4dc8115e69 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -7669,6 +7669,16 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
>        if (mode != VXRM_MODE_NONE && mode != prev_mode)
> emit_insn (gen_vxrmsi (gen_int_mode (mode, SImode)));
>        break;
> +    case RISCV_FRM:
> +      if (mode != FRM_MODE_NONE && mode != prev_mode)
> + {
> +   rtx scaler = gen_reg_rtx (SImode);
> +   rtx imm = gen_int_mode (mode, SImode);
> +
> +   emit_insn (gen_movsi (scaler, imm));
> +   emit_insn (gen_fsrm (scaler, scaler));
> + }
> +      break;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7680,11 +7690,14 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
> static int
> riscv_mode_needed (int entity, rtx_insn *insn)
> {
> +  int code = recog_memoized (insn);
> +
>    switch (entity)
>      {
>      case RISCV_VXRM:
> -      return recog_memoized (insn) >= 0 ? get_attr_vxrm_mode (insn)
> - : VXRM_MODE_NONE;
> +      return code >= 0 ? get_attr_vxrm_mode (insn) : VXRM_MODE_NONE;
> +    case RISCV_FRM:
> +      return code >= 0 ? get_attr_frm_mode (insn) : FRM_MODE_NONE;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7715,6 +7728,21 @@ global_state_unknown_p (rtx_insn *insn, unsigned int regno)
>    return false;
> }
> +static int
> +riscv_entity_mode_after (int regnum, rtx_insn *insn, int mode,
> + int (*get_attr_mode) (rtx_insn *), int default_mode)
> +{
> +  if (global_state_unknown_p (insn, regnum))
> +    return default_mode;
> +  else if (recog_memoized (insn) < 0)
> +    return mode;
> +
> +  rtx reg = gen_rtx_REG (SImode, regnum);
> +  bool mentioned_p = reg_mentioned_p (reg, PATTERN (insn));
> +
> +  return mentioned_p ? get_attr_mode (insn): mode;
> +}
> +
> /* Return the mode that an insn results in.  */
> static int
> @@ -7723,15 +7751,13 @@ riscv_mode_after (int entity, int mode, rtx_insn *insn)
>    switch (entity)
>      {
>      case RISCV_VXRM:
> -      if (global_state_unknown_p (insn, VXRM_REGNUM))
> - return VXRM_MODE_NONE;
> -      else if (recog_memoized (insn) >= 0)
> - return reg_mentioned_p (gen_rtx_REG (SImode, VXRM_REGNUM),
> - PATTERN (insn))
> - ? get_attr_vxrm_mode (insn)
> - : mode;
> -      else
> - return mode;
> +      return riscv_entity_mode_after (VXRM_REGNUM, insn, mode,
> +       (int (*)(rtx_insn *)) get_attr_vxrm_mode,
> +       VXRM_MODE_NONE);
> +    case RISCV_FRM:
> +      return riscv_entity_mode_after (FRM_REGNUM, insn, mode,
> +       (int (*)(rtx_insn *)) get_attr_frm_mode,
> +       FRM_MODE_NONE);
>      default:
>        gcc_unreachable ();
>      }
> @@ -7747,6 +7773,8 @@ riscv_mode_entry (int entity)
>      {
>      case RISCV_VXRM:
>        return VXRM_MODE_NONE;
> +    case RISCV_FRM:
> +      return FRM_MODE_NONE;
>      default:
>        gcc_unreachable ();
>      }
> @@ -7762,6 +7790,8 @@ riscv_mode_exit (int entity)
>      {
>      case RISCV_VXRM:
>        return VXRM_MODE_NONE;
> +    case RISCV_FRM:
> +      return FRM_MODE_NONE;
>      default:
>        gcc_unreachable ();
>      }
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index bfd9b7551bc..83dcac165b5 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -849,7 +849,7 @@ typedef struct {
>    "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", \
>    "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", \
>    "fs8", "fs9", "fs10","fs11","ft8", "ft9", "ft10","ft11", \
> -  "arg", "frame", "vl", "vtype", "vxrm", "N/A", "N/A", "N/A",   \
> +  "arg", "frame", "vl", "vtype", "vxrm", "frm", "N/A", "N/A",   \
>    "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
>    "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
>    "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", \
> @@ -1113,6 +1113,6 @@ extern void riscv_remove_unneeded_save_restore_calls (void);
> /* Mode switching (Lazy code motion) for RVV rounding mode instructions.  */
> #define OPTIMIZE_MODE_SWITCHING(ENTITY) (TARGET_VECTOR)
> -#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE}
> +#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, FRM_MODE_NONE}
> #endif /* ! GCC_RISCV_H */
> diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> index 565e8cd27cd..4cd8b9d7c77 100644
> --- a/gcc/config/riscv/riscv.md
> +++ b/gcc/config/riscv/riscv.md
> @@ -282,6 +282,7 @@ (define_attr "ext_enabled" "no,yes"
> ;; rdvlenb     vector byte length vlenb csrr read
> ;; rdvl        vector length vl csrr read
> ;; wrvxrm      vector fixed-point rounding mode write
> +;; wrfrm       vector floating-point rounding mode write
> ;; vsetvl      vector configuration-setting instrucions
> ;; 7. Vector Loads and Stores
> ;; vlde        vector unit-stride load instructions
> @@ -385,7 +386,8 @@ (define_attr "type"
>     mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
>     fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip,rotate,
>     clmul,min,max,minu,maxu,clz,ctz,cpop,
> -   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,vsetvl,vlde,vste,vldm,vstm,vlds,vsts,
> +   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,wrfrm,vsetvl,
> +   vlde,vste,vldm,vstm,vlds,vsts,
>     vldux,vldox,vstux,vstox,vldff,vldr,vstr,
>     vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,
>     vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax,
> diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
> index 26c1bb7a3d6..50f39b84b24 100644
> --- a/gcc/config/riscv/vector-iterators.md
> +++ b/gcc/config/riscv/vector-iterators.md
> @@ -82,6 +82,8 @@ (define_c_enum "unspec" [
>    UNSPEC_VCOMPRESS
>    UNSPEC_VLEFF
>    UNSPEC_MODIFY_VL
> +
> +  UNSPEC_FSRM
> ])
> (define_mode_iterator V [
> diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
> index 674e602dec6..fadd9071c6d 100644
> --- a/gcc/config/riscv/vector.md
> +++ b/gcc/config/riscv/vector.md
> @@ -462,6 +462,38 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
> (const_string "rod")]
> (const_string "none")))
> +;; Defines rounding mode of an floating-point operation.
> +(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,none"
> +  (cond
> +    [
> +      (eq_attr "type" "vfalu")
> +      (cond
> + [
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
> +   (const_string "rne")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RTZ")
> +   (const_string "rtz")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
> +   (const_string "rdn")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RUP")
> +   (const_string "rup")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RMM")
> +   (const_string "rmm")
> +
> +   (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
> +   (const_string "rdn")
> + ]
> + (const_string "none")
> +      )
> +    ]
> +    (const_string "none")
> +  )
> +)
> +
> ;; -----------------------------------------------------------------
> ;; ---- Miscellaneous Operations
> ;; -----------------------------------------------------------------
> @@ -538,6 +570,27 @@ (define_insn "vxrmsi"
>    [(set_attr "type" "wrvxrm")
>     (set_attr "mode" "SI")])
> +;; Set FRM
> +(define_insn "fsrm"
> +  [
> +    (set
> +      (reg:SI FRM_REGNUM)
> +      (unspec:SI
> + [
> +   (match_operand:SI 0 "register_operand" "=&r")
> +   (match_operand:SI 1 "register_operand" "r")
> + ] UNSPEC_FSRM
> +      )
> +    )
> +  ]
> +  "TARGET_VECTOR"
> +  "fsrm\t%0,%1"
> +  [
> +    (set_attr "type" "wrfrm")
> +    (set_attr "mode" "SI")
> +  ]
> +)
> +
> ;; -----------------------------------------------------------------
> ;; ---- Moves Operations
> ;; -----------------------------------------------------------------
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
> new file mode 100644
> index 00000000000..732e0305a3d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +typedef float float32_t;
> +
> +vfloat32m1_t
> +test_riscv_vfadd_vv_f32m1_rm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
> +  return __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
> +}
> +
> +vfloat32m1_t
> +test_vfadd_vv_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, vfloat32m1_t op2,
> + size_t vl) {
> +  return __riscv_vfadd_vv_f32m1_m_rm(mask, op1, op2, 1, vl);
> +}
> +
> +vfloat32m1_t
> +test_vfadd_vf_f32m1_rm(vfloat32m1_t op1, float32_t op2, size_t vl) {
> +  return __riscv_vfadd_vf_f32m1_rm(op1, op2, 2, vl);
> +}
> +
> +vfloat32m1_t
> +test_vfadd_vf_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, float32_t op2,
> + size_t vl) {
> +  return __riscv_vfadd_vf_f32m1_m_rm(mask, op1, op2, 3, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 4 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 4 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
> new file mode 100644
> index 00000000000..72e5d2084b3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
> +  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
> +  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
> +  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 0, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
> new file mode 100644
> index 00000000000..c9e8d0a6eaf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
> +  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
> +  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
> +  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 1, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 2 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
> new file mode 100644
> index 00000000000..a288e0be628
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
> +      size_t count) {
> +  vfloat32m1_t tmp = op1, result;
> +
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +
> +  for (int i = 0; i < count; i++) {
> +    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 1, vl + i);
> +    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
> +  }
> +
> +  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
> diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
> new file mode 100644
> index 00000000000..bb77a6efc62
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
> +
> +#include "riscv_vector.h"
> +
> +vfloat32m1_t
> +test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
> +      size_t count) {
> +  vfloat32m1_t tmp = op1, result;
> +
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
> +  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +
> +  for (int i = 0; i < count; i++) {
> +    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 2, vl + i);
> +    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
> +  }
> +
> +  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
> +}
> +
> +/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
> +/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 3 } } */
> --
> 2.34.1
>
>
  

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 280aa0b33b9..e4dc8115e69 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7669,6 +7669,16 @@  riscv_emit_mode_set (int entity, int mode, int prev_mode,
       if (mode != VXRM_MODE_NONE && mode != prev_mode)
 	emit_insn (gen_vxrmsi (gen_int_mode (mode, SImode)));
       break;
+    case RISCV_FRM:
+      if (mode != FRM_MODE_NONE && mode != prev_mode)
+	{
+	  rtx scaler = gen_reg_rtx (SImode);
+	  rtx imm = gen_int_mode (mode, SImode);
+
+	  emit_insn (gen_movsi (scaler, imm));
+	  emit_insn (gen_fsrm (scaler, scaler));
+	}
+      break;
     default:
       gcc_unreachable ();
     }
@@ -7680,11 +7690,14 @@  riscv_emit_mode_set (int entity, int mode, int prev_mode,
 static int
 riscv_mode_needed (int entity, rtx_insn *insn)
 {
+  int code = recog_memoized (insn);
+
   switch (entity)
     {
     case RISCV_VXRM:
-      return recog_memoized (insn) >= 0 ? get_attr_vxrm_mode (insn)
-					: VXRM_MODE_NONE;
+      return code >= 0 ? get_attr_vxrm_mode (insn) : VXRM_MODE_NONE;
+    case RISCV_FRM:
+      return code >= 0 ? get_attr_frm_mode (insn) : FRM_MODE_NONE;
     default:
       gcc_unreachable ();
     }
@@ -7715,6 +7728,21 @@  global_state_unknown_p (rtx_insn *insn, unsigned int regno)
   return false;
 }
 
+static int
+riscv_entity_mode_after (int regnum, rtx_insn *insn, int mode,
+			 int (*get_attr_mode) (rtx_insn *), int default_mode)
+{
+  if (global_state_unknown_p (insn, regnum))
+    return default_mode;
+  else if (recog_memoized (insn) < 0)
+    return mode;
+
+  rtx reg = gen_rtx_REG (SImode, regnum);
+  bool mentioned_p = reg_mentioned_p (reg, PATTERN (insn));
+
+  return mentioned_p ? get_attr_mode (insn): mode;
+}
+
 /* Return the mode that an insn results in.  */
 
 static int
@@ -7723,15 +7751,13 @@  riscv_mode_after (int entity, int mode, rtx_insn *insn)
   switch (entity)
     {
     case RISCV_VXRM:
-      if (global_state_unknown_p (insn, VXRM_REGNUM))
-	return VXRM_MODE_NONE;
-      else if (recog_memoized (insn) >= 0)
-	return reg_mentioned_p (gen_rtx_REG (SImode, VXRM_REGNUM),
-				PATTERN (insn))
-		 ? get_attr_vxrm_mode (insn)
-		 : mode;
-      else
-	return mode;
+      return riscv_entity_mode_after (VXRM_REGNUM, insn, mode,
+				      (int (*)(rtx_insn *)) get_attr_vxrm_mode,
+				      VXRM_MODE_NONE);
+    case RISCV_FRM:
+      return riscv_entity_mode_after (FRM_REGNUM, insn, mode,
+				      (int (*)(rtx_insn *)) get_attr_frm_mode,
+				      FRM_MODE_NONE);
     default:
       gcc_unreachable ();
     }
@@ -7747,6 +7773,8 @@  riscv_mode_entry (int entity)
     {
     case RISCV_VXRM:
       return VXRM_MODE_NONE;
+    case RISCV_FRM:
+      return FRM_MODE_NONE;
     default:
       gcc_unreachable ();
     }
@@ -7762,6 +7790,8 @@  riscv_mode_exit (int entity)
     {
     case RISCV_VXRM:
       return VXRM_MODE_NONE;
+    case RISCV_FRM:
+      return FRM_MODE_NONE;
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index bfd9b7551bc..83dcac165b5 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -849,7 +849,7 @@  typedef struct {
   "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",	\
   "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",	\
   "fs8", "fs9", "fs10","fs11","ft8", "ft9", "ft10","ft11",	\
-  "arg", "frame", "vl", "vtype", "vxrm", "N/A", "N/A", "N/A",   \
+  "arg", "frame", "vl", "vtype", "vxrm", "frm", "N/A", "N/A",   \
   "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A",	\
   "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A",	\
   "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A", "N/A",	\
@@ -1113,6 +1113,6 @@  extern void riscv_remove_unneeded_save_restore_calls (void);
 
 /* Mode switching (Lazy code motion) for RVV rounding mode instructions.  */
 #define OPTIMIZE_MODE_SWITCHING(ENTITY) (TARGET_VECTOR)
-#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE}
+#define NUM_MODES_FOR_MODE_SWITCHING {VXRM_MODE_NONE, FRM_MODE_NONE}
 
 #endif /* ! GCC_RISCV_H */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 565e8cd27cd..4cd8b9d7c77 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -282,6 +282,7 @@  (define_attr "ext_enabled" "no,yes"
 ;; rdvlenb     vector byte length vlenb csrr read
 ;; rdvl        vector length vl csrr read
 ;; wrvxrm      vector fixed-point rounding mode write
+;; wrfrm       vector floating-point rounding mode write
 ;; vsetvl      vector configuration-setting instrucions
 ;; 7. Vector Loads and Stores
 ;; vlde        vector unit-stride load instructions
@@ -385,7 +386,8 @@  (define_attr "type"
    mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
    fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,ghost,bitmanip,rotate,
    clmul,min,max,minu,maxu,clz,ctz,cpop,
-   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,vsetvl,vlde,vste,vldm,vstm,vlds,vsts,
+   atomic,condmove,crypto,rdvlenb,rdvl,wrvxrm,wrfrm,vsetvl,
+   vlde,vste,vldm,vstm,vlds,vsts,
    vldux,vldox,vstux,vstox,vldff,vldr,vstr,
    vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,
    vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax,
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 26c1bb7a3d6..50f39b84b24 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -82,6 +82,8 @@  (define_c_enum "unspec" [
   UNSPEC_VCOMPRESS
   UNSPEC_VLEFF
   UNSPEC_MODIFY_VL
+
+  UNSPEC_FSRM
 ])
 
 (define_mode_iterator V [
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 674e602dec6..fadd9071c6d 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -462,6 +462,38 @@  (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
 	 (const_string "rod")]
 	 (const_string "none")))
 
+;; Defines rounding mode of an floating-point operation.
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,none"
+  (cond
+    [
+      (eq_attr "type" "vfalu")
+      (cond
+	[
+	  (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
+	  (const_string "rne")
+
+	  (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RTZ")
+	  (const_string "rtz")
+
+	  (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
+	  (const_string "rdn")
+
+	  (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RUP")
+	  (const_string "rup")
+
+	  (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RMM")
+	  (const_string "rmm")
+
+	  (match_test "INTVAL (operands[9]) == riscv_vector::FRM_RDN")
+	  (const_string "rdn")
+	]
+	(const_string "none")
+      )
+    ]
+    (const_string "none")
+  )
+)
+
 ;; -----------------------------------------------------------------
 ;; ---- Miscellaneous Operations
 ;; -----------------------------------------------------------------
@@ -538,6 +570,27 @@  (define_insn "vxrmsi"
   [(set_attr "type" "wrvxrm")
    (set_attr "mode" "SI")])
 
+;; Set FRM
+(define_insn "fsrm"
+  [
+    (set
+      (reg:SI FRM_REGNUM)
+      (unspec:SI
+	[
+	  (match_operand:SI 0 "register_operand" "=&r")
+	  (match_operand:SI 1 "register_operand" "r")
+	] UNSPEC_FSRM
+      )
+    )
+  ]
+  "TARGET_VECTOR"
+  "fsrm\t%0,%1"
+  [
+    (set_attr "type" "wrfrm")
+    (set_attr "mode" "SI")
+  ]
+)
+
 ;; -----------------------------------------------------------------
 ;; ---- Moves Operations
 ;; -----------------------------------------------------------------
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
new file mode 100644
index 00000000000..732e0305a3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-1.c
@@ -0,0 +1,31 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+typedef float float32_t;
+
+vfloat32m1_t
+test_riscv_vfadd_vv_f32m1_rm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
+  return __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
+}
+
+vfloat32m1_t
+test_vfadd_vv_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, vfloat32m1_t op2,
+			 size_t vl) {
+  return __riscv_vfadd_vv_f32m1_m_rm(mask, op1, op2, 1, vl);
+}
+
+vfloat32m1_t
+test_vfadd_vf_f32m1_rm(vfloat32m1_t op1, float32_t op2, size_t vl) {
+  return __riscv_vfadd_vf_f32m1_rm(op1, op2, 2, vl);
+}
+
+vfloat32m1_t
+test_vfadd_vf_f32m1_m_rm(vbool32_t mask, vfloat32m1_t op1, float32_t op2,
+			 size_t vl) {
+  return __riscv_vfadd_vf_f32m1_m_rm(mask, op1, op2, 3, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
new file mode 100644
index 00000000000..72e5d2084b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-2.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
+  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
+  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
+  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 0, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
new file mode 100644
index 00000000000..c9e8d0a6eaf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-3.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) {
+  vfloat32m1_t v1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 0, vl);
+  vfloat32m1_t v2 = __riscv_vfmin_vv_f32m1 (op1, v1, vl);
+  return __riscv_vfadd_vv_f32m1_rm (v1, v2, 1, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
new file mode 100644
index 00000000000..a288e0be628
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-4.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
+			     size_t count) {
+  vfloat32m1_t tmp = op1, result;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  for (int i = 0; i < count; i++) {
+    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 1, vl + i);
+    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
+  }
+
+  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
new file mode 100644
index 00000000000..bb77a6efc62
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-5.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+vfloat32m1_t
+test_float_point_frm_insert (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl,
+			     size_t count) {
+  vfloat32m1_t tmp = op1, result;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op1, 1, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  for (int i = 0; i < count; i++) {
+    tmp = __riscv_vfadd_vv_f32m1_rm (op1, tmp, 2, vl + i);
+    result = __riscv_vfrsqrt7_v_f32m1 (tmp, vl + i);
+  }
+
+  return __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.vv\s+v[0-9]+,\s*v[0-9]+,\s*v+[0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[ax][0-9]+,\s*[ax][0-9]+} 3 } } */