https://gcc.gnu.org/g:9613bdb1922e62e20da5a2893d27a9f6ef296afc

commit r17-5060-g9613bdb1922e62e20da5a2893d27a9f6ef296afc
Author: Jeff Law <[email protected]>
Date:   Sun Oct 11 08:43:39 2026 -0600

    [RISC-V] Fix pr58727 code quality regression on RISC-V
    
    Essentially we have an outer IOR with turns on one or more bits that were
    masked off by an inner AND.  Previously we'd potentially turn those bits 
back
    on in the AND mask in the hopes the constant would simplify (ideally into a
    single bit clear constant).  So instead of bclr+ior were now getting
    and+bclr+plus (and clears low bits, bclr clears a high bit, plus turns on 
the
    just cleared low bits).
    
    The steering towards PLUS broke that code.  I tried to fix in simplify-rtx, 
but
    things kept getting mucked up as we bubbled out of the various SUBST and
    simplification calls in combine which is unfortunate as other ports that are
    limited to single bit manipulation rather than generalized bitfields could
    benefit.  Also note that since we're dropping that inner AND, we have to 
change
    the outer operation back to IOR to keep the semantics correct.
    
    After much head-banging I gave in and implemented it in the RISC-V backend 
;(
    
    Bootstrapped and regression tested on the c920 and k3 (k1 is in progress).
    Also regression tested on riscv32-elf and riscv64-elf.
    
    gcc/
            * config/riscv/bitmanip.md: Add new 3->2 splitter when an outer PLUS
            turns on some bits cleared by an inner AND.  Adjust the AND mask and
            change the outer code to IOR.

Diff:
---
 gcc/config/riscv/bitmanip.md | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 55bbf304bffd..af4718332446 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1646,3 +1646,28 @@
   [(set_attr "type" "shift")
    (set_attr "mode" "DI")])
 
+;; This is meant to fix minor regressions once the any-or-plus changes went
+;; in.  Essentially if the PLUS (IOR/XOR) sets bits that are off in the mask
+;; then we can turn those bits back on in the AND mask and hopefully produce
+;; a simpler constant (suitable for bclri) and convert the PLUS back to IOR
+;; (so as not to trigger carries if the original bit was on in the operand).
+;;
+;; This results in a bclr+ior rather than and+bclr+addiw
+;;
+;; I started to to implement this in simplify-rtx.cc, but the interactions
+;; with combine were complex.  It would likely still be helpful, particularly
+;; on targets with single bit manipulations similar to RISC-V
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+       (sign_extend:DI
+        (oxp:SI (subreg:SI (and:DI (match_operand:DI 1 "register_operand")
+                                   (match_operand 2 "const_int_operand")) 0)
+                 (match_operand 3 "const_int_operand"))))]
+  "(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)"
+  [(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