public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding
@ 2023-07-19  3:28 pan2.li
  2023-07-19  3:31 ` juzhe.zhong
                   ` (5 more replies)
  0 siblings, 6 replies; 49+ messages in thread
From: pan2.li @ 2023-07-19  3:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, pan2.li, yanzhang.wang, kito.cheng

From: Pan Li <pan2.li@intel.com>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (struct machine_function): Add new field
	static_frm_p.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Fix
	tests cases.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 73 +++++++++++++++-
 gcc/config/riscv/vector.md                    |  4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     | 31 +++++++
 .../rvv/base/float-point-dynamic-frm-34.c     | 32 +++++++
 .../rvv/base/float-point-dynamic-frm-35.c     | 32 +++++++
 .../rvv/base/float-point-dynamic-frm-36.c     | 29 +++++++
 .../rvv/base/float-point-dynamic-frm-37.c     | 36 ++++++++
 .../rvv/base/float-point-dynamic-frm-38.c     | 34 ++++++++
 .../rvv/base/float-point-dynamic-frm-39.c     | 36 ++++++++
 .../rvv/base/float-point-dynamic-frm-40.c     | 34 ++++++++
 .../rvv/base/float-point-dynamic-frm-41.c     | 37 +++++++++
 .../rvv/base/float-point-dynamic-frm-42.c     | 37 +++++++++
 .../rvv/base/float-point-dynamic-frm-43.c     | 38 +++++++++
 .../rvv/base/float-point-dynamic-frm-44.c     | 40 +++++++++
 .../riscv/rvv/base/float-point-frm-insert-7.c |  5 +-
 .../riscv/rvv/base/float-point-frm-run-4.c    | 82 ++++++++++++++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    | 83 +++++++++++++++++++
 17 files changed, 655 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a45c52a2437..e65520ee8a2 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -151,6 +151,10 @@ struct GTY(())  machine_function {
   /* The RTL variable which stores the dynamic FRM value.  We always use this
      RTX to restore dynamic FRM rounding mode in mode switching.  */
   rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
 };
 
 /* Information about a single argument.  */
@@ -7669,9 +7673,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = cfun->machine->dynamic_frm;
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7681,9 +7689,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN
+	&& prev_mode != FRM_MODE_DYN_CALL && cfun->machine->static_frm_p)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7713,6 +7725,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+
+	 TODO: this cannot handle one case if there is no instruction
+	 after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+	{
+	  if (INSN_P (insn))
+	    {
+	      if (CALL_P (insn))
+		mode = FRM_MODE_DYN;
+	      break;
+	    }
+
+	  if (insn == PREV_INSN (BB_HEAD (bb)))
+	    break;
+	}
+    }
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7726,7 +7785,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7803,6 +7862,12 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  cfun->machine->static_frm_p = cfun->machine->static_frm_p
+    || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 215ecb9cb58..8b354e593ce 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -475,7 +475,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
 )
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -610,7 +610,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
 }
 
 /* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
 /* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+		"The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
@ 2023-07-19  3:31 ` juzhe.zhong
  2023-07-19  6:30   ` Li, Pan2
  2023-07-20  6:43 ` [PATCH v4] " pan2.li
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 49+ messages in thread
From: juzhe.zhong @ 2023-07-19  3:31 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: pan2.li, yanzhang.wang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 32099 bytes --]

   /* The RTL variable which stores the dynamic FRM value.  We always use this
      RTX to restore dynamic FRM rounding mode in mode switching.  */
   rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;


Add a structure wrapper to wrap these 2 variable up.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-07-19 11:28
To: gcc-patches
CC: juzhe.zhong; pan2.li; yanzhang.wang; kito.cheng
Subject: [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com>
 
In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.
 
During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.
 
1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.
 
We will perfrom some steps to make above happen.
 
1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.
 
Let's take a flow for this.
 
           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+
 
Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>
 
gcc/ChangeLog:
 
* config/riscv/riscv.cc (struct machine_function): Add new field
static_frm_p.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Fix
tests cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 73 +++++++++++++++-
gcc/config/riscv/vector.md                    |  4 +-
.../rvv/base/float-point-dynamic-frm-33.c     | 31 +++++++
.../rvv/base/float-point-dynamic-frm-34.c     | 32 +++++++
.../rvv/base/float-point-dynamic-frm-35.c     | 32 +++++++
.../rvv/base/float-point-dynamic-frm-36.c     | 29 +++++++
.../rvv/base/float-point-dynamic-frm-37.c     | 36 ++++++++
.../rvv/base/float-point-dynamic-frm-38.c     | 34 ++++++++
.../rvv/base/float-point-dynamic-frm-39.c     | 36 ++++++++
.../rvv/base/float-point-dynamic-frm-40.c     | 34 ++++++++
.../rvv/base/float-point-dynamic-frm-41.c     | 37 +++++++++
.../rvv/base/float-point-dynamic-frm-42.c     | 37 +++++++++
.../rvv/base/float-point-dynamic-frm-43.c     | 38 +++++++++
.../rvv/base/float-point-dynamic-frm-44.c     | 40 +++++++++
.../riscv/rvv/base/float-point-frm-insert-7.c |  5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    | 82 ++++++++++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    | 83 +++++++++++++++++++
17 files changed, 655 insertions(+), 8 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a45c52a2437..e65520ee8a2 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -151,6 +151,10 @@ struct GTY(())  machine_function {
   /* The RTL variable which stores the dynamic FRM value.  We always use this
      RTX to restore dynamic FRM rounding mode in mode switching.  */
   rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
};
/* Information about a single argument.  */
@@ -7669,9 +7673,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = cfun->machine->dynamic_frm;
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7681,9 +7689,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN
+ && prev_mode != FRM_MODE_DYN_CALL && cfun->machine->static_frm_p)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7713,6 +7725,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+
+ TODO: this cannot handle one case if there is no instruction
+ after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+ {
+   if (INSN_P (insn))
+     {
+       if (CALL_P (insn))
+ mode = FRM_MODE_DYN;
+       break;
+     }
+
+   if (insn == PREV_INSN (BB_HEAD (bb)))
+     break;
+ }
+    }
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7726,7 +7785,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7803,6 +7862,12 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  cfun->machine->static_frm_p = cfun->machine->static_frm_p
+    || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 215ecb9cb58..8b354e593ce 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -475,7 +475,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -610,7 +610,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:31 ` juzhe.zhong
@ 2023-07-19  6:30   ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-19  6:30 UTC (permalink / raw)
  To: juzhe.zhong, gcc-patches; +Cc: Wang, Yanzhang, kito.cheng

[-- Attachment #1: Type: text/plain, Size: 32918 bytes --]

Thanks Juzhe for review, updated PATCH v2 with rvv.exp/riscv.exp passed as below.

https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624864.html

Pan

From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Wednesday, July 19, 2023 11:31 AM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Li, Pan2 <pan2.li@intel.com>; Wang, Yanzhang <yanzhang.wang@intel.com>; kito.cheng <kito.cheng@gmail.com>
Subject: Re: [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding

   /* The RTL variable which stores the dynamic FRM value.  We always use this
      RTX to restore dynamic FRM rounding mode in mode switching.  */
   rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;


Add a structure wrapper to wrap these 2 variable up.

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: pan2.li<mailto:pan2.li@intel.com>
Date: 2023-07-19 11:28
To: gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>; kito.cheng<mailto:kito.cheng@gmail.com>
Subject: [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.

Signed-off-by: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>

gcc/ChangeLog:

* config/riscv/riscv.cc (struct machine_function): Add new field
static_frm_p.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Fix
tests cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 73 +++++++++++++++-
gcc/config/riscv/vector.md                    |  4 +-
.../rvv/base/float-point-dynamic-frm-33.c     | 31 +++++++
.../rvv/base/float-point-dynamic-frm-34.c     | 32 +++++++
.../rvv/base/float-point-dynamic-frm-35.c     | 32 +++++++
.../rvv/base/float-point-dynamic-frm-36.c     | 29 +++++++
.../rvv/base/float-point-dynamic-frm-37.c     | 36 ++++++++
.../rvv/base/float-point-dynamic-frm-38.c     | 34 ++++++++
.../rvv/base/float-point-dynamic-frm-39.c     | 36 ++++++++
.../rvv/base/float-point-dynamic-frm-40.c     | 34 ++++++++
.../rvv/base/float-point-dynamic-frm-41.c     | 37 +++++++++
.../rvv/base/float-point-dynamic-frm-42.c     | 37 +++++++++
.../rvv/base/float-point-dynamic-frm-43.c     | 38 +++++++++
.../rvv/base/float-point-dynamic-frm-44.c     | 40 +++++++++
.../riscv/rvv/base/float-point-frm-insert-7.c |  5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    | 82 ++++++++++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    | 83 +++++++++++++++++++
17 files changed, 655 insertions(+), 8 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a45c52a2437..e65520ee8a2 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -151,6 +151,10 @@ struct GTY(())  machine_function {
   /* The RTL variable which stores the dynamic FRM value.  We always use this
      RTX to restore dynamic FRM rounding mode in mode switching.  */
   rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
};
/* Information about a single argument.  */
@@ -7669,9 +7673,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = cfun->machine->dynamic_frm;
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7681,9 +7689,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN
+ && prev_mode != FRM_MODE_DYN_CALL && cfun->machine->static_frm_p)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7713,6 +7725,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+
+ TODO: this cannot handle one case if there is no instruction
+ after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+ {
+   if (INSN_P (insn))
+     {
+       if (CALL_P (insn))
+ mode = FRM_MODE_DYN;
+       break;
+     }
+
+   if (insn == PREV_INSN (BB_HEAD (bb)))
+     break;
+ }
+    }
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7726,7 +7785,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7803,6 +7862,12 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  cfun->machine->static_frm_p = cfun->machine->static_frm_p
+    || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 215ecb9cb58..8b354e593ce 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -475,7 +475,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -610,7 +610,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
--
2.34.1



^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
  2023-07-19  3:31 ` juzhe.zhong
@ 2023-07-20  6:43 ` pan2.li
  2023-07-20  6:47   ` juzhe.zhong
  2023-07-21  3:11   ` juzhe.zhong
  2023-07-23 13:11 ` [PATCH v5] " pan2.li
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 49+ messages in thread
From: pan2.li @ 2023-07-20  6:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, pan2.li, yanzhang.wang

From: Pan Li <pan2.li@intel.com>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
	(STATIC_FRM_P): Ditto.
	(struct mode_switching_info): New struct for mode switching.
	(struct machine_function): Add new field mode switching.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
	test cases.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 100 ++++++++++++++++--
 gcc/config/riscv/vector.md                    |   4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++++
 .../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++++
 .../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++++
 .../rvv/base/float-point-dynamic-frm-36.c     |  29 +++++
 .../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++++
 .../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++++
 .../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++++
 .../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++++
 .../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++++
 .../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++++
 .../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++++
 .../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++++
 .../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++++
 .../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++++
 .../rvv/base/float-point-dynamic-frm-70.c     |  28 +++++
 .../rvv/base/float-point-dynamic-frm-71.c     |  28 +++++
 .../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
 .../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    |  83 +++++++++++++++
 44 files changed, 1657 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..5ffd8945b6b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -90,6 +90,12 @@ along with GCC; see the file COPYING3.  If not see
 /* True if bit BIT is set in VALUE.  */
 #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
 
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +131,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +170,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
 
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
 };
 
 /* Information about a single argument.  */
@@ -7709,9 +7729,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7745,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+	&& prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7781,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+
+	 TODO: this cannot handle one case if there is no instruction
+	 after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+	{
+	  if (INSN_P (insn))
+	    {
+	      if (CALL_P (insn))
+		mode = FRM_MODE_DYN;
+	      break;
+	    }
+
+	  if (insn == PREV_INSN (BB_HEAD (bb)))
+	    break;
+	}
+    }
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7766,7 +7841,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7918,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
@@ -7883,10 +7963,10 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
-	if (!cfun->machine->dynamic_frm)
+	if (!DYNAMIC_FRM_RTL(cfun))
 	  {
-	    cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-	    emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
+	    DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+	    emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
 	  }
 
 	  /* According to RVV 1.0 spec, all vector floating-point operations use
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
 )
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
 }
 
 /* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
 /* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+		"The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-20  6:43 ` [PATCH v4] " pan2.li
@ 2023-07-20  6:47   ` juzhe.zhong
  2023-07-21  3:11   ` juzhe.zhong
  1 sibling, 0 replies; 49+ messages in thread
From: juzhe.zhong @ 2023-07-20  6:47 UTC (permalink / raw)
  To: pan2.li, gcc-patches
  Cc: Kito.cheng, pan2.li, yanzhang.wang, jeffreyalaw, Robin Dapp

[-- Attachment #1: Type: text/plain, Size: 78761 bytes --]

LGTM from my side but plz wait for comments from other reviewers.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-07-20 14:43
To: gcc-patches
CC: juzhe.zhong; kito.cheng; pan2.li; yanzhang.wang
Subject: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com>
 
In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.
 
During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.
 
1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.
 
We will perfrom some steps to make above happen.
 
1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.
 
Let's take a flow for this.
 
           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+
 
Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>
 
gcc/ChangeLog:
 
* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
(STATIC_FRM_P): Ditto.
(struct mode_switching_info): New struct for mode switching.
(struct machine_function): Add new field mode switching.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
test cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 100 ++++++++++++++++--
gcc/config/riscv/vector.md                    |   4 +-
.../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++++
.../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++++
.../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++++
.../rvv/base/float-point-dynamic-frm-36.c     |  29 +++++
.../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++++
.../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++++
.../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++++
.../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++++
.../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++++
.../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++++
.../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++++
.../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++++
.../rvv/base/float-point-dynamic-frm-70.c     |  28 +++++
.../rvv/base/float-point-dynamic-frm-71.c     |  28 +++++
.../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    |  83 +++++++++++++++
44 files changed, 1657 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..5ffd8945b6b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -90,6 +90,12 @@ along with GCC; see the file COPYING3.  If not see
/* True if bit BIT is set in VALUE.  */
#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
/* Information about a function's frame layout.  */
struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +131,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
};
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +170,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
};
/* Information about a single argument.  */
@@ -7709,9 +7729,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7745,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+ && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7781,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+
+ TODO: this cannot handle one case if there is no instruction
+ after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+ {
+   if (INSN_P (insn))
+     {
+       if (CALL_P (insn))
+ mode = FRM_MODE_DYN;
+       break;
+     }
+
+   if (insn == PREV_INSN (BB_HEAD (bb)))
+     break;
+ }
+    }
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7766,7 +7841,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7918,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
@@ -7883,10 +7963,10 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
- if (!cfun->machine->dynamic_frm)
+ if (!DYNAMIC_FRM_RTL(cfun))
  {
-     cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-     emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
+     DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+     emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
  }
  /* According to RVV 1.0 spec, all vector floating-point operations use
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-20  6:43 ` [PATCH v4] " pan2.li
  2023-07-20  6:47   ` juzhe.zhong
@ 2023-07-21  3:11   ` juzhe.zhong
  2023-07-21  6:44     ` Li, Pan2
  1 sibling, 1 reply; 49+ messages in thread
From: juzhe.zhong @ 2023-07-21  3:11 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: Kito.cheng, pan2.li, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 79507 bytes --]

-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));

No, I don't think for DYN_CALL, you need to emit restore_volatile.
It should be normal restore.


-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
No need to change it, recover it back to restore_exit.
The volatile restore should always be only used for exit.


Add one more test:

vfadd (static)

CALL

....
....                         ->   add a bunch integer RVV intrinsic (Ideally it should be only one backup frm insn after CALL).
...


vfadd (static)






juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-07-20 14:43
To: gcc-patches
CC: juzhe.zhong; kito.cheng; pan2.li; yanzhang.wang
Subject: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com>
 
In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.
 
During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.
 
1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.
 
We will perfrom some steps to make above happen.
 
1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.
 
Let's take a flow for this.
 
           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+
 
Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>
 
gcc/ChangeLog:
 
* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
(STATIC_FRM_P): Ditto.
(struct mode_switching_info): New struct for mode switching.
(struct machine_function): Add new field mode switching.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
test cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 100 ++++++++++++++++--
gcc/config/riscv/vector.md                    |   4 +-
.../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++++
.../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++++
.../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++++
.../rvv/base/float-point-dynamic-frm-36.c     |  29 +++++
.../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++++
.../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++++
.../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++++
.../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++++
.../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++++
.../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++++
.../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++++
.../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++++
.../rvv/base/float-point-dynamic-frm-70.c     |  28 +++++
.../rvv/base/float-point-dynamic-frm-71.c     |  28 +++++
.../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    |  83 +++++++++++++++
44 files changed, 1657 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..5ffd8945b6b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -90,6 +90,12 @@ along with GCC; see the file COPYING3.  If not see
/* True if bit BIT is set in VALUE.  */
#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
/* Information about a function's frame layout.  */
struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +131,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
};
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +170,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
};
/* Information about a single argument.  */
@@ -7709,9 +7729,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7745,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+ && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7781,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+
+ TODO: this cannot handle one case if there is no instruction
+ after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+ {
+   if (INSN_P (insn))
+     {
+       if (CALL_P (insn))
+ mode = FRM_MODE_DYN;
+       break;
+     }
+
+   if (insn == PREV_INSN (BB_HEAD (bb)))
+     break;
+ }
+    }
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7766,7 +7841,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7918,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
@@ -7883,10 +7963,10 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
- if (!cfun->machine->dynamic_frm)
+ if (!DYNAMIC_FRM_RTL(cfun))
  {
-     cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-     emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
+     DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+     emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
  }
  /* According to RVV 1.0 spec, all vector floating-point operations use
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-21  3:11   ` juzhe.zhong
@ 2023-07-21  6:44     ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-21  6:44 UTC (permalink / raw)
  To: juzhe.zhong, gcc-patches; +Cc: Kito.cheng, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 80523 bytes --]

Thanks Juzhe for reviewing.

The volatile should be present here as EXIT scenario. When we fsrm a5 (aka restore frm or define frm) before a call,
but the call will not use the frm value and then it will be eliminated later. Thus we need to mark this insn as volatile.

And will add the tests to PATCH v5.

Pan

From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Friday, July 21, 2023 11:11 AM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Kito.cheng <kito.cheng@sifive.com>; Li, Pan2 <pan2.li@intel.com>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding


-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)

+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)

        /* No need to emit when prev mode is DYN already.  */

-       emit_insn (gen_fsrmsi_restore_exit (backup_reg));

+       emit_insn (gen_fsrmsi_restore_volatile (backup_reg));

No, I don't think for DYN_CALL, you need to emit restore_volatile.
It should be normal restore.



-(define_insn "fsrmsi_restore_exit"

+(define_insn "fsrmsi_restore_volatile"
No need to change it, recover it back to restore_exit.
The volatile restore should always be only used for exit.


Add one more test:

vfadd (static)

CALL

....
....                         ->   add a bunch integer RVV intrinsic (Ideally it should be only one backup frm insn after CALL).
...


vfadd (static)




________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: pan2.li<mailto:pan2.li@intel.com>
Date: 2023-07-20 14:43
To: gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; kito.cheng<mailto:kito.cheng@sifive.com>; pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: [PATCH v4] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

Please *NOTE* some corn cases like no instruction after a call is not
well handled, and will be coverred in another PATCH(s) soon.

Signed-off-by: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>

gcc/ChangeLog:

* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
(STATIC_FRM_P): Ditto.
(struct mode_switching_info): New struct for mode switching.
(struct machine_function): Add new field mode switching.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
test cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 100 ++++++++++++++++--
gcc/config/riscv/vector.md                    |   4 +-
.../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++++
.../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++++
.../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++++
.../rvv/base/float-point-dynamic-frm-36.c     |  29 +++++
.../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++++
.../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++++
.../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++++
.../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++++
.../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++++
.../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++++
.../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++++
.../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++++
.../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++++
.../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++++
.../rvv/base/float-point-dynamic-frm-70.c     |  28 +++++
.../rvv/base/float-point-dynamic-frm-71.c     |  28 +++++
.../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    |  83 +++++++++++++++
44 files changed, 1657 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..5ffd8945b6b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -90,6 +90,12 @@ along with GCC; see the file COPYING3.  If not see
/* True if bit BIT is set in VALUE.  */
#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
/* Information about a function's frame layout.  */
struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +131,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
};
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +170,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
};
/* Information about a single argument.  */
@@ -7709,9 +7729,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7745,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+ && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7781,53 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (CALL_P (cur_insn))
+    return FRM_MODE_DYN_CALL;
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+    {
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+
+ TODO: this cannot handle one case if there is no instruction
+ after a call, we will take care of it soon.
+       */
+      rtx_insn *insn;
+      basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+      for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+ {
+   if (INSN_P (insn))
+     {
+       if (CALL_P (insn))
+ mode = FRM_MODE_DYN;
+       break;
+     }
+
+   if (insn == PREV_INSN (BB_HEAD (bb)))
+     break;
+ }
+    }
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7766,7 +7841,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7918,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
@@ -7883,10 +7963,10 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
- if (!cfun->machine->dynamic_frm)
+ if (!DYNAMIC_FRM_RTL(cfun))
  {
-     cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-     emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
+     DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+     emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
  }
  /* According to RVV 1.0 spec, all vector floating-point operations use
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
--
2.34.1



^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
  2023-07-19  3:31 ` juzhe.zhong
  2023-07-20  6:43 ` [PATCH v4] " pan2.li
@ 2023-07-23 13:11 ` pan2.li
  2023-07-24  0:53   ` juzhe.zhong
  2023-07-24  2:42 ` [PATCH v6] " pan2.li
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 49+ messages in thread
From: pan2.li @ 2023-07-23 13:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, pan2.li, yanzhang.wang

From: Pan Li <pan2.li@intel.com>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
	(STATIC_FRM_P): Ditto.
	(struct mode_switching_info): New struct for mode switching.
	(struct machine_function): Add new field mode switching.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_adjust_mode_after_call): New function for call mode.
	(riscv_frm_reconcile_call_as_bb_end): New function for call as
	the last insn of bb.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	(riscv_mode_entry): Remove backup rtl initialization.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
	test cases.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 150 ++++++++++++++++--
 gcc/config/riscv/vector.md                    |   4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++
 .../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++
 .../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++
 .../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
 .../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++
 .../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++
 .../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++
 .../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++
 .../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++
 .../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++
 .../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-72.c     |  33 ++++
 .../rvv/base/float-point-dynamic-frm-73.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-74.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-75.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-76.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
 .../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
 .../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    |  83 ++++++++++
 50 files changed, 1913 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..bd2cf8176a7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-expr.h"
 #include "tree-vectorizer.h"
+#include "gcse.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
 /* True if bit BIT is set in VALUE.  */
 #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
 
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
 
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
 };
 
 /* Information about a single argument.  */
@@ -7709,9 +7730,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7746,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+	&& prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7782,102 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  int mode = FRM_MODE_NONE;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+    {
+      if (INSN_P (insn))
+	{
+	  if (CALL_P (insn))
+	    mode = FRM_MODE_DYN;
+	  break;
+	}
+
+      if (insn == BB_HEAD (bb))
+	break;
+    }
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  gcc_assert (CALL_P (cur_insn));
+
+  if (cur_insn != BB_END (bb))
+    {
+      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
+	{
+	  if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
+	    return;
+
+	  if (insn == BB_END (bb))
+	    break;
+	}
+    }
+
+  /* Then we need to emit backup inst to the end of bb.  */
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      riscv_frm_reconcile_call_as_bb_end (cur_insn);
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn);
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7766,7 +7891,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7968,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
@@ -7883,12 +8013,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
-	if (!cfun->machine->dynamic_frm)
-	  {
-	    cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-	    emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-	  }
-
 	  /* According to RVV 1.0 spec, all vector floating-point operations use
 	     the dynamic rounding mode in the frm register.  Likewise in other
 	     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
 )
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
new file mode 100644
index 00000000000..6a07cfa6df9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  vl = normalize_vl_1 (vl);
+
+  vint32m1_t tmp_1 = __riscv_vreinterpret_v_f32m1_i32m1 (op1);
+  vint32m1_t tmp_2 = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+  tmp_2 = __riscv_vadd_vv_i32m1 (tmp_2, tmp_1, vl);
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
new file mode 100644
index 00000000000..91b015c51e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
new file mode 100644
index 00000000000..ad599b8ef67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
new file mode 100644
index 00000000000..76752e4af28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
new file mode 100644
index 00000000000..dd8e870c787
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
new file mode 100644
index 00000000000..c3d12cfe04e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zbb --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+double sum(double *d)
+{
+  double sum = 0.0;
+
+  for (int i = 0; i < 8; ++i)
+    sum += d[i];
+
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
 }
 
 /* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
 /* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+		"The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-23 13:11 ` [PATCH v5] " pan2.li
@ 2023-07-24  0:53   ` juzhe.zhong
  2023-07-24  1:51     ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: juzhe.zhong @ 2023-07-24  0:53 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: Kito.cheng, pan2.li, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 90092 bytes --]

Overall LGTM from my side. 
But we should  wait for Kito's review.



juzhe.zhong@rivai.ai
 
From: pan2.li
Date: 2023-07-23 21:11
To: gcc-patches
CC: juzhe.zhong; kito.cheng; pan2.li; yanzhang.wang
Subject: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com>
 
In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.
 
During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.
 
1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.
 
We will perfrom some steps to make above happen.
 
1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.
 
Let's take a flow for this.
 
           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+
 
When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.
 
Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>
 
gcc/ChangeLog:
 
* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
(STATIC_FRM_P): Ditto.
(struct mode_switching_info): New struct for mode switching.
(struct machine_function): Add new field mode switching.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_adjust_mode_after_call): New function for call mode.
(riscv_frm_reconcile_call_as_bb_end): New function for call as
the last insn of bb.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
(riscv_mode_entry): Remove backup rtl initialization.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
test cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 150 ++++++++++++++++--
gcc/config/riscv/vector.md                    |   4 +-
.../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++
.../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++
.../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++
.../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
.../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++
.../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++
.../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
.../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
.../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++
.../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++
.../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++
.../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++
.../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
.../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
.../rvv/base/float-point-dynamic-frm-72.c     |  33 ++++
.../rvv/base/float-point-dynamic-frm-73.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-74.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-75.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-76.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
.../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    |  83 ++++++++++
50 files changed, 1913 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
 
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..bd2cf8176a7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
#include "gimple-iterator.h"
#include "gimple-expr.h"
#include "tree-vectorizer.h"
+#include "gcse.h"
/* This file should be included last.  */
#include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
/* True if bit BIT is set in VALUE.  */
#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
/* Information about a function's frame layout.  */
struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
};
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
};
/* Information about a single argument.  */
@@ -7709,9 +7730,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7746,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+ && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7782,102 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  int mode = FRM_MODE_NONE;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+    {
+      if (INSN_P (insn))
+ {
+   if (CALL_P (insn))
+     mode = FRM_MODE_DYN;
+   break;
+ }
+
+      if (insn == BB_HEAD (bb))
+ break;
+    }
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  gcc_assert (CALL_P (cur_insn));
+
+  if (cur_insn != BB_END (bb))
+    {
+      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
+ {
+   if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
+     return;
+
+   if (insn == BB_END (bb))
+     break;
+ }
+    }
+
+  /* Then we need to emit backup inst to the end of bb.  */
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      riscv_frm_reconcile_call_as_bb_end (cur_insn);
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn);
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7766,7 +7891,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7968,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
@@ -7883,12 +8013,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
- if (!cfun->machine->dynamic_frm)
-   {
-     cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-     emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-   }
-
  /* According to RVV 1.0 spec, all vector floating-point operations use
     the dynamic rounding mode in the frm register.  Likewise in other
     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
new file mode 100644
index 00000000000..6a07cfa6df9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  vl = normalize_vl_1 (vl);
+
+  vint32m1_t tmp_1 = __riscv_vreinterpret_v_f32m1_i32m1 (op1);
+  vint32m1_t tmp_2 = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+  tmp_2 = __riscv_vadd_vv_i32m1 (tmp_2, tmp_1, vl);
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
new file mode 100644
index 00000000000..91b015c51e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
new file mode 100644
index 00000000000..ad599b8ef67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
new file mode 100644
index 00000000000..76752e4af28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
new file mode 100644
index 00000000000..dd8e870c787
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
new file mode 100644
index 00000000000..c3d12cfe04e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zbb --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+double sum(double *d)
+{
+  double sum = 0.0;
+
+  for (int i = 0; i < 8; ++i)
+    sum += d[i];
+
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1
 
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-24  0:53   ` juzhe.zhong
@ 2023-07-24  1:51     ` Li, Pan2
  2023-07-24  2:45       ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-24  1:51 UTC (permalink / raw)
  To: juzhe.zhong, gcc-patches; +Cc: Kito.cheng, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 90878 bytes --]

Thanks Juzhe for reviewing, looks some conflicts with upstream, and will send the PATCH v6 after passed all the tests.

Pan

From: juzhe.zhong@rivai.ai <juzhe.zhong@rivai.ai>
Sent: Monday, July 24, 2023 8:54 AM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Kito.cheng <kito.cheng@sifive.com>; Li, Pan2 <pan2.li@intel.com>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding

Overall LGTM from my side.
But we should  wait for Kito's review.

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: pan2.li<mailto:pan2.li@intel.com>
Date: 2023-07-23 21:11
To: gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; kito.cheng<mailto:kito.cheng@sifive.com>; pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>

gcc/ChangeLog:

* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
(STATIC_FRM_P): Ditto.
(struct mode_switching_info): New struct for mode switching.
(struct machine_function): Add new field mode switching.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_adjust_mode_after_call): New function for call mode.
(riscv_frm_reconcile_call_as_bb_end): New function for call as
the last insn of bb.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
(riscv_mode_entry): Remove backup rtl initialization.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
test cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 150 ++++++++++++++++--
gcc/config/riscv/vector.md                    |   4 +-
.../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++
.../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++
.../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++
.../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
.../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++
.../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++
.../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
.../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
.../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++
.../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++
.../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++
.../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++
.../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
.../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
.../rvv/base/float-point-dynamic-frm-72.c     |  33 ++++
.../rvv/base/float-point-dynamic-frm-73.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-74.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-75.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-76.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
.../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    |  83 ++++++++++
50 files changed, 1913 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..bd2cf8176a7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
#include "gimple-iterator.h"
#include "gimple-expr.h"
#include "tree-vectorizer.h"
+#include "gcse.h"
/* This file should be included last.  */
#include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
/* True if bit BIT is set in VALUE.  */
#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
/* Information about a function's frame layout.  */
struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
};
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
};
/* Information about a single argument.  */
@@ -7709,9 +7730,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7746,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+ && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7782,102 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  int mode = FRM_MODE_NONE;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+    {
+      if (INSN_P (insn))
+ {
+   if (CALL_P (insn))
+     mode = FRM_MODE_DYN;
+   break;
+ }
+
+      if (insn == BB_HEAD (bb))
+ break;
+    }
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  gcc_assert (CALL_P (cur_insn));
+
+  if (cur_insn != BB_END (bb))
+    {
+      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
+ {
+   if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
+     return;
+
+   if (insn == BB_END (bb))
+     break;
+ }
+    }
+
+  /* Then we need to emit backup inst to the end of bb.  */
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      riscv_frm_reconcile_call_as_bb_end (cur_insn);
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn);
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7766,7 +7891,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7968,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
@@ -7883,12 +8013,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
- if (!cfun->machine->dynamic_frm)
-   {
-     cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-     emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-   }
-
  /* According to RVV 1.0 spec, all vector floating-point operations use
     the dynamic rounding mode in the frm register.  Likewise in other
     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+   vl = normalize_vl (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+   vl = normalize_vl (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+   vl = normalize_vl_1 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+ }
+      else
+ {
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+   vl = normalize_vl_2 (vl);
+   result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+ }
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
new file mode 100644
index 00000000000..6a07cfa6df9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+      unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  vl = normalize_vl_1 (vl);
+
+  vint32m1_t tmp_1 = __riscv_vreinterpret_v_f32m1_i32m1 (op1);
+  vint32m1_t tmp_2 = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+  tmp_2 = __riscv_vadd_vv_i32m1 (tmp_2, tmp_1, vl);
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
new file mode 100644
index 00000000000..91b015c51e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
new file mode 100644
index 00000000000..ad599b8ef67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
new file mode 100644
index 00000000000..76752e4af28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
new file mode 100644
index 00000000000..dd8e870c787
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+       size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
new file mode 100644
index 00000000000..c3d12cfe04e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zbb --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+double sum(double *d)
+{
+  double sum = 0.0;
+
+  for (int i = 0; i < 8; ++i)
+    sum += d[i];
+
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
}
/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+ "The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+ "The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
--
2.34.1



^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
                   ` (2 preceding siblings ...)
  2023-07-23 13:11 ` [PATCH v5] " pan2.li
@ 2023-07-24  2:42 ` pan2.li
  2023-07-24 10:28   ` Robin Dapp
  2023-07-25  5:51 ` [PATCH v7] " pan2.li
  2023-07-28  1:15 ` [PATCH v8] " pan2.li
  5 siblings, 1 reply; 49+ messages in thread
From: pan2.li @ 2023-07-24  2:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, pan2.li, yanzhang.wang

From: Pan Li <pan2.li@intel.com>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
	(STATIC_FRM_P): Ditto.
	(struct mode_switching_info): New struct for mode switching.
	(struct machine_function): Add new field mode switching.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_adjust_mode_after_call): New function for call mode.
	(riscv_frm_reconcile_call_as_bb_end): New function for call as
	the last insn of bb.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	(riscv_mode_entry): Remove backup rtl initialization.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
	test cases.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 150 ++++++++++++++++--
 gcc/config/riscv/vector.md                    |   4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++
 .../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++
 .../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++
 .../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
 .../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++
 .../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++
 .../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++
 .../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++
 .../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++
 .../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++
 .../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-72.c     |  33 ++++
 .../rvv/base/float-point-dynamic-frm-73.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-74.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-75.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-76.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
 .../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
 .../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    |  83 ++++++++++
 50 files changed, 1913 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..bd2cf8176a7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-expr.h"
 #include "tree-vectorizer.h"
+#include "gcse.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
 /* True if bit BIT is set in VALUE.  */
 #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
 
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
 
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
 };
 
 /* Information about a single argument.  */
@@ -7709,9 +7730,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7746,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+	&& prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7782,102 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  int mode = FRM_MODE_NONE;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+    {
+      if (INSN_P (insn))
+	{
+	  if (CALL_P (insn))
+	    mode = FRM_MODE_DYN;
+	  break;
+	}
+
+      if (insn == BB_HEAD (bb))
+	break;
+    }
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  gcc_assert (CALL_P (cur_insn));
+
+  if (cur_insn != BB_END (bb))
+    {
+      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
+	{
+	  if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
+	    return;
+
+	  if (insn == BB_END (bb))
+	    break;
+	}
+    }
+
+  /* Then we need to emit backup inst to the end of bb.  */
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      riscv_frm_reconcile_call_as_bb_end (cur_insn);
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn);
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7766,7 +7891,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7968,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
@@ -7883,12 +8013,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
-	if (!cfun->machine->dynamic_frm)
-	  {
-	    cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-	    emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-	  }
-
 	  /* According to RVV 1.0 spec, all vector floating-point operations use
 	     the dynamic rounding mode in the frm register.  Likewise in other
 	     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index f745888127c..05fd7600ba4 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -686,7 +686,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
         (const_string "none")))
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond [(eq_attr "type" "vfalu")
          (cond
 	   [(match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
@@ -813,7 +813,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..d2a17ad715f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..50e1da2c3c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..a66ca89308b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..d9c1ef29450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..2c3481b980e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4aeae2ee0cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..350bd4924eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8737ab930aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..a73d414866b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..510210b4f5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..52c99039564
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..a70fc19b5c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..803ec80b5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..846aece4307
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 5 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..06c7fcf1b89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..0ae9c67ce86
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..1dd5a63b381
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..f73383fc279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ed6f22c41d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..3e43aecd913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..344701f3cb5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
new file mode 100644
index 00000000000..6a07cfa6df9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  vl = normalize_vl_1 (vl);
+
+  vint32m1_t tmp_1 = __riscv_vreinterpret_v_f32m1_i32m1 (op1);
+  vint32m1_t tmp_2 = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+  tmp_2 = __riscv_vadd_vv_i32m1 (tmp_2, tmp_1, vl);
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
new file mode 100644
index 00000000000..91b015c51e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
new file mode 100644
index 00000000000..ad599b8ef67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
new file mode 100644
index 00000000000..76752e4af28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
new file mode 100644
index 00000000000..dd8e870c787
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
new file mode 100644
index 00000000000..c3d12cfe04e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zbb --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+double sum(double *d)
+{
+  double sum = 0.0;
+
+  for (int i = 0; i < 8; ++i)
+    sum += d[i];
+
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
 }
 
 /* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
 /* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+		"The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-24  1:51     ` Li, Pan2
@ 2023-07-24  2:45       ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-24  2:45 UTC (permalink / raw)
  To: juzhe.zhong, gcc-patches; +Cc: Kito.cheng, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 23515 bytes --]

Passed the riscv.exp/rvv.exp in both rv32 and rv64 in PATCH v6 as below.

https://gcc.gnu.org/pipermail/gcc-patches/2023-July/625315.html

Pan

From: Li, Pan2
Sent: Monday, July 24, 2023 9:52 AM
To: 'juzhe.zhong@rivai.ai' <juzhe.zhong@rivai.ai>; gcc-patches <gcc-patches@gcc.gnu.org>
Cc: Kito.cheng <kito.cheng@sifive.com>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: RE: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding

Thanks Juzhe for reviewing, looks some conflicts with upstream, and will send the PATCH v6 after passed all the tests.

Pan

From: juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai> <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Monday, July 24, 2023 8:54 AM
To: Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>; gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>
Cc: Kito.cheng <kito.cheng@sifive.com<mailto:kito.cheng@sifive.com>>; Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding

Overall LGTM from my side.
But we should  wait for Kito's review.

________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: pan2.li<mailto:pan2.li@intel.com>
Date: 2023-07-23 21:11
To: gcc-patches<mailto:gcc-patches@gcc.gnu.org>
CC: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; kito.cheng<mailto:kito.cheng@sifive.com>; pan2.li<mailto:pan2.li@intel.com>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: [PATCH v5] RISC-V: Support CALL for RVV floating-point dynamic rounding
From: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>

gcc/ChangeLog:

* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
(STATIC_FRM_P): Ditto.
(struct mode_switching_info): New struct for mode switching.
(struct machine_function): Add new field mode switching.
(riscv_emit_frm_mode_set): Add DYN_CALL emit.
(riscv_frm_adjust_mode_after_call): New function for call mode.
(riscv_frm_reconcile_call_as_bb_end): New function for call as
the last insn of bb.
(riscv_frm_mode_needed): New function for frm mode needed.
(riscv_mode_needed): Extrac function for frm.
(riscv_frm_mode_after): Add DYN_CALL after.
(riscv_mode_entry): Remove backup rtl initialization.
* config/riscv/vector.md (frm_mode): Add dyn_call.
(fsrmsi_restore_exit): Rename to _volatile.
(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
test cases.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
gcc/config/riscv/riscv.cc                     | 150 ++++++++++++++++--
gcc/config/riscv/vector.md                    |   4 +-
.../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++
.../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++
.../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++
.../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
.../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-38.c     |  34 ++++
.../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-40.c     |  34 ++++
.../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
.../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
.../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++
.../rvv/base/float-point-dynamic-frm-45.c     |  35 ++++
.../rvv/base/float-point-dynamic-frm-46.c     |  35 ++++
.../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
.../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
.../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++
.../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
.../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
.../rvv/base/float-point-dynamic-frm-72.c     |  33 ++++
.../rvv/base/float-point-dynamic-frm-73.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-74.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-75.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-76.c     |  39 +++++
.../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
.../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
.../riscv/rvv/base/float-point-frm-run-4.c    |  82 ++++++++++
.../riscv/rvv/base/float-point-frm-run-5.c    |  83 ++++++++++
50 files changed, 1913 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..bd2cf8176a7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
#include "gimple-iterator.h"
#include "gimple-expr.h"
#include "tree-vectorizer.h"
+#include "gcse.h"
/* This file should be included last.  */
#include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
/* True if bit BIT is set in VALUE.  */
#define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
/* Information about a function's frame layout.  */
struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
};
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,7 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  struct mode_switching_info mode_sw_info;
};
/* Information about a single argument.  */
@@ -7709,9 +7730,13 @@ riscv_static_frm_mode_p (int mode)
static void
riscv_emit_frm_mode_set (int mode, int prev_mode)
{
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
different from the FRM value like FRM_RTZ defined in
riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,9 +7746,13 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
/* No need to emit when prev mode is DYN already.  */
- emit_insn (gen_fsrmsi_restore_exit (backup_reg));
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+ && prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+ /* No need to emit when prev mode is DYN or DYN_CALL already.  */
+ emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
       else if (mode == FRM_MODE_DYN)
/* Restore frm value from backup when switch to DYN mode.  */
emit_insn (gen_fsrmsi_restore (backup_reg));
@@ -7753,6 +7782,102 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
}
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  int mode = FRM_MODE_NONE;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
+    {
+      if (INSN_P (insn))
+ {
+   if (CALL_P (insn))
+     mode = FRM_MODE_DYN;
+   break;
+ }
+
+      if (insn == BB_HEAD (bb))
+ break;
+    }
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
+{
+  rtx_insn *insn;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  gcc_assert (CALL_P (cur_insn));
+
+  if (cur_insn != BB_END (bb))
+    {
+      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
+ {
+   if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
+     return;
+
+   if (insn == BB_END (bb))
+     break;
+ }
+    }
+
+  /* Then we need to emit backup inst to the end of bb.  */
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      riscv_frm_reconcile_call_as_bb_end (cur_insn);
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+ updated during the call. Here, for each insn, we will check if
+ the previous insn is a call or not. When previous insn is call,
+ there will be 2 cases for the emit mode set.
+
+ 1. Current insn is not MODE_NONE, then the mode switch framework
+     will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+ 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+     the MODE_DYN, and leave the mode switch itself to perform
+     the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn);
+
+  return mode;
+}
+
/* Return mode that entity must be switched into
    prior to the execution of insn.  */
@@ -7766,7 +7891,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7968,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
@@ -7883,12 +8013,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
- if (!cfun->machine->dynamic_frm)
-   {
-     cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-     emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-   }
-
  /* According to RVV 1.0 spec, all vector floating-point operations use
     the dynamic rounding mode in the frm register.  Likewise in other
     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 69680de2600..63b2d3a9b82 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -694,7 +694,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
)
;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond
     [
       (eq_attr "type" "vfalu")
@@ -829,7 +829,7 @@ (define_insn "fsrmsi_restore"
;; The volatile fsrmsi restore is used for the exit point for the
;; dynamic mode switching. It will generate one volatile fsrm a5
;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
    UNSPECV_FRM_RESTORE_EXIT))]
--
2.34.1



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-24  2:42 ` [PATCH v6] " pan2.li
@ 2023-07-24 10:28   ` Robin Dapp
  2023-07-24 11:59     ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Robin Dapp @ 2023-07-24 10:28 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: rdapp.gcc, juzhe.zhong, kito.cheng, yanzhang.wang

Hi Pan,

> +  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
> +    {
> +      if (INSN_P (insn))
> +	{
> +	  if (CALL_P (insn))
> +	    mode = FRM_MODE_DYN;
> +	  break;
> +	}
> +
> +      if (insn == BB_HEAD (bb))
> +	break;
> +    }
> +
> +  return mode;
> +}

Does prev_nonnote_nondebug_insn_bb help here?  In general, we scan
back here to the last insn and "recover" if it was a call?  Why
can't we set the proper value already before exiting the function?

I guess the more general question is more towards call-clobbered or
not?  In this patch we assume the rounding mode is call clobbered
and restore it ourselves.  Has there been any kind of consensus
on this?  Intuitively I would have expected a function that requires
a non-standard rounding mode to set and restore it itself. 

> +
> +/* Insert the backup frm insn to the end of the bb if and only if the call
> +   is the last insn of this bb.  */
> +
> +static void
> +riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
> +{
> +  rtx_insn *insn;
> +  basic_block bb = BLOCK_FOR_INSN (cur_insn);
> +
> +  gcc_assert (CALL_P (cur_insn));
> +
> +  if (cur_insn != BB_END (bb))
> +    {
> +      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
> +	{
> +	  if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
> +	    return;

What about nondebug insns?  Also maybe next_nonnote_nondebug_insn_bb
helps?  How about splitting the function in detection and emit?
I.e. bb_ends_in_call (or so) and the emit part.  That way it
could be more obvious in "needed" what needs to be done.

Are we handling sibcalls and tail calls properly here?

In general I'm still a bit wary that we are checking mode != prev_mode
but cannot really pinpoint why.  I would have hoped that the generic
code only calls us when this check is unnecessary and if not the
"needed" hook should be adjusted.

I also find it a bit odd to emit instructions when checking
if another mode is needed.  If what's required cannot be accomplished
with the current common code, shouldn't we rather try to amend that?

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-24 10:28   ` Robin Dapp
@ 2023-07-24 11:59     ` Li, Pan2
  2023-07-24 12:03       ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-24 11:59 UTC (permalink / raw)
  To: Robin Dapp, gcc-patches; +Cc: juzhe.zhong, kito.cheng, Wang, Yanzhang

Thanks Robin for comments.

>> Does prev_nonnote_nondebug_insn_bb help here?  In general, we scan
>> back here to the last insn and "recover" if it was a call?  Why
>> can't we set the proper value already before exiting the function?

Good to learn prev_nonnote_nondebug_insn_bb, will have a try here.
First we mark the call as DYN_CALL. We expect the insn next to the call to emit the backup insn.
However, if next instruction is DYN_ONE, the mode switching it self will never call emit. Thus, for each
Insn is DYN_NONE, we will reset it to DYN if the last insn is call and let the mode switching to emit properly.

When meet a call, we assume the rounding mode will be clobbered.

>> What about nondebug insns?  Also maybe next_nonnote_nondebug_insn_bb
>> helps?  How about splitting the function in detection and emit?
>> I.e. bb_ends_in_call (or so) and the emit part.  That way it
>> could be more obvious in "needed" what needs to be done.

The point here is that the call may be the last insn of current bb. Then we have chance to emit backup insn AFTER
the call, because the emit by default emit the insn before current insn.

Thus we try to make up this during the needed process, I know this may not be a good idea but it is the only way
I can locate shortly. I may try to find another way if we can control the insn emit location for each insn.

Pan

-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Monday, July 24, 2023 6:29 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding

Hi Pan,

> +  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
> +    {
> +      if (INSN_P (insn))
> +	{
> +	  if (CALL_P (insn))
> +	    mode = FRM_MODE_DYN;
> +	  break;
> +	}
> +
> +      if (insn == BB_HEAD (bb))
> +	break;
> +    }
> +
> +  return mode;
> +}

Does prev_nonnote_nondebug_insn_bb help here?  In general, we scan
back here to the last insn and "recover" if it was a call?  Why
can't we set the proper value already before exiting the function?

I guess the more general question is more towards call-clobbered or
not?  In this patch we assume the rounding mode is call clobbered
and restore it ourselves.  Has there been any kind of consensus
on this?  Intuitively I would have expected a function that requires
a non-standard rounding mode to set and restore it itself. 

> +
> +/* Insert the backup frm insn to the end of the bb if and only if the call
> +   is the last insn of this bb.  */
> +
> +static void
> +riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
> +{
> +  rtx_insn *insn;
> +  basic_block bb = BLOCK_FOR_INSN (cur_insn);
> +
> +  gcc_assert (CALL_P (cur_insn));
> +
> +  if (cur_insn != BB_END (bb))
> +    {
> +      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
> +	{
> +	  if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
> +	    return;

What about nondebug insns?  Also maybe next_nonnote_nondebug_insn_bb
helps?  How about splitting the function in detection and emit?
I.e. bb_ends_in_call (or so) and the emit part.  That way it
could be more obvious in "needed" what needs to be done.

Are we handling sibcalls and tail calls properly here?

In general I'm still a bit wary that we are checking mode != prev_mode
but cannot really pinpoint why.  I would have hoped that the generic
code only calls us when this check is unnecessary and if not the
"needed" hook should be adjusted.

I also find it a bit odd to emit instructions when checking
if another mode is needed.  If what's required cannot be accomplished
with the current common code, shouldn't we rather try to amend that?

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-24 11:59     ` Li, Pan2
@ 2023-07-24 12:03       ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-24 12:03 UTC (permalink / raw)
  To: Robin Dapp, gcc-patches; +Cc: juzhe.zhong, kito.cheng, Wang, Yanzhang

Fix some typo inline,  sorry for inconvenience.

-----Original Message-----
From: Li, Pan2 
Sent: Monday, July 24, 2023 7:59 PM
To: Robin Dapp <rdapp.gcc@gmail.com>; gcc-patches@gcc.gnu.org
Cc: juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: RE: [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding

Thanks Robin for comments.

>> Does prev_nonnote_nondebug_insn_bb help here?  In general, we scan
>> back here to the last insn and "recover" if it was a call?  Why
>> can't we set the proper value already before exiting the function?

Good to learn prev_nonnote_nondebug_insn_bb, will have a try here.
First we mark the call as DYN_CALL. We expect the insn next to the call to emit the backup insn.
However, if next instruction is DYN_NONE, the mode switching it self will never call emit. Thus, for each
Insn is DYN_NONE, we will reset it to DYN if the last insn is call and let the mode switching to emit properly.

When meet a call, we assume the rounding mode will be clobbered.

>> What about nondebug insns?  Also maybe next_nonnote_nondebug_insn_bb
>> helps?  How about splitting the function in detection and emit?
>> I.e. bb_ends_in_call (or so) and the emit part.  That way it
>> could be more obvious in "needed" what needs to be done.

The point here is that the call may be the last insn of current bb. Then we have chance to emit backup insn AFTER
the call, because the emit by default emit the insn before current insn.

Thus we try to make up this during the needed process, I know this may not be a good idea but it is the only way
I can locate shortly. I may try to find another way if we can control the insn emit location for each insn.

Pan

-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Monday, July 24, 2023 6:29 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v6] RISC-V: Support CALL for RVV floating-point dynamic rounding

Hi Pan,

> +  for (insn = PREV_INSN (cur_insn); insn; insn = PREV_INSN (insn))
> +    {
> +      if (INSN_P (insn))
> +	{
> +	  if (CALL_P (insn))
> +	    mode = FRM_MODE_DYN;
> +	  break;
> +	}
> +
> +      if (insn == BB_HEAD (bb))
> +	break;
> +    }
> +
> +  return mode;
> +}

Does prev_nonnote_nondebug_insn_bb help here?  In general, we scan
back here to the last insn and "recover" if it was a call?  Why
can't we set the proper value already before exiting the function?

I guess the more general question is more towards call-clobbered or
not?  In this patch we assume the rounding mode is call clobbered
and restore it ourselves.  Has there been any kind of consensus
on this?  Intuitively I would have expected a function that requires
a non-standard rounding mode to set and restore it itself. 

> +
> +/* Insert the backup frm insn to the end of the bb if and only if the call
> +   is the last insn of this bb.  */
> +
> +static void
> +riscv_frm_reconcile_call_as_bb_end (rtx_insn *cur_insn)
> +{
> +  rtx_insn *insn;
> +  basic_block bb = BLOCK_FOR_INSN (cur_insn);
> +
> +  gcc_assert (CALL_P (cur_insn));
> +
> +  if (cur_insn != BB_END (bb))
> +    {
> +      for (insn = NEXT_INSN (cur_insn); insn; insn = NEXT_INSN (insn))
> +	{
> +	  if (INSN_P (insn)) /* If there is one insn after call, do nothing.  */
> +	    return;

What about nondebug insns?  Also maybe next_nonnote_nondebug_insn_bb
helps?  How about splitting the function in detection and emit?
I.e. bb_ends_in_call (or so) and the emit part.  That way it
could be more obvious in "needed" what needs to be done.

Are we handling sibcalls and tail calls properly here?

In general I'm still a bit wary that we are checking mode != prev_mode
but cannot really pinpoint why.  I would have hoped that the generic
code only calls us when this check is unnecessary and if not the
"needed" hook should be adjusted.

I also find it a bit odd to emit instructions when checking
if another mode is needed.  If what's required cannot be accomplished
with the current common code, shouldn't we rather try to amend that?

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
                   ` (3 preceding siblings ...)
  2023-07-24  2:42 ` [PATCH v6] " pan2.li
@ 2023-07-25  5:51 ` pan2.li
  2023-07-25  6:07   ` Li, Pan2
  2023-07-28  1:15 ` [PATCH v8] " pan2.li
  5 siblings, 1 reply; 49+ messages in thread
From: pan2.li @ 2023-07-25  5:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, pan2.li, yanzhang.wang, rdapp.gcc

From: Pan Li <pan2.li@intel.com>

Update in PATCH v7:

1. Take previous/next_nonnote_nondebug_insn_bb for seeking the insn.
2. Splitting the function in detection and emit when needed.

Original commit logs:

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
	(STATIC_FRM_P): Ditto.
	(struct mode_switching_info): New struct for mode switching.
	(struct machine_function): Add new field mode switching.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_adjust_mode_after_call): New function for call mode.
	(riscv_frm_emit_after_call_in_bb_end): New function for emit
	insn when call as the end of bb.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	(riscv_mode_entry): Remove backup rtl initialization.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
	test cases.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 130 ++++++++++++++++--
 gcc/config/riscv/vector.md                    |   4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     |  31 +++++
 .../rvv/base/float-point-dynamic-frm-34.c     |  32 +++++
 .../rvv/base/float-point-dynamic-frm-35.c     |  32 +++++
 .../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
 .../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-38.c     |  34 +++++
 .../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-40.c     |  34 +++++
 .../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-44.c     |  40 ++++++
 .../rvv/base/float-point-dynamic-frm-45.c     |  35 +++++
 .../rvv/base/float-point-dynamic-frm-46.c     |  35 +++++
 .../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-69.c     |  31 +++++
 .../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-72.c     |  33 +++++
 .../rvv/base/float-point-dynamic-frm-73.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-74.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-75.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-76.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
 .../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
 .../riscv/rvv/base/float-point-frm-run-4.c    |  82 +++++++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    |  83 +++++++++++
 50 files changed, 1892 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..7d2d4252e5c 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-expr.h"
 #include "tree-vectorizer.h"
+#include "gcse.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
 /* True if bit BIT is set in VALUE.  */
 #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
 
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,8 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
 
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  /* The mode swithching information for the FRM rounding modes.  */
+  struct mode_switching_info mode_sw_info;
 };
 
 /* Information about a single argument.  */
@@ -7709,9 +7731,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,10 +7747,14 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
-      else if (mode == FRM_MODE_DYN)
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+	&& prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
       else if (riscv_static_frm_mode_p (mode))
@@ -7753,6 +7783,79 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn, int mode)
+{
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+  rtx_insn *insn = prev_nonnote_nondebug_insn_bb (cur_insn);
+
+  if (insn && CALL_P (insn))
+    return FRM_MODE_DYN;
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_emit_after_call_in_bb_end (rtx_insn *cur_insn)
+{
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      rtx_insn *insn = next_nonnote_nondebug_insn_bb (cur_insn);
+
+      if (!insn)
+	riscv_frm_emit_after_call_in_bb_end (cur_insn);
+
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn, mode);
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7766,7 +7869,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7946,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
@@ -7883,12 +7991,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
-	if (!cfun->machine->dynamic_frm)
-	  {
-	    cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-	    emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-	  }
-
 	  /* According to RVV 1.0 spec, all vector floating-point operations use
 	     the dynamic rounding mode in the frm register.  Likewise in other
 	     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index f745888127c..05fd7600ba4 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -686,7 +686,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
         (const_string "none")))
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond [(eq_attr "type" "vfalu")
          (cond
 	   [(match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
@@ -813,7 +813,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..1123a93997e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..2ea60ca47c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..7486ed465c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..3ceea105f6a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..994c86e93eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4cde923abc1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..0b0a017cfd5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8b564ca5f43
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..b63f717b239
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..647de39d66e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..8c67d4bba81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..61365103b40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..e5a1c356a98
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..7ac9c960e65
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..87d436ac146
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..8748ca66b1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..8fd97b50124
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..58718c39279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ad2d54510bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..c15629d2134
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..b8500303a21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
new file mode 100644
index 00000000000..6a07cfa6df9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  vl = normalize_vl_1 (vl);
+
+  vint32m1_t tmp_1 = __riscv_vreinterpret_v_f32m1_i32m1 (op1);
+  vint32m1_t tmp_2 = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+  tmp_2 = __riscv_vadd_vv_i32m1 (tmp_2, tmp_1, vl);
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
new file mode 100644
index 00000000000..91b015c51e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
new file mode 100644
index 00000000000..b52400e5123
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
new file mode 100644
index 00000000000..4d3fd859637
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
new file mode 100644
index 00000000000..7ff106a8847
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
new file mode 100644
index 00000000000..c3d12cfe04e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zbb --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+double sum(double *d)
+{
+  double sum = 0.0;
+
+  for (int i = 0; i < 8; ++i)
+    sum += d[i];
+
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
 }
 
 /* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
 /* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..5796aa53a73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,82 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (),
+		"The value of frm register should be ORIGINAL_FRM.");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..208a65fcd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,83 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+static inline void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (),
+		"The value of frm register should be NEW_FRM.");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-25  5:51 ` [PATCH v7] " pan2.li
@ 2023-07-25  6:07   ` Li, Pan2
  2023-07-25  8:38     ` Robin Dapp
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-25  6:07 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, Wang, Yanzhang, rdapp.gcc

Hi Robin,

Given we have a call, we would like to restore before call and then backup frm after call. 
Looks current mode switching cannot emit insn like that, it can only either emit insn before (mostly) or after (when NOTE_INSN_BASIC_BLOCK_P).
Thus, we try to emit the one after call when needed as a specially handling here.

To take care of it elegantly, I may suggest we can have one optional mode switch HOOK like TARGET_MODE_EMIT_AFTER, which will emit
the backup/restore after insn besides TARGET_MODE_EMIT. I may prefer to have a try later in another PATCH(es) in the middle-end.

Pan

-----Original Message-----
From: Li, Pan2 <pan2.li@intel.com> 
Sent: Tuesday, July 25, 2023 1:52 PM
To: gcc-patches@gcc.gnu.org
Cc: juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Li, Pan2 <pan2.li@intel.com>; Wang, Yanzhang <yanzhang.wang@intel.com>; rdapp.gcc@gmail.com
Subject: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

From: Pan Li <pan2.li@intel.com>

Update in PATCH v7:

1. Take previous/next_nonnote_nondebug_insn_bb for seeking the insn.
2. Splitting the function in detection and emit when needed.

Original commit logs:

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
	(STATIC_FRM_P): Ditto.
	(struct mode_switching_info): New struct for mode switching.
	(struct machine_function): Add new field mode switching.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_adjust_mode_after_call): New function for call mode.
	(riscv_frm_emit_after_call_in_bb_end): New function for emit
	insn when call as the end of bb.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	(riscv_mode_entry): Remove backup rtl initialization.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
	test cases.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
---
 gcc/config/riscv/riscv.cc                     | 130 ++++++++++++++++--
 gcc/config/riscv/vector.md                    |   4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     |  31 +++++
 .../rvv/base/float-point-dynamic-frm-34.c     |  32 +++++
 .../rvv/base/float-point-dynamic-frm-35.c     |  32 +++++
 .../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
 .../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-38.c     |  34 +++++
 .../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-40.c     |  34 +++++
 .../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-44.c     |  40 ++++++
 .../rvv/base/float-point-dynamic-frm-45.c     |  35 +++++
 .../rvv/base/float-point-dynamic-frm-46.c     |  35 +++++
 .../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-69.c     |  31 +++++
 .../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-72.c     |  33 +++++
 .../rvv/base/float-point-dynamic-frm-73.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-74.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-75.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-76.c     |  39 ++++++
 .../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
 .../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
 .../riscv/rvv/base/float-point-frm-run-4.c    |  82 +++++++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    |  83 +++++++++++
 50 files changed, 1892 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..7d2d4252e5c 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-expr.h"
 #include "tree-vectorizer.h"
+#include "gcse.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
 /* True if bit BIT is set in VALUE.  */
 #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
 
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,8 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
 
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  /* The mode swithching information for the FRM rounding modes.  */
+  struct mode_switching_info mode_sw_info;
 };
 
 /* Information about a single argument.  */
@@ -7709,9 +7731,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,10 +7747,14 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
-      else if (mode == FRM_MODE_DYN)
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+	&& prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
       else if (riscv_static_frm_mode_p (mode))
@@ -7753,6 +7783,79 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn, int mode)
+{
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+  rtx_insn *insn = prev_nonnote_nondebug_insn_bb (cur_insn);
+
+  if (insn && CALL_P (insn))
+    return FRM_MODE_DYN;
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_emit_after_call_in_bb_end (rtx_insn *cur_insn)
+{
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();
+
+  insert_insn_end_basic_block (backup_insn, bb);
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      rtx_insn *insn = next_nonnote_nondebug_insn_bb (cur_insn);
+
+      if (!insn)
+	riscv_frm_emit_after_call_in_bb_end (cur_insn);
+
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NON_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn, mode);
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7766,7 +7869,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7843,6 +7946,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
@@ -7883,12 +7991,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
-	if (!cfun->machine->dynamic_frm)
-	  {
-	    cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-	    emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-	  }
-
 	  /* According to RVV 1.0 spec, all vector floating-point operations use
 	     the dynamic rounding mode in the frm register.  Likewise in other
 	     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index f745888127c..05fd7600ba4 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -686,7 +686,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
         (const_string "none")))
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond [(eq_attr "type" "vfalu")
          (cond
 	   [(match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
@@ -813,7 +813,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-25  6:07   ` Li, Pan2
@ 2023-07-25  8:38     ` Robin Dapp
  2023-07-25 11:53       ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Robin Dapp @ 2023-07-25  8:38 UTC (permalink / raw)
  To: Li, Pan2, gcc-patches; +Cc: rdapp.gcc, juzhe.zhong, kito.cheng, Wang, Yanzhang

Hi Pan,

> Given we have a call, we would like to restore before call and then
> backup frm after call. Looks current mode switching cannot emit insn
> like that, it can only either emit insn before (mostly) or after
> (when NOTE_INSN_BASIC_BLOCK_P). Thus, we try to emit the one after
> call when needed as a specially handling here.

Would you mind explaining a bit more here?  As far as I know we can
perform necessary mode switching (including saving necessary
registers) directly after function entry and right before function
exit.  Is this somehow too early or too late or cannot handle what
you want?

The patch in itself makes sense (apart from some nits and possible
cleanups) but I'm still missing the bigger picture.  For me it gets
more confusing with every patch to be honest :D

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-25  8:38     ` Robin Dapp
@ 2023-07-25 11:53       ` Li, Pan2
  2023-07-25 13:23         ` Kito Cheng
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-25 11:53 UTC (permalink / raw)
  To: Robin Dapp, gcc-patches; +Cc: juzhe.zhong, kito.cheng, Wang, Yanzhang

Thanks Robin. Let me share one example for the CALL scenario, considering below code.

external int fesetround(int rounding_mode);

test_call_for_rm:
                                                 <-        FRM X
   vfadd RTZ (static)               <-        FRM RTZ
                                                 <-        RESTORE FRM X
   call fesetround RMM         <-        Change FRM to RMM during the call
                                                 <-        Backup the FRM RMM
   vfadd RUP (static)              <-         FRM RUP
                                                 <-         Restore the FRM to RMM
   ret

When emit at the insn call, we need to emit 2 insns, one restore before the call and one backup after call, to ensure 2 things.

1. The static FRM should not pollute the call.
2. The updated FRM in the call will alive to the end of the cfun.

Unfortunately, current mode switching cannot emit 2 insns as above, it mostly emits after. It become even worse when the call
is the last insn of the bb, we try to do some special handling in needed function for this.

And thank robin again for nits and cleanups, like previous/next_nonnote_nondebug_insn_bb.

Pan

-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Tuesday, July 25, 2023 4:38 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

Hi Pan,

> Given we have a call, we would like to restore before call and then
> backup frm after call. Looks current mode switching cannot emit insn
> like that, it can only either emit insn before (mostly) or after
> (when NOTE_INSN_BASIC_BLOCK_P). Thus, we try to emit the one after
> call when needed as a specially handling here.

Would you mind explaining a bit more here?  As far as I know we can
perform necessary mode switching (including saving necessary
registers) directly after function entry and right before function
exit.  Is this somehow too early or too late or cannot handle what
you want?

The patch in itself makes sense (apart from some nits and possible
cleanups) but I'm still missing the bigger picture.  For me it gets
more confusing with every patch to be honest :D

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-25 11:53       ` Li, Pan2
@ 2023-07-25 13:23         ` Kito Cheng
  2023-07-25 14:12           ` Robin Dapp
  0 siblings, 1 reply; 49+ messages in thread
From: Kito Cheng @ 2023-07-25 13:23 UTC (permalink / raw)
  To: Li, Pan2; +Cc: Robin Dapp, gcc-patches, juzhe.zhong, Wang, Yanzhang

Hi Robin:

Give few more context about the design:

The call fesetround could be any function in practice, and we never
know if that function might use dynamic rounding mode floating point
operation or not, also we don't know if it will be called fesetround
or not.

So that's why we want to restore before function call to make sure we
don't break rounding mode for any inner function, also backup the frm
after function call can handle the case if the inner function has
changed global rounding mode.

On Tue, Jul 25, 2023 at 7:53 PM Li, Pan2 <pan2.li@intel.com> wrote:
>
> Thanks Robin. Let me share one example for the CALL scenario, considering below code.
>
> external int fesetround(int rounding_mode);
>
> test_call_for_rm:
>                                                  <-        FRM X
>    vfadd RTZ (static)               <-        FRM RTZ
>                                                  <-        RESTORE FRM X
>    call fesetround RMM         <-        Change FRM to RMM during the call
>                                                  <-        Backup the FRM RMM
>    vfadd RUP (static)              <-         FRM RUP
>                                                  <-         Restore the FRM to RMM
>    ret
>
> When emit at the insn call, we need to emit 2 insns, one restore before the call and one backup after call, to ensure 2 things.
>
> 1. The static FRM should not pollute the call.
> 2. The updated FRM in the call will alive to the end of the cfun.
>
> Unfortunately, current mode switching cannot emit 2 insns as above, it mostly emits after. It become even worse when the call
> is the last insn of the bb, we try to do some special handling in needed function for this.
>
> And thank robin again for nits and cleanups, like previous/next_nonnote_nondebug_insn_bb.
>
> Pan
>
> -----Original Message-----
> From: Robin Dapp <rdapp.gcc@gmail.com>
> Sent: Tuesday, July 25, 2023 4:38 PM
> To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
> Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
> Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
>
> Hi Pan,
>
> > Given we have a call, we would like to restore before call and then
> > backup frm after call. Looks current mode switching cannot emit insn
> > like that, it can only either emit insn before (mostly) or after
> > (when NOTE_INSN_BASIC_BLOCK_P). Thus, we try to emit the one after
> > call when needed as a specially handling here.
>
> Would you mind explaining a bit more here?  As far as I know we can
> perform necessary mode switching (including saving necessary
> registers) directly after function entry and right before function
> exit.  Is this somehow too early or too late or cannot handle what
> you want?
>
> The patch in itself makes sense (apart from some nits and possible
> cleanups) but I'm still missing the bigger picture.  For me it gets
> more confusing with every patch to be honest :D
>
> Regards
>  Robin
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-25 13:23         ` Kito Cheng
@ 2023-07-25 14:12           ` Robin Dapp
  2023-07-26 13:08             ` Robin Dapp
       [not found]             ` <63471C6E126E44CF+D1CEA4C9-0050-43CD-8DE3-26EBD7AEE6DA@rivai.ai>
  0 siblings, 2 replies; 49+ messages in thread
From: Robin Dapp @ 2023-07-25 14:12 UTC (permalink / raw)
  To: Kito Cheng, Li, Pan2; +Cc: rdapp.gcc, gcc-patches, juzhe.zhong, Wang, Yanzhang

> The call fesetround could be any function in practice, and we never
> know if that function might use dynamic rounding mode floating point
> operation or not, also we don't know if it will be called fesetround
> or not.
> 
> So that's why we want to restore before function call to make sure we
> don't break rounding mode for any inner function, also backup the frm
> after function call can handle the case if the inner function has
> changed global rounding mode.

Ah, that clarifies things a bit.  Yes, I figured - the function is
opaque anyway.

I think we're touching a general question here, I suppose there already
have been discussions on the LLVM side about this?  What about ABI
implications?  By saving and restoring before and after a function
call we assume the FRM register to be call clobbered instead of
letting the function/call save/restore it.  Apart from fesetround
I can't imagine many cases where we would want to re-use the rounding
mode from inside a call so it might be advantageous to leave the
burden of saving/restoring to the callee.  But that's a similar
discussion as with the vector ABI so I don't expect a conclusion ;)

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-25 14:12           ` Robin Dapp
@ 2023-07-26 13:08             ` Robin Dapp
  2023-07-26 21:40               ` Jeff Law
  2023-07-27  2:09               ` Li, Pan2
       [not found]             ` <63471C6E126E44CF+D1CEA4C9-0050-43CD-8DE3-26EBD7AEE6DA@rivai.ai>
  1 sibling, 2 replies; 49+ messages in thread
From: Robin Dapp @ 2023-07-26 13:08 UTC (permalink / raw)
  To: Kito Cheng, Li, Pan2; +Cc: rdapp.gcc, gcc-patches, juzhe.zhong, Wang, Yanzhang

So after thinking about it again - I'm still not really sure
I like treating every function as essentially an fesetround.
There is a reason why fesetround is special.  Does LLVM behave
the same way?

But supposing we really, really want it and assuming there's consensus:

+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();

A comment here would be nice why we need a sequence for a single
instruction.  I'm not fully aware what insert_insn_end_basic_block
does but won't a

  rtx_insn *last = BB_END (bb);
  emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);

suffice?  One way or another need these kinds of non-local
constructs here don't seem entirely rock solid.

@@ -7843,6 +7946,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;

Why do we appear to return a different mode here?  We already request
FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
we do not change the mode so we could just always return the incoming
mode?

This is not part of this patch but related and originally I assumed
that we would untangle things after the initial patch, so:

   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;

frm_unknown_dynamic_p checks CALL_P which has already been checked
before.  It returns FRM_MODE_DYN instead of FRM_MODE_DYN_CALL, though.

Apart from that, the function is called unknown_dynamic but we check
for a SET of FRM?  Wouldn't something that sets FRM rather be a "static"
rounding-mode instruction? (using the "static" wording from before)

Then we also still have

  if (reg_mentioned_p (gen_rtx_REG (SImode, FRM_REGNUM), PATTERN (insn)))
    return get_attr_frm_mode (insn);

from before.  Isn't that pretty much the same?


+  assert_equal (NEW_FRM, get_frm (),
+               "The value of frm register should be NEW_FRM.");

Here and in similar cases, NEW_FRM is not exactly telling.  Can't we
use "should be " and then 

+      fprintf (stdout, "%s %d, but get %d != %d\n", message, a, b);

or similar?

+           will do the mode switch from MODE_CALL to MODE_NON_NONE natively.

NON -> FRM.

+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"

This causes a FAIL for me.  I believe the scan directives are off by one.

Are you going to do asm directives in a separate patch?
Similar to vxrm_unknown_p we could just check for one here
and handle it similarly to a call.  Would need some more tests, though.

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
       [not found]             ` <63471C6E126E44CF+D1CEA4C9-0050-43CD-8DE3-26EBD7AEE6DA@rivai.ai>
@ 2023-07-26 13:35               ` Li, Pan2
  2023-07-26 13:43                 ` Li, Pan2
  2023-07-26 13:46               ` Robin Dapp
  1 sibling, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-26 13:35 UTC (permalink / raw)
  To: juzhe.zhong, Robin Dapp
  Cc: Kito Cheng, rdapp.gcc, gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 4289 bytes --]

Thanks Robin for comments.

Yes, you can reference this link to compare the difference between gcc and llvm. And I am trying to understand and send the V8 later.

https://godbolt.org/z/4E434vaqv

Pan

From: juzhe.zhong <juzhe.zhong@rivai.ai>
Sent: Wednesday, July 26, 2023 9:13 PM
To: Robin Dapp <rdapp.gcc@gmail.com>
Cc: Kito Cheng <kito.cheng@sifive.com>; Li, Pan2 <pan2.li@intel.com>; rdapp.gcc@gmail.com; gcc-patches@gcc.gnu.org; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

current llvm didn't do any pre optimization.  They always backup+restore for each rounding mode intrinsic

We should not reference current llvm
---- Replied Message ----
From
Robin Dapp<rdapp.gcc@gmail.com><mailto:rdapp.gcc@gmail.com>
Date
07/26/2023 21:08
To
Kito Cheng<kito.cheng@sifive.com><mailto:kito.cheng@sifive.com>,
Li, Pan2<pan2.li@intel.com><mailto:pan2.li@intel.com>
Cc
rdapp.gcc@gmail.com<rdapp.gcc@gmail.com><mailto:rdapp.gcc@gmail.com>,
gcc-patches@gcc.gnu.org<gcc-patches@gcc.gnu.org><mailto:gcc-patches@gcc.gnu.org>,
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai><mailto:juzhe.zhong@rivai.ai>,
Wang, Yanzhang<yanzhang.wang@intel.com><mailto:yanzhang.wang@intel.com>
Subject
Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
So after thinking about it again - I'm still not really sure
I like treating every function as essentially an fesetround.
There is a reason why fesetround is special.  Does LLVM behave
the same way?

But supposing we really, really want it and assuming there's consensus:

+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();

A comment here would be nice why we need a sequence for a single
instruction.  I'm not fully aware what insert_insn_end_basic_block
does but won't a

 rtx_insn *last = BB_END (bb);
 emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);

suffice?  One way or another need these kinds of non-local
constructs here don't seem entirely rock solid.

@@ -7843,6 +7946,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;

Why do we appear to return a different mode here?  We already request
FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
we do not change the mode so we could just always return the incoming
mode?

This is not part of this patch but related and originally I assumed
that we would untangle things after the initial patch, so:

  if (frm_unknown_dynamic_p (insn))
    return FRM_MODE_DYN;

frm_unknown_dynamic_p checks CALL_P which has already been checked
before.  It returns FRM_MODE_DYN instead of FRM_MODE_DYN_CALL, though.

Apart from that, the function is called unknown_dynamic but we check
for a SET of FRM?  Wouldn't something that sets FRM rather be a "static"
rounding-mode instruction? (using the "static" wording from before)

Then we also still have

 if (reg_mentioned_p (gen_rtx_REG (SImode, FRM_REGNUM), PATTERN (insn)))
   return get_attr_frm_mode (insn);

from before.  Isn't that pretty much the same?


+  assert_equal (NEW_FRM, get_frm (),
+               "The value of frm register should be NEW_FRM.");

Here and in similar cases, NEW_FRM is not exactly telling.  Can't we
use "should be " and then

+      fprintf (stdout, "%s %d, but get %d != %d\n", message, a, b);

or similar?

+           will do the mode switch from MODE_CALL to MODE_NON_NONE natively.

NON -> FRM.

+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"

This causes a FAIL for me.  I believe the scan directives are off by one.

Are you going to do asm directives in a separate patch?
Similar to vxrm_unknown_p we could just check for one here
and handle it similarly to a call.  Would need some more tests, though.

Regards
Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 13:35               ` Li, Pan2
@ 2023-07-26 13:43                 ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-26 13:43 UTC (permalink / raw)
  To: Li, Pan2, juzhe.zhong, Robin Dapp; +Cc: Kito Cheng, gcc-patches, Wang, Yanzhang

For clarification, the llvm side is lack of reference value, due to it will always back up before vfadd, and then restore it after vfadd. For example as below clang trunk code-gen.

test_float_point_dynamic_frm:           # @test_float_point_dynamic_frm
        vsetvli zero, a0, e32, m1, ta, ma

        fsrmi   a0, 1                                     <- set and backup
        vfadd.vv        v9, v8, v9
        fsrm    a0                                         <- restore
        
        fsrmi   a0, 2
        vfadd.vv        v9, v8, v9
        fsrm    a0

        fsrmi   a0, 4
        vfadd.vv        v9, v8, v9
        fsrm    a0

        fsrmi   a0, 3
        vfadd.vv        v8, v8, v9
        fsrm    a0

        ret

Pan

-----Original Message-----
From: Gcc-patches <gcc-patches-bounces+pan2.li=intel.com@gcc.gnu.org> On Behalf Of Li, Pan2 via Gcc-patches
Sent: Wednesday, July 26, 2023 9:35 PM
To: juzhe.zhong <juzhe.zhong@rivai.ai>; Robin Dapp <rdapp.gcc@gmail.com>
Cc: Kito Cheng <kito.cheng@sifive.com>; rdapp.gcc@gmail.com; gcc-patches@gcc.gnu.org; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

Thanks Robin for comments.

Yes, you can reference this link to compare the difference between gcc and llvm. And I am trying to understand and send the V8 later.

https://godbolt.org/z/4E434vaqv

Pan

From: juzhe.zhong <juzhe.zhong@rivai.ai>
Sent: Wednesday, July 26, 2023 9:13 PM
To: Robin Dapp <rdapp.gcc@gmail.com>
Cc: Kito Cheng <kito.cheng@sifive.com>; Li, Pan2 <pan2.li@intel.com>; rdapp.gcc@gmail.com; gcc-patches@gcc.gnu.org; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

current llvm didn't do any pre optimization.  They always backup+restore for each rounding mode intrinsic

We should not reference current llvm
---- Replied Message ----
From
Robin Dapp<rdapp.gcc@gmail.com><mailto:rdapp.gcc@gmail.com>
Date
07/26/2023 21:08
To
Kito Cheng<kito.cheng@sifive.com><mailto:kito.cheng@sifive.com>,
Li, Pan2<pan2.li@intel.com><mailto:pan2.li@intel.com>
Cc
rdapp.gcc@gmail.com<rdapp.gcc@gmail.com><mailto:rdapp.gcc@gmail.com>,
gcc-patches@gcc.gnu.org<gcc-patches@gcc.gnu.org><mailto:gcc-patches@gcc.gnu.org>,
juzhe.zhong@rivai.ai<juzhe.zhong@rivai.ai><mailto:juzhe.zhong@rivai.ai>,
Wang, Yanzhang<yanzhang.wang@intel.com><mailto:yanzhang.wang@intel.com>
Subject
Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
So after thinking about it again - I'm still not really sure
I like treating every function as essentially an fesetround.
There is a reason why fesetround is special.  Does LLVM behave
the same way?

But supposing we really, really want it and assuming there's consensus:

+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();

A comment here would be nice why we need a sequence for a single
instruction.  I'm not fully aware what insert_insn_end_basic_block
does but won't a

 rtx_insn *last = BB_END (bb);
 emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);

suffice?  One way or another need these kinds of non-local
constructs here don't seem entirely rock solid.

@@ -7843,6 +7946,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
static int
riscv_frm_mode_after (rtx_insn *insn, int mode)
{
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;

Why do we appear to return a different mode here?  We already request
FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
we do not change the mode so we could just always return the incoming
mode?

This is not part of this patch but related and originally I assumed
that we would untangle things after the initial patch, so:

  if (frm_unknown_dynamic_p (insn))
    return FRM_MODE_DYN;

frm_unknown_dynamic_p checks CALL_P which has already been checked
before.  It returns FRM_MODE_DYN instead of FRM_MODE_DYN_CALL, though.

Apart from that, the function is called unknown_dynamic but we check
for a SET of FRM?  Wouldn't something that sets FRM rather be a "static"
rounding-mode instruction? (using the "static" wording from before)

Then we also still have

 if (reg_mentioned_p (gen_rtx_REG (SImode, FRM_REGNUM), PATTERN (insn)))
   return get_attr_frm_mode (insn);

from before.  Isn't that pretty much the same?


+  assert_equal (NEW_FRM, get_frm (),
+               "The value of frm register should be NEW_FRM.");

Here and in similar cases, NEW_FRM is not exactly telling.  Can't we
use "should be " and then

+      fprintf (stdout, "%s %d, but get %d != %d\n", message, a, b);

or similar?

+           will do the mode switch from MODE_CALL to MODE_NON_NONE natively.

NON -> FRM.

+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"

This causes a FAIL for me.  I believe the scan directives are off by one.

Are you going to do asm directives in a separate patch?
Similar to vxrm_unknown_p we could just check for one here
and handle it similarly to a call.  Would need some more tests, though.

Regards
Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
       [not found]             ` <63471C6E126E44CF+D1CEA4C9-0050-43CD-8DE3-26EBD7AEE6DA@rivai.ai>
  2023-07-26 13:35               ` Li, Pan2
@ 2023-07-26 13:46               ` Robin Dapp
  2023-07-26 13:57                 ` Kito Cheng
  2023-07-26 14:18                 ` 钟居哲
  1 sibling, 2 replies; 49+ messages in thread
From: Robin Dapp @ 2023-07-26 13:46 UTC (permalink / raw)
  To: juzhe.zhong, Li, Pan2; +Cc: rdapp.gcc, Kito Cheng, gcc-patches, Wang, Yanzhang

> current llvm didn't do any pre optimization.  They always
> backup+restore for each rounding mode intrinsic

I see.  There is still the option of lazily restoring the
(entry) FRM before a function call but not read the FRM
after every call.  Do we have any data on how good or bad the
mode-switching LCM works when we explicitly backup and restore
for each intrinsic?

Regards
 Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 13:46               ` Robin Dapp
@ 2023-07-26 13:57                 ` Kito Cheng
  2023-07-26 14:05                   ` Kito Cheng
  2023-07-26 14:18                 ` 钟居哲
  1 sibling, 1 reply; 49+ messages in thread
From: Kito Cheng @ 2023-07-26 13:57 UTC (permalink / raw)
  To: Robin Dapp; +Cc: Kito Cheng, Li, Pan2, Wang, Yanzhang, gcc-patches, juzhe.zhong

[-- Attachment #1: Type: text/plain, Size: 687 bytes --]

Sorry for late ack on the LLVM part, I can say they are did the same
model/semantics, it done by our team member too, and I have regular meeting
with that guy :P

Robin Dapp via Gcc-patches <gcc-patches@gcc.gnu.org>於 2023年7月26日 週三,21:47寫道:

> > current llvm didn't do any pre optimization.  They always
> > backup+restore for each rounding mode intrinsic
>
> I see.  There is still the option of lazily restoring the
> (entry) FRM before a function call but not read the FRM
> after every call.  Do we have any data on how good or bad the
> mode-switching LCM works when we explicitly backup and restore
> for each intrinsic?
>
> Regards
>  Robin
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 13:57                 ` Kito Cheng
@ 2023-07-26 14:05                   ` Kito Cheng
  2023-07-26 14:10                     ` Robin Dapp
  0 siblings, 1 reply; 49+ messages in thread
From: Kito Cheng @ 2023-07-26 14:05 UTC (permalink / raw)
  To: Kito Cheng; +Cc: Li, Pan2, Robin Dapp, Wang, Yanzhang, gcc-patches, juzhe.zhong

[-- Attachment #1: Type: text/plain, Size: 897 bytes --]

CSR write could be expensive, it will flush whole pipeline in some RISC-V
core implementation…

Kito Cheng <kito.cheng@gmail.com>於 2023年7月26日 週三,21:57寫道:

> Sorry for late ack on the LLVM part, I can say they are did the same
> model/semantics, it done by our team member too, and I have regular meeting
> with that guy :P
>
> Robin Dapp via Gcc-patches <gcc-patches@gcc.gnu.org>於 2023年7月26日
> 週三,21:47寫道:
>
>> > current llvm didn't do any pre optimization.  They always
>> > backup+restore for each rounding mode intrinsic
>>
>> I see.  There is still the option of lazily restoring the
>> (entry) FRM before a function call but not read the FRM
>> after every call.  Do we have any data on how good or bad the
>> mode-switching LCM works when we explicitly backup and restore
>> for each intrinsic?
>>
>> Regards
>>  Robin
>>
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 14:05                   ` Kito Cheng
@ 2023-07-26 14:10                     ` Robin Dapp
  0 siblings, 0 replies; 49+ messages in thread
From: Robin Dapp @ 2023-07-26 14:10 UTC (permalink / raw)
  To: Kito Cheng, Kito Cheng
  Cc: rdapp.gcc, Li, Pan2, Wang, Yanzhang, gcc-patches, juzhe.zhong


> CSR write could be expensive, it will flush whole pipeline in some
> RISC-V core implementation…
Hopefully not flush but just sequentialize but yes, it's usually a
performance concern.  However if we set the rounding mode to something
else for an intrinsic and then call a function we want to restore it
one way or another, right?

That's also the reason why glibc has done a lot of work to minimize
fesetround calls (or other fcsr setters).

Regards
 Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 13:46               ` Robin Dapp
  2023-07-26 13:57                 ` Kito Cheng
@ 2023-07-26 14:18                 ` 钟居哲
  2023-07-26 14:30                   ` Li, Pan2
  1 sibling, 1 reply; 49+ messages in thread
From: 钟居哲 @ 2023-07-26 14:18 UTC (permalink / raw)
  To: rdapp.gcc, pan2.li; +Cc: rdapp.gcc, kito.cheng, gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 1080 bytes --]

Explicitly backup and restore for each intrinsic just the same as we did for CALL in this patch.

I can't have the data to prove how good we use LCM/PRE of mode switching but I trust it.

Since the the LCM/PRE is the key optimization method of VSETVL PASS which is doing good job on VSETVL instruction optimizations.

I don't we should give up LCM/PRE chance then just backup and restore for each intrinsic bindly.
 



juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-07-26 21:46
To: juzhe.zhong; Li, Pan2
CC: rdapp.gcc; Kito Cheng; gcc-patches@gcc.gnu.org; Wang, Yanzhang
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
> current llvm didn't do any pre optimization.  They always
> backup+restore for each rounding mode intrinsic
 
I see.  There is still the option of lazily restoring the
(entry) FRM before a function call but not read the FRM
after every call.  Do we have any data on how good or bad the
mode-switching LCM works when we explicitly backup and restore
for each intrinsic?
 
Regards
Robin
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 14:18                 ` 钟居哲
@ 2023-07-26 14:30                   ` Li, Pan2
  2023-07-26 15:34                     ` Kito Cheng
  2023-07-26 21:01                     ` Robin Dapp
  0 siblings, 2 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-26 14:30 UTC (permalink / raw)
  To: 钟居哲, rdapp.gcc
  Cc: rdapp.gcc, kito.cheng, gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 2148 bytes --]

As Juzhe mentioned, the problem of the CALL is resolved by LCM/PRE similar to the VSETVL pass, which is well proofed up to a point.

I would like to propose that being focus and moving forward for this patch itself, the underlying other RVV floating point API support and the RVV instrinsic API fully tests depend on this.

Of course, I am working on PATCH v8 and thanks again for Robin’s comments.

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai>
Sent: Wednesday, July 26, 2023 10:18 PM
To: rdapp.gcc <rdapp.gcc@gmail.com>; Li, Pan2 <pan2.li@intel.com>
Cc: rdapp.gcc <rdapp.gcc@gmail.com>; kito.cheng <kito.cheng@sifive.com>; gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

Explicitly backup and restore for each intrinsic just the same as we did for CALL in this patch.

I can't have the data to prove how good we use LCM/PRE of mode switching but I trust it.

Since the the LCM/PRE is the key optimization method of VSETVL PASS which is doing good job on VSETVL instruction optimizations.

I don't we should give up LCM/PRE chance then just backup and restore for each intrinsic bindly.


________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Robin Dapp<mailto:rdapp.gcc@gmail.com>
Date: 2023-07-26 21:46
To: juzhe.zhong<mailto:juzhe.zhong@rivai.ai>; Li, Pan2<mailto:pan2.li@intel.com>
CC: rdapp.gcc<mailto:rdapp.gcc@gmail.com>; Kito Cheng<mailto:kito.cheng@sifive.com>; gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>; Wang, Yanzhang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
> current llvm didn't do any pre optimization.  They always
> backup+restore for each rounding mode intrinsic

I see.  There is still the option of lazily restoring the
(entry) FRM before a function call but not read the FRM
after every call.  Do we have any data on how good or bad the
mode-switching LCM works when we explicitly backup and restore
for each intrinsic?

Regards
Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 14:30                   ` Li, Pan2
@ 2023-07-26 15:34                     ` Kito Cheng
  2023-07-26 16:00                       ` Palmer Dabbelt
  2023-07-26 21:01                     ` Robin Dapp
  1 sibling, 1 reply; 49+ messages in thread
From: Kito Cheng @ 2023-07-26 15:34 UTC (permalink / raw)
  To: Li, Pan2; +Cc: Wang, Yanzhang, gcc-patches, rdapp.gcc, 钟居哲

[-- Attachment #1: Type: text/plain, Size: 3196 bytes --]

I would say LCM/PRE is the key of this set of static rounding model
intrinsic, otherwise I think it's will push people to using dynamic with
fesetrouding mode or inline asm to set the rounding mode for performance
issue - it's kind of opposite way of the design concept, we want to provide
a reliable way with performance to precisely control the ronding model.

For the function call stuff that could be resolved by fenv_access pragma in
theory, since it can be an annotation to tell compiler some function has
modify fenv or not, but unfortunately it’s not well modeled within GCC yet,
so we must did the conservative to make sure we didn't break anything.

And also the LLVM side is trying to implement some simple LCM/PRE to
optimize that, so I believe we need LCM/PRE based mode switching to do that.


Li, Pan2 <pan2.li@intel.com>於 2023年7月26日 週三,22:31寫道:

> As Juzhe mentioned, the problem of the CALL is resolved by LCM/PRE
> similar to the VSETVL pass, which is well proofed up to a point.
>
>
>
> I would like to propose that being focus and moving forward for this patch
> itself, the underlying other RVV floating point API support and the RVV
> instrinsic API fully tests depend on this.
>
>
>
> Of course, I am working on PATCH v8 and thanks again for Robin’s comments.
>
>
>
> Pan
>
>
>
> *From:* 钟居哲 <juzhe.zhong@rivai.ai>
> *Sent:* Wednesday, July 26, 2023 10:18 PM
> *To:* rdapp.gcc <rdapp.gcc@gmail.com>; Li, Pan2 <pan2.li@intel.com>
> *Cc:* rdapp.gcc <rdapp.gcc@gmail.com>; kito.cheng <kito.cheng@sifive.com>;
> gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <
> yanzhang.wang@intel.com>
> *Subject:* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point
> dynamic rounding
>
>
>
> Explicitly backup and restore for each intrinsic just the same as we did
> for CALL in this patch.
>
>
>
> I can't have the data to prove how good we use LCM/PRE of mode switching
> but I trust it.
>
>
>
> Since the the LCM/PRE is the key optimization method of VSETVL PASS which
> is doing good job on VSETVL instruction optimizations.
>
>
>
> I don't we should give up LCM/PRE chance then just backup and restore for
> each intrinsic bindly.
>
>
>
>
> ------------------------------
>
> juzhe.zhong@rivai.ai
>
>
>
> *From:* Robin Dapp <rdapp.gcc@gmail.com>
>
> *Date:* 2023-07-26 21:46
>
> *To:* juzhe.zhong <juzhe.zhong@rivai.ai>; Li, Pan2 <pan2.li@intel.com>
>
> *CC:* rdapp.gcc <rdapp.gcc@gmail.com>; Kito Cheng <kito.cheng@sifive.com>;
> gcc-patches@gcc.gnu.org; Wang, Yanzhang <yanzhang.wang@intel.com>
>
> *Subject:* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point
> dynamic rounding
>
> > current llvm didn't do any pre optimization.  They always
>
> > backup+restore for each rounding mode intrinsic
>
>
>
> I see.  There is still the option of lazily restoring the
>
> (entry) FRM before a function call but not read the FRM
>
> after every call.  Do we have any data on how good or bad the
>
> mode-switching LCM works when we explicitly backup and restore
>
> for each intrinsic?
>
>
>
> Regards
>
> Robin
>
>
>
>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 15:34                     ` Kito Cheng
@ 2023-07-26 16:00                       ` Palmer Dabbelt
  0 siblings, 0 replies; 49+ messages in thread
From: Palmer Dabbelt @ 2023-07-26 16:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: pan2.li, yanzhang.wang, gcc-patches, rdapp.gcc, juzhe.zhong

On Wed, 26 Jul 2023 08:34:14 PDT (-0700), gcc-patches@gcc.gnu.org wrote:
> I would say LCM/PRE is the key of this set of static rounding model
> intrinsic, otherwise I think it's will push people to using dynamic with
> fesetrouding mode or inline asm to set the rounding mode for performance
> issue - it's kind of opposite way of the design concept, we want to provide
> a reliable way with performance to precisely control the ronding model.
>
> For the function call stuff that could be resolved by fenv_access pragma in
> theory, since it can be an annotation to tell compiler some function has
> modify fenv or not, but unfortunately it’s not well modeled within GCC yet,
> so we must did the conservative to make sure we didn't break anything.
>
> And also the LLVM side is trying to implement some simple LCM/PRE to
> optimize that, so I believe we need LCM/PRE based mode switching to do that.

IMO that's a perfectly reasonably way to start: let's just get something 
that's correct and simple, if we need to do more complicated stuff later 
we can always add it.

There's going to be a very small amount of this code written my a very 
small number of people (that are likely very close to the compiler teams 
doing the optimizations here), so we can just all work with each other 
to sort out any important performance issues as we go.

I think whether LCM or entry/exit performs better is probably just going 
to boil down to some uarch/workload specific decisions, so as long as 
whatever we have is correct and reasonably simple it seems fine for now.  
Given how little of this code there's going to be it's probably not 
worth spending a ton of time on things until we have a concrete use case 
to drive things.

Let's just make sure to also update the intrinsic spec to get rid of the 
grey area here, that way we can point to something if we want to 
optimize differently in the future.

> Li, Pan2 <pan2.li@intel.com>於 2023年7月26日 週三,22:31寫道:
>
>> As Juzhe mentioned, the problem of the CALL is resolved by LCM/PRE
>> similar to the VSETVL pass, which is well proofed up to a point.
>>
>>
>>
>> I would like to propose that being focus and moving forward for this patch
>> itself, the underlying other RVV floating point API support and the RVV
>> instrinsic API fully tests depend on this.
>>
>>
>>
>> Of course, I am working on PATCH v8 and thanks again for Robin’s comments.
>>
>>
>>
>> Pan
>>
>>
>>
>> *From:* 钟居哲 <juzhe.zhong@rivai.ai>
>> *Sent:* Wednesday, July 26, 2023 10:18 PM
>> *To:* rdapp.gcc <rdapp.gcc@gmail.com>; Li, Pan2 <pan2.li@intel.com>
>> *Cc:* rdapp.gcc <rdapp.gcc@gmail.com>; kito.cheng <kito.cheng@sifive.com>;
>> gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <
>> yanzhang.wang@intel.com>
>> *Subject:* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point
>> dynamic rounding
>>
>>
>>
>> Explicitly backup and restore for each intrinsic just the same as we did
>> for CALL in this patch.
>>
>>
>>
>> I can't have the data to prove how good we use LCM/PRE of mode switching
>> but I trust it.
>>
>>
>>
>> Since the the LCM/PRE is the key optimization method of VSETVL PASS which
>> is doing good job on VSETVL instruction optimizations.
>>
>>
>>
>> I don't we should give up LCM/PRE chance then just backup and restore for
>> each intrinsic bindly.
>>
>>
>>
>>
>> ------------------------------
>>
>> juzhe.zhong@rivai.ai
>>
>>
>>
>> *From:* Robin Dapp <rdapp.gcc@gmail.com>
>>
>> *Date:* 2023-07-26 21:46
>>
>> *To:* juzhe.zhong <juzhe.zhong@rivai.ai>; Li, Pan2 <pan2.li@intel.com>
>>
>> *CC:* rdapp.gcc <rdapp.gcc@gmail.com>; Kito Cheng <kito.cheng@sifive.com>;
>> gcc-patches@gcc.gnu.org; Wang, Yanzhang <yanzhang.wang@intel.com>
>>
>> *Subject:* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point
>> dynamic rounding
>>
>> > current llvm didn't do any pre optimization.  They always
>>
>> > backup+restore for each rounding mode intrinsic
>>
>>
>>
>> I see.  There is still the option of lazily restoring the
>>
>> (entry) FRM before a function call but not read the FRM
>>
>> after every call.  Do we have any data on how good or bad the
>>
>> mode-switching LCM works when we explicitly backup and restore
>>
>> for each intrinsic?
>>
>>
>>
>> Regards
>>
>> Robin
>>
>>
>>
>>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 14:30                   ` Li, Pan2
  2023-07-26 15:34                     ` Kito Cheng
@ 2023-07-26 21:01                     ` Robin Dapp
  1 sibling, 0 replies; 49+ messages in thread
From: Robin Dapp @ 2023-07-26 21:01 UTC (permalink / raw)
  To: Li, Pan2, 钟居哲
  Cc: rdapp.gcc, kito.cheng, gcc-patches, Wang, Yanzhang

> I would like to propose that being focus and moving forward for this
> patch itself, the underlying other RVV floating point API support and
> the RVV instrinsic API fully tests depend on this.

Sorry, I didn't mean to ditch LCM/mode switching.  I believe it is doing
a pretty good job and we should continue to use it.  The changes in this
patch (and the ones before) seem to follow a certain plan but, at least
to me, it only became obvious with this last patch.  We're already lost
in details when the fundamentals are not agreed upon yet.  It would have
been easier to discuss (and quicker to "focus and move forward") if the
cover letter had already laid out the possible alternatives and their
respective pros and cons instead, even more so when many things depend
on it.

Still, three things:
 
 (1) I'm fully on board with restoring the rounding mode after changing
 it implicitly via an intrinsic (guess everybody is).  This needs to be
 done anyway and also implies a costly fsrm.  "Forcing" it before a call
 can most likely be treated like any other DYN instruction requiring the
 "entry" rounding mode.  Likewise restoring at function exit.  The
 placement of the necessary restores LCM can handle reasonably well.

 (2) What I'm not entirely happy with is assuming that every function
 call can _change_ the rounding mode and we always need to re-backup it.
 I realize that it might be a necessary evil because all other options
 are worse.  Assuming no change through a call makes properly using
 fesetround-like calls impossible as they would clobber our backup
 register.  This patch takes the approach to re-backup after every call.
 As-is, wouldn't we also need to make sure that GCC  knows that a call
 clobbers the FRM (via clobber: (reg:SI 69 frm)) so we don't accidentally
 move something beyond it?

 (3) One other option I can think of is "localized" re-backup of the
 FRM before each mode-changing intrinsic.  That would result in
 redundant save/restore insns around those than with the call proposal
 and therefore likely worse.  Whether that is relevant when the restore
 is slow anyway might be debatable.  Yet, it's not a given that storing
 the FRM always is an in-order operation, it has just mostly been
 that way historically.  Another conceivable option (and maybe even
 the right thing to do) would be special treatment, like a propagating
 flag etc. for fesetround.  That's common code and not likely to happen
 or land soon, though.

Regards
 Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 13:08             ` Robin Dapp
@ 2023-07-26 21:40               ` Jeff Law
  2023-07-26 22:21                 ` 钟居哲
  2023-07-27  2:09               ` Li, Pan2
  1 sibling, 1 reply; 49+ messages in thread
From: Jeff Law @ 2023-07-26 21:40 UTC (permalink / raw)
  To: Robin Dapp, Kito Cheng, Li, Pan2; +Cc: gcc-patches, juzhe.zhong, Wang, Yanzhang



On 7/26/23 07:08, Robin Dapp via Gcc-patches wrote:
> So after thinking about it again - I'm still not really sure
> I like treating every function as essentially an fesetround.
> There is a reason why fesetround is special.  Does LLVM behave
> the same way?
> 
> But supposing we really, really want it and assuming there's consensus:
> 
> +  start_sequence ();
> +  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
> +  rtx_insn *backup_insn = get_insns ();
> +  end_sequence ();
> 
> A comment here would be nice why we need a sequence for a single
> instruction.  I'm not fully aware what insert_insn_end_basic_block
> does but won't a
> 
>    rtx_insn *last = BB_END (bb);
>    emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);
> 
> suffice?  One way or another need these kinds of non-local
> constructs here don't seem entirely rock solid.
Typically an LCM algorithm needs to insert on edges rather than at the 
end of blocks -- this is particularly important to preserve its property 
that on no path through the CFG can we have more evaluations of the 
expression after PRE/LCM than before PRE/LCM.

The other thing edge insertions do is simplify the abnormal critical 
edge problems.  I'd have to dig into the precise details, but in the 
generic PRE/LCM code we clobber the available expressions on critical 
edges so that we don't try to hold a value live across that edge.

Thus the insertion point will tend to be the normal edge of a block that 
ends with a call to a potentially throwing function.

Inserting on the edge also significantly simplifies handling of 
conditional branches ;-)

Jeff

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 21:40               ` Jeff Law
@ 2023-07-26 22:21                 ` 钟居哲
  2023-07-26 22:46                   ` Jeff Law
  0 siblings, 1 reply; 49+ messages in thread
From: 钟居哲 @ 2023-07-26 22:21 UTC (permalink / raw)
  To: Jeff Law, rdapp.gcc, kito.cheng, pan2.li; +Cc: gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 2508 bytes --]

Hi, Jeff.

insert_insn_end_basic_block is to handle this following case:

bb 1:
...
CALL.---->BB_END of bb 
bb 2:
vfadd rne

You can see there is no instructions after CALL.

So you we use insert_insn_end_basic_block insert a "frrm" at the end of the bb 1.

I know typically it's better to insert a edge between bb 1 and bb 2, then put "frrm" in that edgen.
However, it causes ICE.

If we really need to follow this approach, it seems that we need to modify the "mode_sw" PASS?
Currently, we are avoiding changing the codes of PASS.

Thanks.


juzhe.zhong@rivai.ai
 
From: Jeff Law
Date: 2023-07-27 05:40
To: Robin Dapp; Kito Cheng; Li, Pan2
CC: gcc-patches@gcc.gnu.org; juzhe.zhong@rivai.ai; Wang, Yanzhang
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
 
 
On 7/26/23 07:08, Robin Dapp via Gcc-patches wrote:
> So after thinking about it again - I'm still not really sure
> I like treating every function as essentially an fesetround.
> There is a reason why fesetround is special.  Does LLVM behave
> the same way?
> 
> But supposing we really, really want it and assuming there's consensus:
> 
> +  start_sequence ();
> +  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
> +  rtx_insn *backup_insn = get_insns ();
> +  end_sequence ();
> 
> A comment here would be nice why we need a sequence for a single
> instruction.  I'm not fully aware what insert_insn_end_basic_block
> does but won't a
> 
>    rtx_insn *last = BB_END (bb);
>    emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);
> 
> suffice?  One way or another need these kinds of non-local
> constructs here don't seem entirely rock solid.
Typically an LCM algorithm needs to insert on edges rather than at the 
end of blocks -- this is particularly important to preserve its property 
that on no path through the CFG can we have more evaluations of the 
expression after PRE/LCM than before PRE/LCM.
 
The other thing edge insertions do is simplify the abnormal critical 
edge problems.  I'd have to dig into the precise details, but in the 
generic PRE/LCM code we clobber the available expressions on critical 
edges so that we don't try to hold a value live across that edge.
 
Thus the insertion point will tend to be the normal edge of a block that 
ends with a call to a potentially throwing function.
 
Inserting on the edge also significantly simplifies handling of 
conditional branches ;-)
 
Jeff
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 22:21                 ` 钟居哲
@ 2023-07-26 22:46                   ` Jeff Law
  2023-07-26 22:56                     ` 钟居哲
  0 siblings, 1 reply; 49+ messages in thread
From: Jeff Law @ 2023-07-26 22:46 UTC (permalink / raw)
  To: 钟居哲, rdapp.gcc, kito.cheng, pan2.li
  Cc: gcc-patches, yanzhang.wang



On 7/26/23 16:21, 钟居哲 wrote:
> Hi, Jeff.
> 
> insert_insn_end_basic_block is to handle this following case:
> 
> bb 1:
> ...
> CALL.---->BB_END of bb
> bb 2:
> vfadd rne
> 
> You can see there is no instructions after CALL.
> 
> So you we use insert_insn_end_basic_block insert a "frrm" at the end of 
> the bb 1.
> 
> I know typically it's better to insert a edge between bb 1 and bb 2, 
> then put "frrm" in that edgen.
> However, it causes ICE.
We'd need to know the reason for the ICE.

> 
> If we really need to follow this approach, it seems that we need to 
> modify the "mode_sw" PASS?
> Currently, we are avoiding changing the codes of PASS.
Generally wise, but sometimes we do need to change generic bits.  Let's 
dive a bit into this.

We have more freedom here to loosen the profitability constraints since 
its a target specific pass, but let's at least understand the what's 
going on with the ICE, then make some decisions about the best way forward.

jeff

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 22:46                   ` Jeff Law
@ 2023-07-26 22:56                     ` 钟居哲
  2023-07-27  1:38                       ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: 钟居哲 @ 2023-07-26 22:56 UTC (permalink / raw)
  To: Jeff Law, rdapp.gcc, kito.cheng, pan2.li; +Cc: gcc-patches, yanzhang.wang

[-- Attachment #1: Type: text/plain, Size: 1822 bytes --]

Thanks Jeff.

Hi, Pan:
Plz try (insert edge and put 'frrm' on that edge) instead of insert end of block to see whether it works 
(I have tried onece but I don't remember what happens).

Try that with following codes:
edge eg;
edge_iterator ei;
FOR_EACH_EDGE (eg, ei, bb->succs)
{
start_sequence ();
   emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
   rtx_insn *backup_insn = get_insns ();
end_sequence ();
insert_insn_on_edge (backup_insn, eg);
}

to see how's going.

Not sure whether it is correct, Jeff could comments on that.

Thanks.


juzhe.zhong@rivai.ai
 
From: Jeff Law
Date: 2023-07-27 06:46
To: 钟居哲; rdapp.gcc; kito.cheng; pan2.li
CC: gcc-patches; yanzhang.wang
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
 
 
On 7/26/23 16:21, 钟居哲 wrote:
> Hi, Jeff.
> 
> insert_insn_end_basic_block is to handle this following case:
> 
> bb 1:
> ...
> CALL.---->BB_END of bb
> bb 2:
> vfadd rne
> 
> You can see there is no instructions after CALL.
> 
> So you we use insert_insn_end_basic_block insert a "frrm" at the end of 
> the bb 1.
> 
> I know typically it's better to insert a edge between bb 1 and bb 2, 
> then put "frrm" in that edgen.
> However, it causes ICE.
We'd need to know the reason for the ICE.
 
> 
> If we really need to follow this approach, it seems that we need to 
> modify the "mode_sw" PASS?
> Currently, we are avoiding changing the codes of PASS.
Generally wise, but sometimes we do need to change generic bits.  Let's 
dive a bit into this.
 
We have more freedom here to loosen the profitability constraints since 
its a target specific pass, but let's at least understand the what's 
going on with the ICE, then make some decisions about the best way forward.
 
jeff
 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 22:56                     ` 钟居哲
@ 2023-07-27  1:38                       ` Li, Pan2
  2023-07-27  8:19                         ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-27  1:38 UTC (permalink / raw)
  To: 钟居哲, Jeff Law, rdapp.gcc, kito.cheng
  Cc: gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 3106 bytes --]

Thanks Juzhe and Jeff for suggestion. The approach like emit_insn_before_noloc will result in below ICE here.

../../../.././gcc/libstdc++-v3/libsupc++/new_opant.cc:42:1: error: flow control insn inside a basic block.
../../../.././gcc/libstdc++-v3/libsupc++/new_opant.cc:42:1: internal compiler error: in rtl_verify_bb_insns, at cfgrtl.cc:2796

Then I tried below approach but also have ICE like below.

../../../.././gcc/libstdc++-v3/libsupc++/eh_personality.cc:805:1: internal compiler error: in insert_insn_on_edge, at cfgrtl.cc:1976.

The insert_insn_end_basic_block have some special handling when end bb is CALL.

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai>
Sent: Thursday, July 27, 2023 6:56 AM
To: Jeff Law <jeffreyalaw@gmail.com>; rdapp.gcc <rdapp.gcc@gmail.com>; kito.cheng <kito.cheng@sifive.com>; Li, Pan2 <pan2.li@intel.com>
Cc: gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

Thanks Jeff.

Hi, Pan:
Plz try (insert edge and put 'frrm' on that edge) instead of insert end of block to see whether it works
(I have tried onece but I don't remember what happens).

Try that with following codes:
edge eg;
edge_iterator ei;
FOR_EACH_EDGE (eg, ei, bb->succs)
{
  start_sequence ();
   emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
   rtx_insn *backup_insn = get_insns ();
  end_sequence ();
  insert_insn_on_edge (backup_insn, eg);
}

to see how's going.

Not sure whether it is correct, Jeff could comments on that.

Thanks.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Jeff Law<mailto:jeffreyalaw@gmail.com>
Date: 2023-07-27 06:46
To: 钟居哲<mailto:juzhe.zhong@rivai.ai>; rdapp.gcc<mailto:rdapp.gcc@gmail.com>; kito.cheng<mailto:kito.cheng@sifive.com>; pan2.li<mailto:pan2.li@intel.com>
CC: gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding


On 7/26/23 16:21, 钟居哲 wrote:
> Hi, Jeff.
>
> insert_insn_end_basic_block is to handle this following case:
>
> bb 1:
> ...
> CALL.---->BB_END of bb
> bb 2:
> vfadd rne
>
> You can see there is no instructions after CALL.
>
> So you we use insert_insn_end_basic_block insert a "frrm" at the end of
> the bb 1.
>
> I know typically it's better to insert a edge between bb 1 and bb 2,
> then put "frrm" in that edgen.
> However, it causes ICE.
We'd need to know the reason for the ICE.

>
> If we really need to follow this approach, it seems that we need to
> modify the "mode_sw" PASS?
> Currently, we are avoiding changing the codes of PASS.
Generally wise, but sometimes we do need to change generic bits.  Let's
dive a bit into this.

We have more freedom here to loosen the profitability constraints since
its a target specific pass, but let's at least understand the what's
going on with the ICE, then make some decisions about the best way forward.

jeff


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-26 13:08             ` Robin Dapp
  2023-07-26 21:40               ` Jeff Law
@ 2023-07-27  2:09               ` Li, Pan2
  2023-07-27  7:25                 ` Robin Dapp
  1 sibling, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-27  2:09 UTC (permalink / raw)
  To: Robin Dapp, Kito Cheng; +Cc: gcc-patches, juzhe.zhong, Wang, Yanzhang

 > rtx_insn *last = BB_END (bb);
 > emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);

The frrmsi insn need to be placed after CALL (aka last), then I bet here we should use emit_insn_after_noloc.
Unfortunately, it will have ICE like below. I am still investigating the suggestion from Jeff for this.

../../../.././gcc/libstdc++-v3/libsupc++/vec.cc:292:3: error: flow control insn inside a basic block.
../../../.././gcc/libstdc++-v3/libsupc++/vec.cc:292:3: internal compiler error: in rtl_verify_bb_insns, at cfgrtl.cc:2796

> Why do we appear to return a different mode here?  We already request
> FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
> we do not change the mode so we could just always return the incoming
> mode?

Because we need to emit 2 insn when meet a call.
One before the call, we must return DYN_CALL when needed, then the emit part is able to know the mode switch to DYN_CALL and restore.
One after the call, we must return DYN_CALL when after, then the next insn emit part is able to know the prev_mode is DYN_CALL and backup.

> frm_unknown_dynamic_p checks CALL_P which has already been checked
> before.  It returns FRM_MODE_DYN instead of FRM_MODE_DYN_CALL, though.

Thanks for pointing this out, and will cleanup in PATCH v8.

> Here and in similar cases, NEW_FRM is not exactly telling.  Can't we
> use "should be " and then

Thanks and will fix in v8.

> NON -> FRM.

Thanks and will fix in v8.

> This causes a FAIL for me.  I believe the scan directives are off by one.

Will double check about it for both rv32/rv64 tests.

Pan

-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Wednesday, July 26, 2023 9:08 PM
To: Kito Cheng <kito.cheng@sifive.com>; Li, Pan2 <pan2.li@intel.com>
Cc: rdapp.gcc@gmail.com; gcc-patches@gcc.gnu.org; juzhe.zhong@rivai.ai; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

So after thinking about it again - I'm still not really sure
I like treating every function as essentially an fesetround.
There is a reason why fesetround is special.  Does LLVM behave
the same way?

But supposing we really, really want it and assuming there's consensus:

+  start_sequence ();
+  emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+  rtx_insn *backup_insn = get_insns ();
+  end_sequence ();

A comment here would be nice why we need a sequence for a single
instruction.  I'm not fully aware what insert_insn_end_basic_block
does but won't a

  rtx_insn *last = BB_END (bb);
  emit_insn_before_noloc (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)), last, bb);

suffice?  One way or another need these kinds of non-local
constructs here don't seem entirely rock solid.

@@ -7843,6 +7946,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return FRM_MODE_DYN_CALL;

Why do we appear to return a different mode here?  We already request
FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
we do not change the mode so we could just always return the incoming
mode?

This is not part of this patch but related and originally I assumed
that we would untangle things after the initial patch, so:

   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;

frm_unknown_dynamic_p checks CALL_P which has already been checked
before.  It returns FRM_MODE_DYN instead of FRM_MODE_DYN_CALL, though.

Apart from that, the function is called unknown_dynamic but we check
for a SET of FRM?  Wouldn't something that sets FRM rather be a "static"
rounding-mode instruction? (using the "static" wording from before)

Then we also still have

  if (reg_mentioned_p (gen_rtx_REG (SImode, FRM_REGNUM), PATTERN (insn)))
    return get_attr_frm_mode (insn);

from before.  Isn't that pretty much the same?


+  assert_equal (NEW_FRM, get_frm (),
+               "The value of frm register should be NEW_FRM.");

Here and in similar cases, NEW_FRM is not exactly telling.  Can't we
use "should be " and then 

+      fprintf (stdout, "%s %d, but get %d != %d\n", message, a, b);

or similar?

+           will do the mode switch from MODE_CALL to MODE_NON_NONE natively.

NON -> FRM.

+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"

This causes a FAIL for me.  I believe the scan directives are off by one.

Are you going to do asm directives in a separate patch?
Similar to vxrm_unknown_p we could just check for one here
and handle it similarly to a call.  Would need some more tests, though.

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-27  2:09               ` Li, Pan2
@ 2023-07-27  7:25                 ` Robin Dapp
  2023-07-27  8:26                   ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Robin Dapp @ 2023-07-27  7:25 UTC (permalink / raw)
  To: Li, Pan2, Kito Cheng; +Cc: rdapp.gcc, gcc-patches, juzhe.zhong, Wang, Yanzhang

>> Why do we appear to return a different mode here?  We already request
>> FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
>> we do not change the mode so we could just always return the incoming
>> mode?
> 
> Because we need to emit 2 insn when meet a call. One before the call,
> we must return DYN_CALL when needed, then the emit part is able to
> know the mode switch to DYN_CALL and restore. One after the call, we
> must return DYN_CALL when after, then the next insn emit part is able
> to know the prev_mode is DYN_CALL and backup.

My question was not about DYN_CALL in general but rather - mode switching
will switch to the moded requested by mode_needed.  The mode_after hook
allows to specify if we want to change a mode afterwards but it doesn't look
like we every do.

mode_needed -> CALL_P -> DYN_CALL
mode_sw switches to DYN_CALL
mode_after -> DYN_CALL

so there is no need to appear to change the mode but we can just pass it
through, possibly same for DYN?  Or to put it differently, can we start
with "return mode" in riscv_frm_mode_after and then only add the condition
that are strictly necessary?

I also noticed an unused bb in riscv_frm_adjust_mode_after_call that
we want to remove.  Also, if (mode != prev_mode) in mode_set is unnecessary
as mode_sw already checks that.

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-27  1:38                       ` Li, Pan2
@ 2023-07-27  8:19                         ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-27  8:19 UTC (permalink / raw)
  To: 钟居哲, Jeff Law, rdapp.gcc, kito.cheng
  Cc: gcc-patches, Wang, Yanzhang

[-- Attachment #1: Type: text/plain, Size: 4210 bytes --]

> ../../../.././gcc/libstdc++-v3/libsupc++/eh_personality.cc:805:1: internal compiler error: in insert_insn_on_edge, at cfgrtl.cc:1976.

This error comes from assert of insert_insn_on_edge, the edge cannot be ABNORMAL and CRITIAL.

Thus, I try to filter out it like gcse.cc:2168 do like below, but still hit some assert like regno < FIRST_PSEDUO_REGISTER in find_oldest_value_reg.

If (eg->flags & EDGE_ABNORMAL)
  Insert_insn_end_basic_block
else
  insert_insn_on_edge

will continue to figure it out.

Pan

From: Li, Pan2
Sent: Thursday, July 27, 2023 9:38 AM
To: 钟居哲 <juzhe.zhong@rivai.ai>; Jeff Law <jeffreyalaw@gmail.com>; rdapp.gcc <rdapp.gcc@gmail.com>; kito.cheng <kito.cheng@sifive.com>
Cc: gcc-patches <gcc-patches@gcc.gnu.org>; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: RE: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

Thanks Juzhe and Jeff for suggestion. The approach like emit_insn_before_noloc will result in below ICE here.

../../../.././gcc/libstdc++-v3/libsupc++/new_opant.cc:42:1: error: flow control insn inside a basic block.
../../../.././gcc/libstdc++-v3/libsupc++/new_opant.cc:42:1: internal compiler error: in rtl_verify_bb_insns, at cfgrtl.cc:2796

Then I tried below approach but also have ICE like below.

../../../.././gcc/libstdc++-v3/libsupc++/eh_personality.cc:805:1: internal compiler error: in insert_insn_on_edge, at cfgrtl.cc:1976.

The insert_insn_end_basic_block have some special handling when end bb is CALL.

Pan

From: 钟居哲 <juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>>
Sent: Thursday, July 27, 2023 6:56 AM
To: Jeff Law <jeffreyalaw@gmail.com<mailto:jeffreyalaw@gmail.com>>; rdapp.gcc <rdapp.gcc@gmail.com<mailto:rdapp.gcc@gmail.com>>; kito.cheng <kito.cheng@sifive.com<mailto:kito.cheng@sifive.com>>; Li, Pan2 <pan2.li@intel.com<mailto:pan2.li@intel.com>>
Cc: gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>>; Wang, Yanzhang <yanzhang.wang@intel.com<mailto:yanzhang.wang@intel.com>>
Subject: Re: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

Thanks Jeff.

Hi, Pan:
Plz try (insert edge and put 'frrm' on that edge) instead of insert end of block to see whether it works
(I have tried onece but I don't remember what happens).

Try that with following codes:
edge eg;
edge_iterator ei;
FOR_EACH_EDGE (eg, ei, bb->succs)
{
  start_sequence ();
   emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
   rtx_insn *backup_insn = get_insns ();
  end_sequence ();
  insert_insn_on_edge (backup_insn, eg);
}

to see how's going.

Not sure whether it is correct, Jeff could comments on that.

Thanks.
________________________________
juzhe.zhong@rivai.ai<mailto:juzhe.zhong@rivai.ai>

From: Jeff Law<mailto:jeffreyalaw@gmail.com>
Date: 2023-07-27 06:46
To: 钟居哲<mailto:juzhe.zhong@rivai.ai>; rdapp.gcc<mailto:rdapp.gcc@gmail.com>; kito.cheng<mailto:kito.cheng@sifive.com>; pan2.li<mailto:pan2.li@intel.com>
CC: gcc-patches<mailto:gcc-patches@gcc.gnu.org>; yanzhang.wang<mailto:yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding


On 7/26/23 16:21, 钟居哲 wrote:
> Hi, Jeff.
>
> insert_insn_end_basic_block is to handle this following case:
>
> bb 1:
> ...
> CALL.---->BB_END of bb
> bb 2:
> vfadd rne
>
> You can see there is no instructions after CALL.
>
> So you we use insert_insn_end_basic_block insert a "frrm" at the end of
> the bb 1.
>
> I know typically it's better to insert a edge between bb 1 and bb 2,
> then put "frrm" in that edgen.
> However, it causes ICE.
We'd need to know the reason for the ICE.

>
> If we really need to follow this approach, it seems that we need to
> modify the "mode_sw" PASS?
> Currently, we are avoiding changing the codes of PASS.
Generally wise, but sometimes we do need to change generic bits.  Let's
dive a bit into this.

We have more freedom here to loosen the profitability constraints since
its a target specific pass, but let's at least understand the what's
going on with the ICE, then make some decisions about the best way forward.

jeff


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-27  7:25                 ` Robin Dapp
@ 2023-07-27  8:26                   ` Li, Pan2
  2023-07-27  8:41                     ` Robin Dapp
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-27  8:26 UTC (permalink / raw)
  To: Robin Dapp, Kito Cheng; +Cc: gcc-patches, juzhe.zhong, Wang, Yanzhang

> so there is no need to appear to change the mode but we can just pass it
> through, possibly same for DYN?  Or to put it differently, can we start
> with "return mode" in riscv_frm_mode_after and then only add the condition
> that are strictly necessary?

I see, you mean at the beginning of frm_after, we can just return the incoming mode as is?

If (CALL_P (insn))
  return mode; // Given we aware the mode is DYN_CALL already.

> I also noticed an unused bb in riscv_frm_adjust_mode_after_call that
> we want to remove.  Also, if (mode != prev_mode) in mode_set is unnecessary
> as mode_sw already checks that.

Thank and will cleanup this in v8. AFAIK, the optimize_mode_switching only check ptr->mode != no_mode before emit,
not sure if I missed something.

Pan


-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Thursday, July 27, 2023 3:26 PM
To: Li, Pan2 <pan2.li@intel.com>; Kito Cheng <kito.cheng@sifive.com>
Cc: rdapp.gcc@gmail.com; gcc-patches@gcc.gnu.org; juzhe.zhong@rivai.ai; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding

>> Why do we appear to return a different mode here?  We already request
>> FRM_MODE_DYN_CALL in mode_needed.  It looks like in the whole function
>> we do not change the mode so we could just always return the incoming
>> mode?
> 
> Because we need to emit 2 insn when meet a call. One before the call,
> we must return DYN_CALL when needed, then the emit part is able to
> know the mode switch to DYN_CALL and restore. One after the call, we
> must return DYN_CALL when after, then the next insn emit part is able
> to know the prev_mode is DYN_CALL and backup.

My question was not about DYN_CALL in general but rather - mode switching
will switch to the moded requested by mode_needed.  The mode_after hook
allows to specify if we want to change a mode afterwards but it doesn't look
like we every do.

mode_needed -> CALL_P -> DYN_CALL
mode_sw switches to DYN_CALL
mode_after -> DYN_CALL

so there is no need to appear to change the mode but we can just pass it
through, possibly same for DYN?  Or to put it differently, can we start
with "return mode" in riscv_frm_mode_after and then only add the condition
that are strictly necessary?

I also noticed an unused bb in riscv_frm_adjust_mode_after_call that
we want to remove.  Also, if (mode != prev_mode) in mode_set is unnecessary
as mode_sw already checks that.

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-27  8:26                   ` Li, Pan2
@ 2023-07-27  8:41                     ` Robin Dapp
  2023-07-27 10:27                       ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Robin Dapp @ 2023-07-27  8:41 UTC (permalink / raw)
  To: Li, Pan2, Kito Cheng; +Cc: rdapp.gcc, gcc-patches, juzhe.zhong, Wang, Yanzhang


> I see, you mean at the beginning of frm_after, we can just return the incoming mode as is?
> 
> If (CALL_P (insn))
>   return mode; // Given we aware the mode is DYN_CALL already.

Yes, potentially similar for all the other ifs but I didn't check
all of them.

> Thank and will cleanup this in v8. AFAIK, the optimize_mode_switching
> only check ptr->mode != no_mode before emit, not sure if I missed
> something.

 if (mode != no_mode && mode != last_mode)
    {

Shouldn't this cover us?  I didn't run the testsuite or so but it looks
like it.

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-27  8:41                     ` Robin Dapp
@ 2023-07-27 10:27                       ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-07-27 10:27 UTC (permalink / raw)
  To: Robin Dapp, Kito Cheng; +Cc: gcc-patches, juzhe.zhong, Wang, Yanzhang

> Yes, potentially similar for all the other ifs but I didn't check
> all of them.

Thanks and sure thing, will clean up this in v8.

> if (mode != no_mode && mode != last_mode)
>  {

This comes from after not the emit part as I mentioned, I am not quit familiar with this part, as well as if the after part will effect on emit or not.

But I would like to say the if (prev_mode != mode) can be consider as defensive code from the Backend (aka the consumer of the mode switching framework).
I think it is not good idea to do something based on the mode switching framework implementation details.

As a hook (interface) provided by mode switch framework, aka RISC-V backend as the user of mode switching framework. The implementation of hook in RISC-V 
Should only follow the sematics, and get rid of any implementation of the framework itself. Or we may have many implicit dependency across kinds of 
components, and may shoot your own leg one day.

Sorry for disturbing and share some of my two cents. 

Pan

-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Thursday, July 27, 2023 4:42 PM
To: Li, Pan2 <pan2.li@intel.com>; Kito Cheng <kito.cheng@sifive.com>
Cc: rdapp.gcc@gmail.com; gcc-patches@gcc.gnu.org; juzhe.zhong@rivai.ai; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v7] RISC-V: Support CALL for RVV floating-point dynamic rounding


> I see, you mean at the beginning of frm_after, we can just return the incoming mode as is?
> 
> If (CALL_P (insn))
>   return mode; // Given we aware the mode is DYN_CALL already.

Yes, potentially similar for all the other ifs but I didn't check
all of them.

> Thank and will cleanup this in v8. AFAIK, the optimize_mode_switching
> only check ptr->mode != no_mode before emit, not sure if I missed
> something.

 if (mode != no_mode && mode != last_mode)
    {

Shouldn't this cover us?  I didn't run the testsuite or so but it looks
like it.

Regards
 Robin


^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
                   ` (4 preceding siblings ...)
  2023-07-25  5:51 ` [PATCH v7] " pan2.li
@ 2023-07-28  1:15 ` pan2.li
  2023-07-28 10:05   ` Robin Dapp
  5 siblings, 1 reply; 49+ messages in thread
From: pan2.li @ 2023-07-28  1:15 UTC (permalink / raw)
  To: gcc-patches; +Cc: juzhe.zhong, kito.cheng, pan2.li, yanzhang.wang, rdapp.gcc

From: Pan Li <pan2.li@intel.com>

Update in PATCH v8:

1. Emit non-abnormal backup insn to edge.
2. Fix _after return when call.
3. Refine some run tests.
4. Cleanup code.

Original commit logs:

In basic dynamic rounding mode, we simply ignore call instructions and
we would like to take care of call in this PATCH.

During the call, the frm may be updated or keep as is. Thus, we must
make sure at least 2 things.

1. The static frm before call should not pollute the frm value in call.
2. The updated frm value in call should be sticky after call completed.

We will perfrom some steps to make above happen.

1. Mark call instruction with new mode DYN_CALL.
2. Mark the instruction after CALL from NONE to DYN.
3. When emit for a DYN_CALL, we will restore the frm value.
4. When emit from a DYN_CALL, we will backup the frm value.

Let's take a flow for this.

           +-------------+
           | Entry (DYN) | <- frrm a5
           +-------------+
          /               \
    +-------+             +-----------+
    | VFADD |             | VFADD RTZ |  <- fsrmi 1(RTZ)
    +-------+             +-----------+
          |                    |
    +-------+             +-----------+
    | CALL  |             | CALL      |  <- fsrm a5
    +-------+             +-----------+
          |                       |
+-----------+                 +-------+
| SHIFT     | <- frrm a5      | VFADD |  <- frrm a5
+-----------+                 +-------+
          |                  /
+-----------+               /
| VFADD RUP | <- fsrm1 3(RUP)
+-----------+             /
           \             /
            +-----------------+
            | Exit (DYN_EXIT) | <- fsrm a5
            +-----------------+

When call is the last insn of one bb, we take care of it when needed
for each insn by inserting one frm backup (frrm) insn to the end of
the current bb.

Signed-off-by: Pan Li <pan2.li@intel.com>
Co-Authored-By: Juzhe-Zhong <juzhe.zhong@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv.cc (DYNAMIC_FRM_RTL): New macro.
	(STATIC_FRM_P): Ditto.
	(struct mode_switching_info): New struct for mode switching.
	(struct machine_function): Add new field mode switching.
	(riscv_emit_frm_mode_set): Add DYN_CALL emit.
	(riscv_frm_adjust_mode_after_call): New function for call mode.
	(riscv_frm_emit_after_call_in_bb_end): New function for emit
	insn when call as the end of bb.
	(riscv_frm_mode_needed): New function for frm mode needed.
	(frm_unknown_dynamic_p): Remove call check.
	(riscv_mode_needed): Extrac function for frm.
	(riscv_frm_mode_after): Add DYN_CALL after.
	(riscv_mode_entry): Remove backup rtl initialization.
	* config/riscv/vector.md (frm_mode): Add dyn_call.
	(fsrmsi_restore_exit): Rename to _volatile.
	(fsrmsi_restore_volatile): Likewise.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/base/float-point-frm-insert-7.c: Adjust
	test cases.
	* gcc.target/riscv/rvv/base/float-point-frm-run-1.c: Ditto.
	* gcc.target/riscv/rvv/base/float-point-frm-run-2.c: Ditto.
	* gcc.target/riscv/rvv/base/float-point-frm-run-3.c: Ditto.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c: New test.
	* gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-4.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run-5.c: New test.
	* gcc.target/riscv/rvv/base/float-point-frm-run.h: New test.
---
 gcc/config/riscv/riscv.cc                     | 144 +++++++++++++++---
 gcc/config/riscv/vector.md                    |   4 +-
 .../rvv/base/float-point-dynamic-frm-33.c     |  31 ++++
 .../rvv/base/float-point-dynamic-frm-34.c     |  32 ++++
 .../rvv/base/float-point-dynamic-frm-35.c     |  32 ++++
 .../rvv/base/float-point-dynamic-frm-36.c     |  29 ++++
 .../rvv/base/float-point-dynamic-frm-37.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-38.c     |  34 +++++
 .../rvv/base/float-point-dynamic-frm-39.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-40.c     |  34 +++++
 .../rvv/base/float-point-dynamic-frm-41.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-42.c     |  37 +++++
 .../rvv/base/float-point-dynamic-frm-43.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-44.c     |  40 +++++
 .../rvv/base/float-point-dynamic-frm-45.c     |  35 +++++
 .../rvv/base/float-point-dynamic-frm-46.c     |  35 +++++
 .../rvv/base/float-point-dynamic-frm-47.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-48.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-49.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-50.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-51.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-52.c     |  36 +++++
 .../rvv/base/float-point-dynamic-frm-53.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-54.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-55.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-56.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-57.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-58.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-59.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-60.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-61.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-62.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-63.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-64.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-65.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-66.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-67.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-68.c     |  38 +++++
 .../rvv/base/float-point-dynamic-frm-69.c     |  31 ++++
 .../rvv/base/float-point-dynamic-frm-70.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-71.c     |  28 ++++
 .../rvv/base/float-point-dynamic-frm-72.c     |  33 ++++
 .../rvv/base/float-point-dynamic-frm-73.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-74.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-75.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-76.c     |  39 +++++
 .../rvv/base/float-point-dynamic-frm-77.c     |  20 +++
 .../riscv/rvv/base/float-point-frm-insert-7.c |   5 +-
 .../riscv/rvv/base/float-point-frm-run-1.c    |  50 +-----
 .../riscv/rvv/base/float-point-frm-run-2.c    |  40 +----
 .../riscv/rvv/base/float-point-frm-run-3.c    |  40 +----
 .../riscv/rvv/base/float-point-frm-run-4.c    |  47 ++++++
 .../riscv/rvv/base/float-point-frm-run-5.c    |  47 ++++++
 .../riscv/rvv/base/float-point-frm-run.h      |  40 +++++
 54 files changed, 1884 insertions(+), 139 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run.h

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 332fa720f01..13f8d1c9a79 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-expr.h"
 #include "tree-vectorizer.h"
+#include "gcse.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -90,6 +91,12 @@ along with GCC; see the file COPYING3.  If not see
 /* True if bit BIT is set in VALUE.  */
 #define BITSET_P(VALUE, BIT) (((VALUE) & (1ULL << (BIT))) != 0)
 
+/* Extract the backup dynamic frm rtl.  */
+#define DYNAMIC_FRM_RTL(c) ((c)->machine->mode_sw_info.dynamic_frm)
+
+/* True the mode switching has static frm, or false.  */
+#define STATIC_FRM_P(c) ((c)->machine->mode_sw_info.static_frm_p)
+
 /* Information about a function's frame layout.  */
 struct GTY(())  riscv_frame_info {
   /* The size of the frame in bytes.  */
@@ -125,6 +132,22 @@ enum riscv_privilege_levels {
   UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
+struct GTY(()) mode_switching_info {
+  /* The RTL variable which stores the dynamic FRM value.  We always use this
+     RTX to restore dynamic FRM rounding mode in mode switching.  */
+  rtx dynamic_frm;
+
+  /* The boolean variables indicates there is at least one static rounding
+     mode instruction in the function or not.  */
+  bool static_frm_p;
+
+  mode_switching_info ()
+    {
+      dynamic_frm = NULL_RTX;
+      static_frm_p = false;
+    }
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -148,9 +171,8 @@ struct GTY(())  machine_function {
      not be considered by the prologue and epilogue.  */
   bool reg_is_wrapped_separately[FIRST_PSEUDO_REGISTER];
 
-  /* The RTL variable which stores the dynamic FRM value.  We always use this
-     RTX to restore dynamic FRM rounding mode in mode switching.  */
-  rtx dynamic_frm;
+  /* The mode swithching information for the FRM rounding modes.  */
+  struct mode_switching_info mode_sw_info;
 };
 
 /* Information about a single argument.  */
@@ -7709,9 +7731,13 @@ riscv_static_frm_mode_p (int mode)
 static void
 riscv_emit_frm_mode_set (int mode, int prev_mode)
 {
+  rtx backup_reg = DYNAMIC_FRM_RTL (cfun);
+
+  if (prev_mode == FRM_MODE_DYN_CALL)
+    emit_insn (gen_frrmsi (backup_reg)); /* Backup frm when DYN_CALL.  */
+
   if (mode != prev_mode)
     {
-      rtx backup_reg = cfun->machine->dynamic_frm;
       /* TODO: By design, FRM_MODE_xxx used by mode switch which is
 	 different from the FRM value like FRM_RTZ defined in
 	 riscv-protos.h.  When mode switching we actually need a conversion
@@ -7721,10 +7747,14 @@ riscv_emit_frm_mode_set (int mode, int prev_mode)
 	 and then we leverage this assumption when emit.  */
       rtx frm = gen_int_mode (mode, SImode);
 
-      if (mode == FRM_MODE_DYN_EXIT && prev_mode != FRM_MODE_DYN)
+      if (mode == FRM_MODE_DYN_CALL && prev_mode != FRM_MODE_DYN)
 	/* No need to emit when prev mode is DYN already.  */
-	emit_insn (gen_fsrmsi_restore_exit (backup_reg));
-      else if (mode == FRM_MODE_DYN)
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN_EXIT && STATIC_FRM_P (cfun)
+	&& prev_mode != FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
+	/* No need to emit when prev mode is DYN or DYN_CALL already.  */
+	emit_insn (gen_fsrmsi_restore_volatile (backup_reg));
+      else if (mode == FRM_MODE_DYN && prev_mode != FRM_MODE_DYN_CALL)
 	/* Restore frm value from backup when switch to DYN mode.  */
 	emit_insn (gen_fsrmsi_restore (backup_reg));
       else if (riscv_static_frm_mode_p (mode))
@@ -7753,6 +7783,88 @@ riscv_emit_mode_set (int entity, int mode, int prev_mode,
     }
 }
 
+/* Adjust the FRM_MODE_NONE insn after a call to FRM_MODE_DYN for the
+   underlying emit.  */
+
+static int
+riscv_frm_adjust_mode_after_call (rtx_insn *cur_insn, int mode)
+{
+  rtx_insn *insn = prev_nonnote_nondebug_insn_bb (cur_insn);
+
+  if (insn && CALL_P (insn))
+    return FRM_MODE_DYN;
+
+  return mode;
+}
+
+/* Insert the backup frm insn to the end of the bb if and only if the call
+   is the last insn of this bb.  */
+
+static void
+riscv_frm_emit_after_bb_end (rtx_insn *cur_insn)
+{
+  edge eg;
+  edge_iterator eg_iterator;
+  basic_block bb = BLOCK_FOR_INSN (cur_insn);
+
+  FOR_EACH_EDGE (eg, eg_iterator, bb->succs)
+    {
+      start_sequence ();
+      emit_insn (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+      rtx_insn *backup_insn = get_insns ();
+      end_sequence ();
+
+      if (eg->flags & EDGE_ABNORMAL)
+	insert_insn_end_basic_block (backup_insn, bb);
+      else
+	insert_insn_on_edge (backup_insn, eg);
+    }
+
+  commit_edge_insertions ();
+}
+
+/* Return mode that frm must be switched into
+   prior to the execution of insn.  */
+
+static int
+riscv_frm_mode_needed (rtx_insn *cur_insn, int code)
+{
+  if (!DYNAMIC_FRM_RTL(cfun))
+    {
+      /* The dynamic frm will be initialized only onece during cfun.  */
+      DYNAMIC_FRM_RTL (cfun) = gen_reg_rtx (SImode);
+      emit_insn_at_entry (gen_frrmsi (DYNAMIC_FRM_RTL (cfun)));
+    }
+
+  if (CALL_P (cur_insn))
+    {
+      rtx_insn *insn = next_nonnote_nondebug_insn_bb (cur_insn);
+
+      if (!insn)
+	riscv_frm_emit_after_bb_end (cur_insn);
+
+      return FRM_MODE_DYN_CALL;
+    }
+
+  int mode = code >= 0 ? get_attr_frm_mode (cur_insn) : FRM_MODE_NONE;
+
+  if (mode == FRM_MODE_NONE)
+      /* After meet a call, we need to backup the frm because it may be
+	 updated during the call. Here, for each insn, we will check if
+	 the previous insn is a call or not. When previous insn is call,
+	 there will be 2 cases for the emit mode set.
+
+	 1. Current insn is not MODE_NONE, then the mode switch framework
+	    will do the mode switch from MODE_CALL to MODE_NONE natively.
+	 2. Current insn is MODE_NONE, we need to adjust the MODE_NONE to
+	    the MODE_DYN, and leave the mode switch itself to perform
+	    the emit mode set.
+       */
+    mode = riscv_frm_adjust_mode_after_call (cur_insn, mode);
+
+  return mode;
+}
+
 /* Return mode that entity must be switched into
    prior to the execution of insn.  */
 
@@ -7766,7 +7878,7 @@ riscv_mode_needed (int entity, rtx_insn *insn)
     case RISCV_VXRM:
       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;
+      return riscv_frm_mode_needed (insn, code);
     default:
       gcc_unreachable ();
     }
@@ -7813,11 +7925,6 @@ frm_unknown_dynamic_p (rtx_insn *insn)
   if (reg_set_p (gen_rtx_REG (SImode, FRM_REGNUM), insn))
     return true;
 
-  /* A CALL function may contain an instruction that modifies the FRM,
-     return true in this situation.  */
-  if (CALL_P (insn))
-    return true;
-
   return false;
 }
 
@@ -7843,6 +7950,11 @@ riscv_vxrm_mode_after (rtx_insn *insn, int mode)
 static int
 riscv_frm_mode_after (rtx_insn *insn, int mode)
 {
+  STATIC_FRM_P (cfun) = STATIC_FRM_P (cfun) || riscv_static_frm_mode_p (mode);
+
+  if (CALL_P (insn))
+    return mode;
+
   if (frm_unknown_dynamic_p (insn))
     return FRM_MODE_DYN;
 
@@ -7883,12 +7995,6 @@ riscv_mode_entry (int entity)
       return VXRM_MODE_NONE;
     case RISCV_FRM:
       {
-	if (!cfun->machine->dynamic_frm)
-	  {
-	    cfun->machine->dynamic_frm = gen_reg_rtx (SImode);
-	    emit_insn_at_entry (gen_frrmsi (cfun->machine->dynamic_frm));
-	  }
-
 	  /* According to RVV 1.0 spec, all vector floating-point operations use
 	     the dynamic rounding mode in the frm register.  Likewise in other
 	     similar places.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index f745888127c..05fd7600ba4 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -686,7 +686,7 @@ (define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
         (const_string "none")))
 
 ;; Defines rounding mode of an floating-point operation.
-(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,none"
+(define_attr "frm_mode" "rne,rtz,rdn,rup,rmm,dyn,dyn_exit,dyn_call,none"
   (cond [(eq_attr "type" "vfalu")
          (cond
 	   [(match_test "INTVAL (operands[9]) == riscv_vector::FRM_RNE")
@@ -813,7 +813,7 @@ (define_insn "fsrmsi_restore"
 ;; The volatile fsrmsi restore is used for the exit point for the
 ;; dynamic mode switching. It will generate one volatile fsrm a5
 ;; which won't be eliminated.
-(define_insn "fsrmsi_restore_exit"
+(define_insn "fsrmsi_restore_volatile"
   [(set (reg:SI FRM_REGNUM)
 	(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
 			    UNSPECV_FRM_RESTORE_EXIT))]
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
new file mode 100644
index 00000000000..4bd520ea2af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-33.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  vl = normalize_vl (vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
new file mode 100644
index 00000000000..6c7cf7ef69c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-34.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  vl = normalize_vl (vl);
+
+  return vl > 128 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
new file mode 100644
index 00000000000..b7f5a6919f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-35.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
new file mode 100644
index 00000000000..4485cea24d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-36.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (vl % 4 != 0)
+    vl = normalize_vl (vl);
+
+  return vl > 16 ? result : op2;
+}
+
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
new file mode 100644
index 00000000000..a1fca1a2a3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-37.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      if (i % 2 == 0)
+        result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      else
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
new file mode 100644
index 00000000000..8d59cae9a87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-38.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+      vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
new file mode 100644
index 00000000000..04c54877393
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-39.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      int count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (int i = 0; i < count; i++)
+    {
+      result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+      if (vl % 8 != 0)
+        vl = normalize_vl (vl);
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
new file mode 100644
index 00000000000..49cf52f739b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-40.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
new file mode 100644
index 00000000000..79ef55b2c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-41.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
new file mode 100644
index 00000000000..1123a93997e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-42.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
new file mode 100644
index 00000000000..2ea60ca47c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-43.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+  vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
new file mode 100644
index 00000000000..7486ed465c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-44.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+size_t __attribute__ ((noinline))
+normalize_vl (size_t vl)
+{
+  if (vl % 4 == 0)
+    return vl;
+
+  return ((vl / 4) + 1) * 4;
+}
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+
+  vl = normalize_vl (vl);
+
+  if (vl % 16 == 0)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+
+
+  if (vl % 7 != 0)
+    vl = normalize_vl (vl);
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
new file mode 100644
index 00000000000..3ceea105f6a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-45.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
new file mode 100644
index 00000000000..b990fb434f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-46.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	  vl = normalize_vl (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	  vl = normalize_vl (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
new file mode 100644
index 00000000000..994c86e93eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-47.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
new file mode 100644
index 00000000000..4cde923abc1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-48.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
new file mode 100644
index 00000000000..0b0a017cfd5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-49.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
new file mode 100644
index 00000000000..23f72664426
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-50.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
new file mode 100644
index 00000000000..8b564ca5f43
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-51.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
new file mode 100644
index 00000000000..b63f717b239
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-52.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
new file mode 100644
index 00000000000..647de39d66e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-53.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
new file mode 100644
index 00000000000..8c67d4bba81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-54.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
new file mode 100644
index 00000000000..61365103b40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-55.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
new file mode 100644
index 00000000000..e5a1c356a98
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-56.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
new file mode 100644
index 00000000000..7ac9c960e65
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-57.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
new file mode 100644
index 00000000000..c5f96bc45c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-58.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 4 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
new file mode 100644
index 00000000000..87d436ac146
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-59.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
new file mode 100644
index 00000000000..ad3a7f81a69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-60.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
new file mode 100644
index 00000000000..8748ca66b1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-61.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
new file mode 100644
index 00000000000..8fd97b50124
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-62.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
new file mode 100644
index 00000000000..58718c39279
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-63.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
new file mode 100644
index 00000000000..ad2d54510bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-64.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
new file mode 100644
index 00000000000..c15629d2134
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-65.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
new file mode 100644
index 00000000000..ea99831f31f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-66.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
new file mode 100644
index 00000000000..b8500303a21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-67.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 3 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
new file mode 100644
index 00000000000..1dbf6dba208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-68.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+extern size_t normalize_vl_2 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  for (unsigned i = 0; i < count; i++)
+    {
+      if (i % 3 == 0)
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 1, vl);
+	  vl = normalize_vl_1 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+	}
+      else
+	{
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+	  vl = normalize_vl_2 (vl);
+	  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 4, vl);
+	}
+    }
+
+  return result;
+}
+
+/* { 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 {frrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 4 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
new file mode 100644
index 00000000000..b08ab1ef605
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-69.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result;
+  vfloat32m1_t f32_res = op1;
+  vint32m1_t i32_res = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  if (count & vl == 0x1f)
+    i32_res = __riscv_vadd_vv_i32m1 (i32_res, i32_res, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  f32_res = __riscv_vreinterpret_v_i32m1_f32m1 (i32_res);
+  result = __riscv_vfadd_vv_f32m1_rm (f32_res, op2, 4, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
new file mode 100644
index 00000000000..5a2b8a16952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-70.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1 (result, op2, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
new file mode 100644
index 00000000000..185a04cc2bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-71.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  if (count & vl == 0x1f)
+    result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  else
+    vl = normalize_vl_1 (vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
new file mode 100644
index 00000000000..6a07cfa6df9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-72.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 (size_t vl);
+
+vfloat32m1_t
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			     unsigned count, size_t vl)
+{
+  vfloat32m1_t result = op1;
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 1, vl);
+  vl = normalize_vl_1 (vl);
+
+  vint32m1_t tmp_1 = __riscv_vreinterpret_v_f32m1_i32m1 (op1);
+  vint32m1_t tmp_2 = __riscv_vreinterpret_v_f32m1_i32m1 (op2);
+
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+  tmp_2 = __riscv_vadd_vv_i32m1 (tmp_2, tmp_1, vl);
+  tmp_1 = __riscv_vadd_vv_i32m1 (tmp_1, tmp_2, vl);
+
+  result = __riscv_vfadd_vv_f32m1_rm (result, op2, 3, vl);
+
+  return result;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
new file mode 100644
index 00000000000..91b015c51e8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-73.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
new file mode 100644
index 00000000000..b52400e5123
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-74.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 3, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 3 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
new file mode 100644
index 00000000000..4d3fd859637
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-75.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1_rm (op1, op2, 1, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 1 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
new file mode 100644
index 00000000000..7ff106a8847
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-76.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+extern size_t normalize_vl_1 ();
+extern size_t normalize_vl_2 ();
+
+void
+test_float_point_dynamic_frm (vfloat32m1_t op1, vfloat32m1_t op2,
+			      size_t vl, int cond)
+{
+  vfloat32m1_t result_1;
+
+  asm volatile ("#def %0" : "=vr"(result_1));
+
+  result_1 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_1));
+
+  if (cond)
+    normalize_vl_1 ();
+  else
+    normalize_vl_2 ();
+
+  vfloat32m1_t result_2;
+
+  asm volatile ("#def %0" : "=vr"(result_2));
+
+  result_2 = __riscv_vfadd_vv_f32m1 (op1, op2, vl);
+
+  asm volatile ("#use %0" : : "vr"(result_2));
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
new file mode 100644
index 00000000000..c3d12cfe04e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-dynamic-frm-77.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zbb --param=riscv-autovec-preference=fixed-vlmax -ffast-math -mabi=lp64 -O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+
+double sum(double *d)
+{
+  double sum = 0.0;
+
+  for (int i = 0; i < 8; ++i)
+    sum += d[i];
+
+  return sum;
+}
+
+/* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 3 } } */
+/* { dg-final { scan-assembler-not {frrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrm\s+[axs][0-9]+} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[01234]} } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
index 12db112dd0b..6de9d06b875 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-insert-7.c
@@ -26,6 +26,7 @@ test_float_point_frm_static (float *out, vfloat32m1_t op1, vfloat32m1_t op2,
 }
 
 /* { dg-final { scan-assembler-times {vfadd\.v[vf]\s+v[0-9]+,\s*v[0-9]+,\s*[fav]+[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 1 } } */
-/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {frrm\s+[axs][0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {fsrm\s+[axs][0-9]+} 2 } } */
 /* { dg-final { scan-assembler-times {fsrmi\s+[01234]} 2 } } */
+/* { dg-final { scan-assembler-not {fsrmi\s+[axs][0-9]+,\s*[01234]} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-1.c
index 1b2789a924b..f3089d2b773 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-1.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-1.c
@@ -5,6 +5,8 @@
 #include <stdio.h>
 #include <stdint-gcc.h>
 
+#include "float-point-frm-run.h"
+
 #define DEFINE_TEST_FUNC(FRM) \
 vfloat32m1_t __attribute__ ((noinline)) \
 test_float_point_frm_run_##FRM (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) \
@@ -15,7 +17,7 @@ test_float_point_frm_run_##FRM (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) \
                                                                                \
   result = __riscv_vfadd_vv_f32m1_rm (op1, result, FRM, vl);                   \
                                                                                \
-  assert_equal (FRM, get_frm (), "The value of frm should be " #FRM ".");      \
+  assert_equal (FRM, get_frm (), "The value of frm should be equal");          \
                                                                                \
   return result;                                                               \
 }
@@ -23,42 +25,6 @@ test_float_point_frm_run_##FRM (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl) \
 #define RUN_TEST_FUNC(FRM, op1, op2, vl) \
   test_float_point_frm_run_##FRM (op1, op2, vl)
 
-static int
-get_frm ()
-{
-  int frm = -1;
-
-  __asm__ volatile (
-    "frrm %0"
-    :"=r"(frm)
-    :
-    :
-  );
-
-  return frm;
-}
-
-static void
-set_frm (int frm)
-{
-  __asm__ volatile (
-    "fsrm %0"
-    :
-    :"r"(frm)
-    :
-  );
-}
-
-static inline void
-assert_equal (int a, int b, char *message)
-{
-  if (a != b)
-    {
-      printf (message);
-      __builtin_abort ();
-    }
-}
-
 DEFINE_TEST_FUNC (0)
 DEFINE_TEST_FUNC (1)
 DEFINE_TEST_FUNC (2)
@@ -75,19 +41,19 @@ main ()
   set_frm (4);
 
   RUN_TEST_FUNC (0, op1, op2, vl);
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   RUN_TEST_FUNC (1, op1, op2, vl);
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   RUN_TEST_FUNC (2, op1, op2, vl);
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   RUN_TEST_FUNC (3, op1, op2, vl);
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   RUN_TEST_FUNC (4, op1, op2, vl);
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-2.c
index ec4cc26135d..8303b61eb04 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-2.c
@@ -5,41 +5,7 @@
 #include <stdio.h>
 #include <stdint-gcc.h>
 
-static int
-get_frm ()
-{
-  int frm = -1;
-
-  __asm__ volatile (
-    "frrm %0"
-    :"=r"(frm)
-    :
-    :
-  );
-
-  return frm;
-}
-
-static void
-set_frm (int frm)
-{
-  __asm__ volatile (
-    "fsrm %0"
-    :
-    :"r"(frm)
-    :
-  );
-}
-
-static inline void
-assert_equal (int a, int b, char *message)
-{
-  if (a != b)
-    {
-      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
-      __builtin_abort ();
-    }
-}
+#include "float-point-frm-run.h"
 
 vfloat32m1_t __attribute__ ((noinline))
 test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
@@ -50,7 +16,7 @@ test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
 
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   return result;
 }
@@ -65,7 +31,7 @@ main ()
   set_frm (2);
   test_float_point_frm_run (op1, op2, vl);
 
-  assert_equal (2, get_frm (), "The value of frm register should be 2.");
+  assert_equal (2, get_frm (), "The value of frm should be equal");
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-3.c
index 32ed6962dc9..592ff6bd621 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-3.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-3.c
@@ -5,41 +5,7 @@
 #include <stdio.h>
 #include <stdint-gcc.h>
 
-static int
-get_frm ()
-{
-  int frm = -1;
-
-  __asm__ volatile (
-    "frrm %0"
-    :"=r"(frm)
-    :
-    :
-  );
-
-  return frm;
-}
-
-static void
-set_frm (int frm)
-{
-  __asm__ volatile (
-    "fsrm %0"
-    :
-    :"r"(frm)
-    :
-  );
-}
-
-static inline void
-assert_equal (int a, int b, char *message)
-{
-  if (a != b)
-    {
-      fprintf (stdout, "%s, but get %d != %d\n", message, a, b);
-      __builtin_abort ();
-    }
-}
+#include "float-point-frm-run.h"
 
 vfloat32m1_t __attribute__ ((noinline))
 test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
@@ -48,7 +14,7 @@ test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
 
   result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
 
-  assert_equal (4, get_frm (), "The value of frm register should be 4.");
+  assert_equal (4, get_frm (), "The value of frm should be equal");
 
   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
   result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
@@ -66,7 +32,7 @@ main ()
   set_frm (0);
   test_float_point_frm_run (op1, op2, vl);
 
-  assert_equal (0, get_frm (), "The value of frm register should be 0.");
+  assert_equal (0, get_frm (), "The value of frm should be equal");
 
   return 0;
 }
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
new file mode 100644
index 00000000000..56e46680e8d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-4.c
@@ -0,0 +1,47 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#include "float-point-frm-run.h"
+
+#define ORIGINAL_FRM 1
+
+vfloat32m1_t __attribute__ ((noinline))
+other_function (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = op2;
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+
+  assert_equal (ORIGINAL_FRM, get_frm (), "The value of frm should be equal");
+
+  return result;
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 4, vl);
+
+  assert_equal (4, get_frm (), "The value of frm should be equal");
+
+  return other_function (result, op2, vl);
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
new file mode 100644
index 00000000000..8b338f2903d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run-5.c
@@ -0,0 +1,47 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-options "-O3 -Wno-psabi" } */
+
+#include "riscv_vector.h"
+#include <stdio.h>
+#include <stdint-gcc.h>
+
+#include "float-point-frm-run.h"
+
+#define ORIGINAL_FRM 1
+#define NEW_FRM 4
+
+void __attribute__ ((noinline))
+other_function ()
+{
+  set_frm (NEW_FRM);
+}
+
+vfloat32m1_t __attribute__ ((noinline))
+test_float_point_frm_run (vfloat32m1_t op1, vfloat32m1_t op2, size_t vl)
+{
+  vfloat32m1_t result = {};
+
+  other_function ();
+  assert_equal (NEW_FRM, get_frm (), "The value of frm should be equal");
+
+  result = __riscv_vfadd_vv_f32m1_rm (op1, result, 2, vl);
+  assert_equal (2, get_frm (), "The value of frm should be equal");
+
+  result = __riscv_vfadd_vv_f32m1 (op1, result, vl);
+  assert_equal (NEW_FRM, get_frm (), "The value of frm should be equal");
+
+  return result;
+}
+
+int
+main ()
+{
+  size_t vl = 8;
+  vfloat32m1_t op1 = {};
+  vfloat32m1_t op2 = {};
+
+  set_frm (ORIGINAL_FRM);
+  test_float_point_frm_run (op1, op2, vl);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run.h b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run.h
new file mode 100644
index 00000000000..7dc2a10bc16
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/float-point-frm-run.h
@@ -0,0 +1,40 @@
+#ifndef FLOAT_POINT_FRM_RUN_H
+#define FLOAT_POINT_FRM_RUN_H
+
+static void
+assert_equal (int a, int b, char *message)
+{
+  if (a != b)
+    {
+      printf ("%s, but get %d != %d\n", message, a, b);
+      __builtin_abort ();
+    }
+}
+
+static int
+get_frm ()
+{
+  int frm = -1;
+
+  __asm__ volatile (
+    "frrm %0"
+    :"=r"(frm)
+    :
+    :
+  );
+
+  return frm;
+}
+
+static void
+set_frm (int frm)
+{
+  __asm__ volatile (
+    "fsrm %0"
+    :
+    :"r"(frm)
+    :
+  );
+}
+
+#endif
-- 
2.34.1


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-28  1:15 ` [PATCH v8] " pan2.li
@ 2023-07-28 10:05   ` Robin Dapp
  2023-07-28 12:34     ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Robin Dapp @ 2023-07-28 10:05 UTC (permalink / raw)
  To: pan2.li, gcc-patches; +Cc: rdapp.gcc, juzhe.zhong, kito.cheng, yanzhang.wang

Hi Pan,

thanks for your patience and your work.  Apart from my general doubt
whether mode-changing intrinsics are a good idea, I don't have other
remarks that need fixing.  What I mentioned before:

 - Handling of asms wouldn't be a huge change.  It can be done
 in a follow-up patch of course but should be done eventually.

 - The code is still rather difficult to follow because we diverge
 from the usual mode-switching semantics e.g. in that we emit insns
 in mode_needed as well as in mode_set.  I would have preferred
 to stay close to the regular usage, document where and why we need
 to do something different and suggest future middle-end improvements
 to solve this more elegantly.

 - I hope non-local control flow like setjmp/longjmp, sibcall
 optimization and maybe others work fine.  I didn't see a reason
 why not but I haven't checked very closely either.

 - We can probably get away with not annotating every call with
 an FRM clobber because there isn't any pass that would make use
 of that anyway?


As to my general qualm, independent of this patch, quickly
summarized again one last time (the problem was latent before this
specific patch anyway):

I would prefer not to have mode-changing intrinsics at all but
have users call fesetround explicitly.  That way the exact point
where the rounding mode is changed would be obvious and not
subject to optimization as well as caching/backing up.
If at all necessary I would have preferred the LLVM way of
backing up, setting new mode, performing the instruction
and restoring directly after.
If the initial intent of mode-changing intrinsics was to give
users more control, I don't believe we achieve this by the "lazy"
restore mechanism which is rather an obfuscation.

Pardon my frankness but the whole mode-changing thing feels to me
like just getting a feature out of the door to solve "something"
/appease users than a well thought-out feature.  It doesn't even
seem clear if this optimization is worthwhile when changing the
rounding mode is prohibitively slow anyway.

That said, if the current status is what the majority of
contributors can live with, I'm not going to stand in the way,
but I'd ask Kito or somebody else to give the final OK.

Regards
 Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-28 10:05   ` Robin Dapp
@ 2023-07-28 12:34     ` Li, Pan2
  2023-08-01  7:50       ` Kito Cheng
  0 siblings, 1 reply; 49+ messages in thread
From: Li, Pan2 @ 2023-07-28 12:34 UTC (permalink / raw)
  To: Robin Dapp, gcc-patches; +Cc: juzhe.zhong, kito.cheng, Wang, Yanzhang

Great! Thanks Robin for so many useful comments, as well as the thought-provoking discussion with different insights.
I believe such kind of interactively discussion will empower all of us, and leading us to do the right things.

Back to this PATCH, I try to only do one thing at a time and I totally agree that there are something we need to try.
Thanks again and let's wait for kito's comments.

Pan

-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Friday, July 28, 2023 6:05 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding

Hi Pan,

thanks for your patience and your work.  Apart from my general doubt
whether mode-changing intrinsics are a good idea, I don't have other
remarks that need fixing.  What I mentioned before:

 - Handling of asms wouldn't be a huge change.  It can be done
 in a follow-up patch of course but should be done eventually.

 - The code is still rather difficult to follow because we diverge
 from the usual mode-switching semantics e.g. in that we emit insns
 in mode_needed as well as in mode_set.  I would have preferred
 to stay close to the regular usage, document where and why we need
 to do something different and suggest future middle-end improvements
 to solve this more elegantly.

 - I hope non-local control flow like setjmp/longjmp, sibcall
 optimization and maybe others work fine.  I didn't see a reason
 why not but I haven't checked very closely either.

 - We can probably get away with not annotating every call with
 an FRM clobber because there isn't any pass that would make use
 of that anyway?


As to my general qualm, independent of this patch, quickly
summarized again one last time (the problem was latent before this
specific patch anyway):

I would prefer not to have mode-changing intrinsics at all but
have users call fesetround explicitly.  That way the exact point
where the rounding mode is changed would be obvious and not
subject to optimization as well as caching/backing up.
If at all necessary I would have preferred the LLVM way of
backing up, setting new mode, performing the instruction
and restoring directly after.
If the initial intent of mode-changing intrinsics was to give
users more control, I don't believe we achieve this by the "lazy"
restore mechanism which is rather an obfuscation.

Pardon my frankness but the whole mode-changing thing feels to me
like just getting a feature out of the door to solve "something"
/appease users than a well thought-out feature.  It doesn't even
seem clear if this optimization is worthwhile when changing the
rounding mode is prohibitively slow anyway.

That said, if the current status is what the majority of
contributors can live with, I'm not going to stand in the way,
but I'd ask Kito or somebody else to give the final OK.

Regards
 Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-07-28 12:34     ` Li, Pan2
@ 2023-08-01  7:50       ` Kito Cheng
  2023-08-01  8:00         ` Li, Pan2
  0 siblings, 1 reply; 49+ messages in thread
From: Kito Cheng @ 2023-08-01  7:50 UTC (permalink / raw)
  To: Li, Pan2; +Cc: Robin Dapp, gcc-patches, juzhe.zhong, kito.cheng, Wang, Yanzhang

Hi Pan:


Thanks for your effort on this, this is LGTM and OK for trunk.


Hi Robin:


Thanks for your review on this stuff, this set of intrinsic functions
is complicated and might be controversial since the whole floating
point rounding mode is…complicated, and people might have different
tastes on that.


So what we (RVV intrinsic TG) trying to do is adding another set of
intrinsic *and* keep existing floating point intrinsic, so people
could still using fesetround style to play around the floating point
stuffs, but I am not intend to convince you that is necessary and it's
100% right design - I admit it's kind of experimental design as the
LLVM's constrained floating-point intrinsics.

Anyway, let's move forward, and see how useful it is for the RISC-V ecosystem :)

On Fri, Jul 28, 2023 at 8:35 PM Li, Pan2 via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Great! Thanks Robin for so many useful comments, as well as the thought-provoking discussion with different insights.
> I believe such kind of interactively discussion will empower all of us, and leading us to do the right things.
>
> Back to this PATCH, I try to only do one thing at a time and I totally agree that there are something we need to try.
> Thanks again and let's wait for kito's comments.
>
> Pan
>
> -----Original Message-----
> From: Robin Dapp <rdapp.gcc@gmail.com>
> Sent: Friday, July 28, 2023 6:05 PM
> To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
> Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
> Subject: Re: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
>
> Hi Pan,
>
> thanks for your patience and your work.  Apart from my general doubt
> whether mode-changing intrinsics are a good idea, I don't have other
> remarks that need fixing.  What I mentioned before:
>
>  - Handling of asms wouldn't be a huge change.  It can be done
>  in a follow-up patch of course but should be done eventually.
>
>  - The code is still rather difficult to follow because we diverge
>  from the usual mode-switching semantics e.g. in that we emit insns
>  in mode_needed as well as in mode_set.  I would have preferred
>  to stay close to the regular usage, document where and why we need
>  to do something different and suggest future middle-end improvements
>  to solve this more elegantly.
>
>  - I hope non-local control flow like setjmp/longjmp, sibcall
>  optimization and maybe others work fine.  I didn't see a reason
>  why not but I haven't checked very closely either.
>
>  - We can probably get away with not annotating every call with
>  an FRM clobber because there isn't any pass that would make use
>  of that anyway?
>
>
> As to my general qualm, independent of this patch, quickly
> summarized again one last time (the problem was latent before this
> specific patch anyway):
>
> I would prefer not to have mode-changing intrinsics at all but
> have users call fesetround explicitly.  That way the exact point
> where the rounding mode is changed would be obvious and not
> subject to optimization as well as caching/backing up.
> If at all necessary I would have preferred the LLVM way of
> backing up, setting new mode, performing the instruction
> and restoring directly after.
> If the initial intent of mode-changing intrinsics was to give
> users more control, I don't believe we achieve this by the "lazy"
> restore mechanism which is rather an obfuscation.
>
> Pardon my frankness but the whole mode-changing thing feels to me
> like just getting a feature out of the door to solve "something"
> /appease users than a well thought-out feature.  It doesn't even
> seem clear if this optimization is worthwhile when changing the
> rounding mode is prohibitively slow anyway.
>
> That said, if the current status is what the majority of
> contributors can live with, I'm not going to stand in the way,
> but I'd ask Kito or somebody else to give the final OK.
>
> Regards
>  Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

* RE: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
  2023-08-01  7:50       ` Kito Cheng
@ 2023-08-01  8:00         ` Li, Pan2
  0 siblings, 0 replies; 49+ messages in thread
From: Li, Pan2 @ 2023-08-01  8:00 UTC (permalink / raw)
  To: Kito Cheng
  Cc: Robin Dapp, gcc-patches, juzhe.zhong, kito.cheng, Wang, Yanzhang

Committed, thanks a lof, Robin and Kito, very appreciative for the explanation and comments from the expert's perspective.

Pan

-----Original Message-----
From: Kito Cheng <kito.cheng@gmail.com> 
Sent: Tuesday, August 1, 2023 3:51 PM
To: Li, Pan2 <pan2.li@intel.com>
Cc: Robin Dapp <rdapp.gcc@gmail.com>; gcc-patches@gcc.gnu.org; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
Subject: Re: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding

Hi Pan:


Thanks for your effort on this, this is LGTM and OK for trunk.


Hi Robin:


Thanks for your review on this stuff, this set of intrinsic functions
is complicated and might be controversial since the whole floating
point rounding mode is…complicated, and people might have different
tastes on that.


So what we (RVV intrinsic TG) trying to do is adding another set of
intrinsic *and* keep existing floating point intrinsic, so people
could still using fesetround style to play around the floating point
stuffs, but I am not intend to convince you that is necessary and it's
100% right design - I admit it's kind of experimental design as the
LLVM's constrained floating-point intrinsics.

Anyway, let's move forward, and see how useful it is for the RISC-V ecosystem :)

On Fri, Jul 28, 2023 at 8:35 PM Li, Pan2 via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Great! Thanks Robin for so many useful comments, as well as the thought-provoking discussion with different insights.
> I believe such kind of interactively discussion will empower all of us, and leading us to do the right things.
>
> Back to this PATCH, I try to only do one thing at a time and I totally agree that there are something we need to try.
> Thanks again and let's wait for kito's comments.
>
> Pan
>
> -----Original Message-----
> From: Robin Dapp <rdapp.gcc@gmail.com>
> Sent: Friday, July 28, 2023 6:05 PM
> To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
> Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@sifive.com; Wang, Yanzhang <yanzhang.wang@intel.com>
> Subject: Re: [PATCH v8] RISC-V: Support CALL for RVV floating-point dynamic rounding
>
> Hi Pan,
>
> thanks for your patience and your work.  Apart from my general doubt
> whether mode-changing intrinsics are a good idea, I don't have other
> remarks that need fixing.  What I mentioned before:
>
>  - Handling of asms wouldn't be a huge change.  It can be done
>  in a follow-up patch of course but should be done eventually.
>
>  - The code is still rather difficult to follow because we diverge
>  from the usual mode-switching semantics e.g. in that we emit insns
>  in mode_needed as well as in mode_set.  I would have preferred
>  to stay close to the regular usage, document where and why we need
>  to do something different and suggest future middle-end improvements
>  to solve this more elegantly.
>
>  - I hope non-local control flow like setjmp/longjmp, sibcall
>  optimization and maybe others work fine.  I didn't see a reason
>  why not but I haven't checked very closely either.
>
>  - We can probably get away with not annotating every call with
>  an FRM clobber because there isn't any pass that would make use
>  of that anyway?
>
>
> As to my general qualm, independent of this patch, quickly
> summarized again one last time (the problem was latent before this
> specific patch anyway):
>
> I would prefer not to have mode-changing intrinsics at all but
> have users call fesetround explicitly.  That way the exact point
> where the rounding mode is changed would be obvious and not
> subject to optimization as well as caching/backing up.
> If at all necessary I would have preferred the LLVM way of
> backing up, setting new mode, performing the instruction
> and restoring directly after.
> If the initial intent of mode-changing intrinsics was to give
> users more control, I don't believe we achieve this by the "lazy"
> restore mechanism which is rather an obfuscation.
>
> Pardon my frankness but the whole mode-changing thing feels to me
> like just getting a feature out of the door to solve "something"
> /appease users than a well thought-out feature.  It doesn't even
> seem clear if this optimization is worthwhile when changing the
> rounding mode is prohibitively slow anyway.
>
> That said, if the current status is what the majority of
> contributors can live with, I'm not going to stand in the way,
> but I'd ask Kito or somebody else to give the final OK.
>
> Regards
>  Robin

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2023-08-01  8:01 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-19  3:28 [PATCH v1] RISC-V: Support CALL for RVV floating-point dynamic rounding pan2.li
2023-07-19  3:31 ` juzhe.zhong
2023-07-19  6:30   ` Li, Pan2
2023-07-20  6:43 ` [PATCH v4] " pan2.li
2023-07-20  6:47   ` juzhe.zhong
2023-07-21  3:11   ` juzhe.zhong
2023-07-21  6:44     ` Li, Pan2
2023-07-23 13:11 ` [PATCH v5] " pan2.li
2023-07-24  0:53   ` juzhe.zhong
2023-07-24  1:51     ` Li, Pan2
2023-07-24  2:45       ` Li, Pan2
2023-07-24  2:42 ` [PATCH v6] " pan2.li
2023-07-24 10:28   ` Robin Dapp
2023-07-24 11:59     ` Li, Pan2
2023-07-24 12:03       ` Li, Pan2
2023-07-25  5:51 ` [PATCH v7] " pan2.li
2023-07-25  6:07   ` Li, Pan2
2023-07-25  8:38     ` Robin Dapp
2023-07-25 11:53       ` Li, Pan2
2023-07-25 13:23         ` Kito Cheng
2023-07-25 14:12           ` Robin Dapp
2023-07-26 13:08             ` Robin Dapp
2023-07-26 21:40               ` Jeff Law
2023-07-26 22:21                 ` 钟居哲
2023-07-26 22:46                   ` Jeff Law
2023-07-26 22:56                     ` 钟居哲
2023-07-27  1:38                       ` Li, Pan2
2023-07-27  8:19                         ` Li, Pan2
2023-07-27  2:09               ` Li, Pan2
2023-07-27  7:25                 ` Robin Dapp
2023-07-27  8:26                   ` Li, Pan2
2023-07-27  8:41                     ` Robin Dapp
2023-07-27 10:27                       ` Li, Pan2
     [not found]             ` <63471C6E126E44CF+D1CEA4C9-0050-43CD-8DE3-26EBD7AEE6DA@rivai.ai>
2023-07-26 13:35               ` Li, Pan2
2023-07-26 13:43                 ` Li, Pan2
2023-07-26 13:46               ` Robin Dapp
2023-07-26 13:57                 ` Kito Cheng
2023-07-26 14:05                   ` Kito Cheng
2023-07-26 14:10                     ` Robin Dapp
2023-07-26 14:18                 ` 钟居哲
2023-07-26 14:30                   ` Li, Pan2
2023-07-26 15:34                     ` Kito Cheng
2023-07-26 16:00                       ` Palmer Dabbelt
2023-07-26 21:01                     ` Robin Dapp
2023-07-28  1:15 ` [PATCH v8] " pan2.li
2023-07-28 10:05   ` Robin Dapp
2023-07-28 12:34     ` Li, Pan2
2023-08-01  7:50       ` Kito Cheng
2023-08-01  8:00         ` Li, Pan2

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).