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])); })

Reply via email to