https://gcc.gnu.org/g:31eb899f30c51f03e9dcae76ff92c53928345d7c

commit r17-5663-g31eb899f30c51f03e9dcae76ff92c53928345d7c
Author: Jeff Law <[email protected]>
Date:   Wed Oct 28 07:11:44 2026 -0600

    [RISC-V] Fix multiple small RISC-V bugs discovered during LLM review
    
    And yesterday's set of fixes inspired by LLM review of the RISC-V machine
    description.
    
    For ior/xor synthesis, two issues.  First we can trigger undefined behavior
    with a shift by the size of the object.  It never results in incorrect code,
    but it's best avoided.  Second, there's an off-by-1 error which caused us to
    fail to synthesize the rotate variants in one class of cases.  The LLM
    generated a test for the missed optimization.
    
    For and synthesis, we could generate an unrecognizable insn if B is off, but
    Zbkb was on.  It's an unlikely combination, but clearly wrong.  The LLM
    generated a testcase for this problem too.
    
    In the overflow expanders and divmod expanders, we can write the output 
before
    the inputs are consumed.  This is actually safe in practice for these
    expanders, but wrong from a design standpoint.  I don't have the md.texi or
    rtl.texi passage handy, but the expanders are responsible for ensuring the
    inputs are fully consumed before outputs are written.  make_safe_from 
handles
    that nicely.  Given it's 100% latent, no testcase.
    
    There's a unnamed define_insn_and_split that shifted 1, potentially by 32 or
    more bits.  That's bad.  HOST_WIDE_INT_1U fixes that.  Didn't bother asking 
for
    a testcase from the LLM
    
    Regression tested on riscv32-elf and riscv64-elf.  Bootstrapped and 
regression
    tested on the K3 and c920.  K1 is in flight.
    
    gcc/
            * config/riscv/riscv.cc (synthesize_xor): Avoid undefined shift when
            using rotate to get key bits into useful position.  Fix off-by-one
            error causing missed optimization in rotate case.
            (synthesize_and): Do not use zext.h if ZBB is not enabled.
            * config/riscv/riscv.md (addv<mode>4): Use make_safe_from to ensure 
inputs
            are not overwritten by early assignments to the output.
            (uaddv<mode>4, subv<mode>4, usubv<mode>4, <u>divmod<mode>4): 
Likewise.
            (addition with masked shift splitter): Use HOST_WIDE_INT_1U rather 
than 1.
    
    gcc/testsuite/
    
            * gcc.target/riscv/xor-synthesis-5.c: New test.
            * gcc.target/riscv/zbkb-zext.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                        | 14 ++++++++++----
 gcc/config/riscv/riscv.md                        | 10 +++++++++-
 gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c | 10 ++++++++++
 gcc/testsuite/gcc.target/riscv/zbkb-zext.c       |  3 +++
 4 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index cc96cc0ad8bf..bed695ccae4b 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -16270,12 +16270,18 @@ synthesize_ior_xor (rtx_code code, rtx operands[3])
         of leading zeros after masking off all but the low 11 bits.  */
       int rotcount = clz_hwi (ival & 0x7ff) - (BITS_PER_WORD - 11);
 
-      /* Rotate the constant left by MSB bits.  */
-      ival = (ival << rotcount) | (ival >> (BITS_PER_WORD - rotcount));
+      /* Rotate the constant left by MSB bits.  Avoid undefined behavior if
+        rotcount is zero.  A rotcount of zero means there's no room to rotate
+        in bits.  We can just set ival to all ones so is rejected later with
+        the msb - lsb check.  */
+      if (rotcount != 0)
+       ival = (ival << rotcount) | (ival >> (BITS_PER_WORD - rotcount));
+      else
+       ival = HOST_WIDE_INT_M1U;
 
       /* Now we can do the same tests as before. */
       lsb = ctz_hwi (ival);
-      msb = BITS_PER_WORD - clz_hwi (ival);
+      msb = BITS_PER_WORD - 1 - clz_hwi (ival);
       if ((INTVAL (operands[2]) & HOST_WIDE_INT_UC (0x7ff)) != 0
          && msb - lsb + 1 <= 11)
        {
@@ -16524,7 +16530,7 @@ synthesize_and (rtx operands[3])
       && budget >= 3
       && consecutive_bits_operand (GEN_INT (~t), word_mode)
       && ((TARGET_ZBA && popcount_hwi (t) == 32)
-         || popcount_hwi (t) == 16
+         || (TARGET_ZBB && popcount_hwi (t) == 16)
          || popcount_hwi (t) <= 11))
     {
       /* First rotate the relevant bits into the low position.  */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 76a566520ff5..a913660d9511 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -811,6 +811,8 @@
       rtx t3 = gen_reg_rtx (<MODE>mode);
       rtx t4 = gen_reg_rtx (<MODE>mode);
 
+      operands[1] = make_safe_from (operands[1], operands[0]);
+      operands[2] = make_safe_from (operands[2], operands[0]);
       emit_insn (gen_add3_insn (operands[0], operands[1], operands[2]));
       rtx cmp1 = gen_rtx_LT (<MODE>mode, operands[2], const0_rtx);
       emit_insn (gen_cstore<mode>4 (t3, cmp1, operands[2], const0_rtx));
@@ -845,6 +847,7 @@
     }
   else
     {
+      operands[1] = make_safe_from (operands[1], operands[0]);
       emit_insn (gen_add3_insn (operands[0], operands[1], operands[2]));
       riscv_expand_conditional_branch (operands[3], LTU, operands[0],
                                       operands[1]);
@@ -993,6 +996,8 @@
       rtx t3 = gen_reg_rtx (<MODE>mode);
       rtx t4 = gen_reg_rtx (<MODE>mode);
 
+      operands[1] = make_safe_from (operands[1], operands[0]);
+      operands[2] = make_safe_from (operands[2], operands[0]);
       emit_insn (gen_sub3_insn (operands[0], operands[1], operands[2]));
 
       rtx cmp1 = gen_rtx_LT (<MODE>mode, operands[2], const0_rtx);
@@ -1030,6 +1035,7 @@
     }
   else
     {
+      operands[1] = make_safe_from (operands[1], operands[0]);
       emit_insn (gen_sub3_insn (operands[0], operands[1], operands[2]));
       riscv_expand_conditional_branch (operands[3], LTU, operands[1],
                                       operands[0]);
@@ -1451,6 +1457,8 @@
   "TARGET_DIV && riscv_use_divmod_expander ()"
   {
       rtx tmp = gen_reg_rtx (<MODE>mode);
+      operands[1] = make_safe_from (operands[1], operands[0]);
+      operands[2] = make_safe_from (operands[2], operands[0]);
       emit_insn (gen_<u>div<GPR:mode>3 (operands[0], operands[1], 
operands[2]));
       emit_insn (gen_mul<GPR:mode>3 (tmp, operands[0], operands[2]));
       emit_insn (gen_sub<GPR:mode>3 (operands[3], operands[1], tmp));
@@ -4962,7 +4970,7 @@
                   (match_operand:SI 4 "register_operand" "r"))))
    (clobber (match_scratch:DI 5 "=&r"))]
   "TARGET_64BIT
-   && (INTVAL (operands[3]) | ((1 << INTVAL (operands[2])) - 1)) == 0xffffffff"
+   && (INTVAL (operands[3]) | ((HOST_WIDE_INT_1U << INTVAL (operands[2])) - 
1)) == 0xffffffff"
   "#"
   "&& reload_completed"
   [(set (match_dup 5) (ashift:DI (match_dup 1) (match_dup 2)))
diff --git a/gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c 
b/gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c
new file mode 100644
index 000000000000..02ef91a22bc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+/* { dg-options "-march=rv64gc_zbkb -mabi=lp64d" } */
+
+unsigned long f_or  (unsigned long x) { return x | 0xF80000000000003Ful; }
+unsigned long f_xor (unsigned long x) { return x ^ 0xF80000000000003Ful; }
+
+/* { dg-final { scan-assembler-times "\tori\t\[a-z0-9\]+,\[a-z0-9\]+,2047" 1 } 
} */
+/* { dg-final { scan-assembler-times "\txori\t\[a-z0-9\]+,\[a-z0-9\]+,2047" 1 
} } */
+/* { dg-final { scan-assembler-times "\trori\t" 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zbkb-zext.c 
b/gcc/testsuite/gcc.target/riscv/zbkb-zext.c
new file mode 100644
index 000000000000..b856adf37837
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zbkb-zext.c
@@ -0,0 +1,3 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbkb -mabi=lp64" } */
+unsigned long f(unsigned long x){ return x & 0xFF000000000000FFul; }

Reply via email to