https://gcc.gnu.org/g:892195ef99cb6cf899f480d13a125bb5bfe62313

commit r17-5506-g892195ef99cb6cf899f480d13a125bb5bfe62313
Author: Jeff Law <[email protected]>
Date:   Fri Oct 23 06:59:05 2026 -0600

    [RISC-V][PR target/121268] Fix splitter for pr121268
    
    This is a mis-compile caught by my LLM checker for machine descriptions.
    
    Basically the pattern in question has two operands, one in SI, one in DI 
that
    ultimately refer to the same pseudo register.  The pattern works fine when 
bits
    32..63 in that register are zero and generates incorrect code if any of 
those
    bits are set.
    
    Given its a define_split, we can condition splitting on nonzero_bits and get
    the benefit of the pattern most of the time which is precisely what this 
patch
    does.
    
    The existing test can't prove the nonzero bits quality we need for 2 of the 
24
    tests, so the counts are adjusted accordingly.  And an execution test is 
added
    which trips the bug.
    
    Assisted-By: LLM for pattern review and testcase generation
    
    Tested on riscv32-elf and riscv64-elf.  Bootstrap on K3, K1 and c920 are all
    queued.  Plan is to commit in the AM once I confirm the K3 and c920 
bootstrap +
    regression cycle were happy.
    
            PR target/121268
    gcc/
            * config/riscv/bitmanip.md ((x & -x) - 1 -> (x - 1) & ~x): Ensure
            input register has zeros in bits 32..63 for extended SI variant.
    
    gcc/testsuite
            * gcc.target/riscv/pr121268.c: Adjust expected output.
            * gcc.target/riscv/pr121268-2.c: New test.

Diff:
---
 gcc/config/riscv/bitmanip.md                |  2 ++
 gcc/testsuite/gcc.target/riscv/pr121268-2.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr121268.c   |  8 +++++++-
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index b35743d7f361..52cf0fccd8a1 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1527,6 +1527,8 @@
    (clobber (match_operand:DI 3 "register_operand"))]
   "(TARGET_64BIT
     && TARGET_ZBB
+    && (nonzero_bits (operands[2], DImode)
+       & HOST_WIDE_INT_UC (0xffffffff00000000)) == 0
     && (REG_P (operands[2]) && SUBREG_P (operands[1])
         ? REGNO (operands[2]) == REGNO (SUBREG_REG (operands[1]))
         : REG_P (operands[1]) && SUBREG_P (operands[2])
diff --git a/gcc/testsuite/gcc.target/riscv/pr121268-2.c 
b/gcc/testsuite/gcc.target/riscv/pr121268-2.c
new file mode 100644
index 000000000000..66ba94925b37
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr121268-2.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target rv64 } } */
+/* { dg-options "-O2 -march=rv64gc_zbb -mabi=lp64d" } */
+
+__attribute__ ((noipa)) long
+f (unsigned long y)
+{
+  unsigned int x = (unsigned int) y;
+  return (long) (int) ((x & -x) - 1u);
+}
+
+int
+main (void)
+{
+  if (f(0x100000000) != -1)
+    __builtin_abort ();
+  __builtin_exit (0);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/pr121268.c 
b/gcc/testsuite/gcc.target/riscv/pr121268.c
index d79f444d2f87..65f7f13ffdcf 100644
--- a/gcc/testsuite/gcc.target/riscv/pr121268.c
+++ b/gcc/testsuite/gcc.target/riscv/pr121268.c
@@ -36,4 +36,10 @@ F3 (signed long, sl)
 
 /* We match addi and addiw here on purpose.  */
 /* { dg-final { scan-assembler-times "addi" 24 } } */
-/* { dg-final { scan-assembler-times "andn\t" 24 } } */
+
+/* The transformation we want to apply for one class of test requires
+   nonzero bits information to be safe on rv64.  That information is
+   not available for the long of that test. Hence the difference
+   in andn instrutions seen across rv32 and rv64.  */
+/* { dg-final { scan-assembler-times "andn\t" 24 { target rv32 } } } */
+/* { dg-final { scan-assembler-times "andn\t" 22 { target rv64 } } } */

Reply via email to