https://gcc.gnu.org/g:aac916630f4e5b8747ef60742a6a4c2f7db8ebdc

commit aac916630f4e5b8747ef60742a6a4c2f7db8ebdc
Author: Jeff Law <[email protected]>
Date:   Tue Jan 20 13:57:10 2026 -0700

    [RISC-V][PR target/123626] Fix VXRM state after calls
    
    This is a partial fix for a long standing issue that Richard S. raised 
about a
    year ago.
    
    Specifically he indicated that he believed our handling of VXRM mode 
switching
    was wrong and could lead to incorrect code, particularly WRT handling of 
calls.
    
    Without rehashing everything related to VXRM, its sufficient to say that it 
has
    no known value at function entry or upon returning from a call.
    
    If we look at the main scan loop in mode-switching we have:
    
    >           FOR_BB_INSNS (bb, insn)
    >             {
    >               if (NONDEBUG_INSN_P (insn))
    >                 {
    >                   int mode = targetm.mode_switching.needed (e, insn, 
live_now);
    >                   rtx link;
    >
    >                   if (mode != no_mode && mode != last_mode)
    >                     {
    >                       ptr = new_seginfo (last_mode, mode, insn, live_now);
    >                       add_seginfo (&tail_ptr, ptr);
    >                       bitmap_clear_bit (transp_all, bb->index);
    >                       any_set_required = true;
    >                       last_mode = mode;
    >                     }
    
    The way to think about this is if INSN requests a mode and it is not the 
same
    as the last mode, then we've got a new point where we need to logically 
insert
    a mode switch and we clear TRANSP.
    
    A CALL_INSN in the RISC-V backend produces NO_MODE (it doesn't need VXRM
    state).  So we never get into the then clause of that inner if statement and
    TRANSP stays on.
    
    The fix is quite simple.  We need one more state in the VXRM mode switching
    that indicates we don't know VXRM's state after a call. While I could have
    hacked up the various hooks to special case CALLs, it was just as easy to
    adjust the attribute's generic handling so that any CALL_P is given the
    VXRM_MODE_CLOBBER state.
    
    Out of an abundance of caution if we'll filter out any actual code 
generation
    setting it to CLOBBER state.
    
    This is enough to make the testcase pass for rv64.  It's still failing rv32,
    but likely for completely different reasons.   It obviously doesn't cause 
any
    regressions on riscv{32,64}-elf and bootstraps will fire up later today on 
the
    Pioneer and BPI.
    
            PR target/123626
    gcc/
            * config/riscv/vector.md (vxrm_mode): Handle CALL_INSNs, which set
            the attribute to the new VXRM_MODE_CLOBBER state.
            * config/riscv/riscv.cc (riscv_emit_mode_set): Don't emit code when
            VXRM's state changes to VXRM_MODE_CLOBBER.
    
    gcc/testsuite
            * gcc.target/riscv/rvv/base/pr123626.c: New test.
    
    (cherry picked from commit 6b79f1a5b8b62ce711d590a7f3e6ecb40b465464)

Diff:
---
 gcc/config/riscv/riscv.cc                          |  4 +++-
 gcc/config/riscv/vector.md                         |  6 ++++--
 gcc/testsuite/gcc.target/riscv/rvv/base/pr123626.c | 23 ++++++++++++++++++++++
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index a5bda2e43751..aa482c132598 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13777,7 +13777,9 @@ riscv_emit_mode_set (int entity, int mode, int 
prev_mode,
   switch (entity)
     {
     case RISCV_VXRM:
-      if (mode != VXRM_MODE_NONE && mode != prev_mode)
+      if (mode != VXRM_MODE_NONE
+         && mode != VXRM_MODE_CLOBBER
+         && mode != prev_mode)
        emit_insn (gen_vxrmsi (gen_int_mode (mode, SImode)));
       break;
     case RISCV_FRM:
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 8175fada6429..cc617f14812b 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -1003,7 +1003,7 @@
 
 ;; Defines rounding mode of an fixed-point operation.
 
-(define_attr "vxrm_mode" "rnu,rne,rdn,rod,none"
+(define_attr "vxrm_mode" "rnu,rne,rdn,rod,clobber,none"
   (cond [(eq_attr "type" "vaalu,vsmul,vsshift,vnclip")
         (cond
           [(match_test "INTVAL (operands[9]) == riscv_vector::VXRM_RNU")
@@ -1017,7 +1017,9 @@
 
            (match_test "INTVAL (operands[9]) == riscv_vector::VXRM_ROD")
            (const_string "rod")]
-          (const_string "none"))]
+          (const_string "none"))
+        (match_test "CALL_P (insn)")
+        (const_string "clobber")]
         (const_string "none")))
 
 ;; Defines rounding mode of an floating-point operation.
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr123626.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/pr123626.c
new file mode 100644
index 000000000000..ddf9b065d91e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr123626.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-march=rv64gcv_zvl256b -mabi=lp64d -O3 -fsigned-char 
-fno-strict-aliasing -fwrapv -std=gnu99" { target rv64 } } */
+/* { dg-options "-march=rv32gcv_zvl256b -mabi=ilp32 -O3 -fsigned-char 
-fno-strict-aliasing -fwrapv -std=gnu99" { target rv32 } } */
+short a;
+long long b;
+char c[3][3][17];
+_Bool d;
+
+int main() {
+  for (long g=0; g<3; ++g)
+    for (long h=0; h<3; ++h)
+      for (long i=0; i<17; ++i)
+        c[g][h][i] = 2;
+
+  for (char g=0; g<3; g-=13)
+    for (short j=3; j<d+21; j+=2)
+      a += 2;
+
+  b = (int)a;
+  if (b != 180)
+    __builtin_abort ();
+  __builtin_exit (0);
+}

Reply via email to