Although we already try to set the mode needed to FRM_DYN after a function call,
there are still some corner cases where both FRM_DYN and FRM_DYN_CALL may appear
on incoming edges.

Therefore, we use TARGET_MODE_CONFLUENCE to tell GCC that FRM_DYN, FRM_DYN_CALL,
and FRM_DYN_EXIT modes are compatible.

gcc/ChangeLog:

        PR target/119832
        * config/riscv/riscv.cc riscv_dynamic_frm_mode_p): New.
        (riscv_mode_confluence): New.
        (TARGET_MODE_CONFLUENCE): Define to riscv_mode_confluence.

gcc/testsuite/ChangeLog:

        PR target/119832
        * g++.target/riscv/pr119832.C: New test.
---
 gcc/config/riscv/riscv.cc                 | 37 +++++++++++++++++++++++
 gcc/testsuite/g++.target/riscv/pr119832.C | 27 +++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 gcc/testsuite/g++.target/riscv/pr119832.C

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index bad59e248d0..198fe72ef68 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -12273,6 +12273,41 @@ riscv_mode_needed (int entity, rtx_insn *insn, 
HARD_REG_SET)
     }
 }
 
+/* Return TRUE if the rouding mode is dynamic.  */
+
+static bool
+riscv_dynamic_frm_mode_p (int mode)
+{
+  return mode == riscv_vector::FRM_DYN
+        || mode == riscv_vector::FRM_DYN_CALL
+        || mode == riscv_vector::FRM_DYN_EXIT;
+}
+
+/* Implement TARGET_MODE_CONFLUENCE.  */
+
+static int
+riscv_mode_confluence (int entity, int mode1, int mode2)
+{
+  switch (entity)
+    {
+    case RISCV_VXRM:
+      return VXRM_MODE_NONE;
+    case RISCV_FRM:
+      {
+       /* FRM_DYN, FRM_DYN_CALL and FRM_DYN_EXIT are all compatible.
+          Although we already try to set the mode needed to FRM_DYN after a
+          function call, there are still some corner cases where both FRM_DYN
+          and FRM_DYN_CALL may appear on incoming edges.  */
+       if (riscv_dynamic_frm_mode_p (mode1)
+           && riscv_dynamic_frm_mode_p (mode2))
+         return riscv_vector::FRM_DYN;
+       return riscv_vector::FRM_NONE;
+      }
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Return TRUE that an insn is asm.  */
 
 static bool
@@ -14356,6 +14391,8 @@ bool need_shadow_stack_push_pop_p ()
 #define TARGET_MODE_EMIT riscv_emit_mode_set
 #undef TARGET_MODE_NEEDED
 #define TARGET_MODE_NEEDED riscv_mode_needed
+#undef TARGET_MODE_CONFLUENCE
+#define TARGET_MODE_CONFLUENCE riscv_mode_confluence
 #undef TARGET_MODE_AFTER
 #define TARGET_MODE_AFTER riscv_mode_after
 #undef TARGET_MODE_ENTRY
diff --git a/gcc/testsuite/g++.target/riscv/pr119832.C 
b/gcc/testsuite/g++.target/riscv/pr119832.C
new file mode 100644
index 00000000000..f4dc480e6d5
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/pr119832.C
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gcv -mabi=lp64 -ffast-math" } */
+
+struct ac  {
+  ~ac();
+  void u();
+};
+struct ae {
+  int s;
+  float *ag;
+};
+
+float c;
+
+void ak(ae *al, int n) {
+  ac d;
+  for (int i;i<n;++i) {
+    float a = 0;
+    for (long j; j < al[i].s; j++)
+      a += al[i].ag[j];
+    c = a;
+    d.u();
+  }
+}
+
+/* { dg-final { scan-assembler-not "frrm\t" } } */
+/* { dg-final { scan-assembler-not "fsrm\t" } } */
-- 
2.37.1

Reply via email to