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 } } } */
