https://gcc.gnu.org/g:5601e5ce49fa66811bb065a53ff3007ea5c8a224
commit r17-5344-g5601e5ce49fa66811bb065a53ff3007ea5c8a224 Author: Jeff Law <[email protected]> Date: Mon Oct 19 09:21:23 2026 -0600 [RISC-V] Fix two RISC-V bitmanip bugs spotted by LLM review First in the recently added pattern which rewrites mask constants in AOP operations to encourage simplification or elimination of the AND mask, make sure not to touch the SI sign bit. We're taking an and+bclr+addiw sequence and turning it into bclr+ior. The former sign extends its result from bit 31 into bits 32..63, the latter sequence does not. The pattern is guarded on knowing we have 33+ sign bit copies in the nonconstant operand. What I missed was ensuring that the bit twiddle doesn't change the SI sign bit or any copies of the sign bit. The second case rewrites a slli+zext+shNadd into slli+shNadd.uw. It's similar to the slli+slliw pattern elsewhere in bitmanip.md. If we're not careful we can generate a negative shift count. I don't think we're seeing that in practice as the constants which generate that scenario bump the cost and we don't apply the transformation. But it's better to fix the pattern so that it works properly in case we fix the cost (which Shreya is working on). Both fixes have been bootstrapped and regression tested on the k3. The c920 wedged up again (common) and the k1 is queued waiting for a prior job to finish. Also tested on riscv32-elf and riscv64-elf. Pushing to the trunk. Assisted-By: LLM for bug hunting in bitmanip.md and review of my patch. gcc/ * config/riscv/bitmanip.md (shift_then_shNadd.uw): Ensure popcount of mask is < 32. (and+bclr+addiw -> bclr+ior splitter): Ensure the operation preserves the SI mode sign extension to DI. Diff: --- gcc/config/riscv/bitmanip.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index ab0bfb27c3c5..1027aa2dc066 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -192,6 +192,7 @@ (match_operand:DI 4 "register_operand" "r"))) (clobber (match_scratch:DI 5 "=&r"))] "TARGET_64BIT && TARGET_ZBA + && popcount_hwi (UINTVAL (operands[3])) < 32 && riscv_shamt_matches_mask_p (UINTVAL (operands[2]), UINTVAL (operands[3])) && IN_RANGE (clz_hwi (UINTVAL (operands[3])), 29, 31)" "#" @@ -1624,7 +1625,13 @@ "(TARGET_ZBS && (UINTVAL (operands[2]) & UINTVAL (operands[3])) == 0 && popcount_hwi (~(UINTVAL (operands[2]) | UINTVAL (operands[3]))) == 1 - && num_sign_bit_copies (operands[1], DImode) >= 33)" + && num_sign_bit_copies (operands[1], DImode) >= 33 + /* Be careful with the SI sign bit. We're relying on not changing the + sign bit or the extension in this transformation. */ + && ((UINTVAL (operands[2]) & HOST_WIDE_INT_C (0xffffffff80000000)) + == HOST_WIDE_INT_C (0xffffffff80000000)) + && ((UINTVAL (operands[3]) & HOST_WIDE_INT_C (0xffffffff80000000)) + == 0))" [(set (match_dup 0) (and:DI (match_dup 1) (match_dup 2))) (set (match_dup 0) (ior:DI (match_dup 0) (match_dup 3)))] { operands[2] = GEN_INT (UINTVAL (operands[2]) | UINTVAL (operands[3])); })
