]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V][PR target/123626] Fix VXRM state after calls
authorJeff Law <jeffrey.law@oss.qualcomm.com>
Tue, 20 Jan 2026 20:57:10 +0000 (13:57 -0700)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Tue, 20 Jan 2026 20:57:10 +0000 (13:57 -0700)
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.

gcc/config/riscv/riscv.cc
gcc/config/riscv/vector.md
gcc/testsuite/gcc.target/riscv/rvv/base/pr123626.c [new file with mode: 0644]

index 949616a63d3c5b6f29ebf95aae355f66eb74c2e5..a85a2035a8b7a3ef5211faa2eb2cdad7ee81734b 100644 (file)
@@ -13793,7 +13793,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:
index 8e20aac9bb8e698c08a189a16f4c9e6ac05c39ac..6bf01338117c9ddb1b13c2469747d0360c530264 100644 (file)
 
 ;; 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")
 
            (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 (file)
index 0000000..ddf9b06
--- /dev/null
@@ -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);
+}