This patch contains 1 split and 1 insn_and_split pattern:

The define_split handles 3rd case (shafinish).  On RV64
~(1 << n) for an int n is computed in SImode and sign-extended to
DImode.  If the other operand has no bits set above bit 30,
the sign extension does not matter, and the AND
can be rewritten with (rotate (const_int -2) n), which matches bclr.

void shafinish(unsigned char *block, int blockcnt)
{
    block[blockcnt] |= (0x01 << (blockcnt));
    block[blockcnt] &= ~(0x01 << (blockcnt));
}

before:
    add     a0,a0,a1
     lbu     a4,0(a0)
     li      a5,1
     sllw    a5,a5,a1
     andn    a5,a4,a5
     sb      a5,0(a0)

after:
     add  a0,a0,a1
     lbu  a5,0(a0)
     bclr t0,a5,a1
     sb   t0,0(a0)

The define_insn_and_split removes the redundant andi in the 1st
example (shabits). The shift count is (~x) & C, which
is at most C, so when C < log2 (M + 1) the bit always lies inside the
mask M and the AND is a no-op.  The pattern splits into li/andn/bset.

There should be a 2nd patch that covers the GIMPLE side of the problem
for the 1st and 2nd example.

Regression tested on riscv64.

2026-10-21  Milan Tripkovic  <[email protected]>

      PR target/124020

gcc/ChangeLog:

      *config/riscv/bitmanip.md (bset_andn_masked): new pattern

gcc/testsuite/ChangeLog:

      *gcc.target/riscv/pr124020-1.c: New test.
      *gcc.target/riscv/pr124020-2.c: New test.





CONFIDENTIALITY: The contents of this e-mail are confidential and intended only 
for the above addressee(s). If you are not the intended recipient, or the 
person responsible for delivering it to the intended recipient, copying or 
delivering it to anyone else or using it in any unauthorized manner is 
prohibited and may be unlawful. If you receive this e-mail by mistake, please 
notify the sender and the systems administrator at [email protected] 
immediately.
---
 gcc/config/riscv/bitmanip.md                | 38 +++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr124020-1.c | 20 +++++++++++
 gcc/testsuite/gcc.target/riscv/pr124020-2.c | 28 +++++++++++++++
 3 files changed, 86 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr124020-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr124020-2.c

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 1027aa2dc06..0136ea7d8b3 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -740,6 +740,44 @@
   { operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); }
   [(set_attr "type" "bitmanip")])
 
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+       (and:DI (not:DI (sign_extend:DI
+                         (ashift:SI (const_int 1)
+                                    (match_operand:QI 1 "register_operand"))))
+               (match_operand:DI 2 "register_operand")))]
+  "TARGET_64BIT && TARGET_ZBS
+   && (nonzero_bits (operands[2], DImode)
+       & ~HOST_WIDE_INT_C (0x7fffffff)) == 0"
+  [(set (match_dup 0)
+       (and:DI (rotate:DI (const_int -2) (match_dup 1))
+               (match_dup 2)))])
+
+(define_insn_and_split "*bset_andn_masked"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (and:DI
+         (ashift:DI
+           (const_int 1)
+           (subreg:QI
+             (and:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
+                     (match_operand:DI 2 "const_int_operand" "n")) 0))
+         (match_operand:DI 3 "const_int_operand" "n")))
+   (clobber (match_scratch:DI 4 "=&r"))]
+  "TARGET_64BIT && TARGET_ZBS && (TARGET_ZBB || TARGET_ZBKB)
+   && exact_log2 (UINTVAL (operands[3]) + 1) > 0
+   && UINTVAL (operands[2])
+      < (unsigned HOST_WIDE_INT) exact_log2 (UINTVAL (operands[3]) + 1)"
+  "#"
+  "&& 1"
+  [(set (match_dup 4) (match_dup 2))
+   (set (match_dup 4) (and:DI (not:DI (match_dup 1)) (match_dup 4)))
+   (set (match_dup 0) (ashift:DI (const_int 1) (subreg:QI (match_dup 4) 0)))]
+{
+  if (GET_CODE (operands[4]) == SCRATCH)
+    operands[4] = gen_reg_rtx (DImode);
+}
+  [(set_attr "type" "bitmanip")])
+
 ;; Similarly two patterns for IOR/XOR generating bset/binv to
 ;; manipulate a bit in a register
 (define_insn_and_split ""
diff --git a/gcc/testsuite/gcc.target/riscv/pr124020-1.c 
b/gcc/testsuite/gcc.target/riscv/pr124020-1.c
new file mode 100644
index 00000000000..eec0d0562e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr124020-1.c
@@ -0,0 +1,20 @@
+/* PR rtl-optimization/124020 */
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-O2 -march=rv64gc_zbb_zbs -mabi=lp64d" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" } } */
+
+void
+shafinish (unsigned char *block, int blockcnt)
+{
+  block[blockcnt] |= (0x01 << (blockcnt));
+  block[blockcnt] &= ~(0x01 << (blockcnt));
+}
+
+void
+clr_short (unsigned short *p, int n)
+{
+  *p &= ~(1 << n);
+}
+
+/* { dg-final { scan-assembler-times {\mbclr\M} 2 } } */
+/* { dg-final { scan-assembler-not {\msllw\M} } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/pr124020-2.c 
b/gcc/testsuite/gcc.target/riscv/pr124020-2.c
new file mode 100644
index 00000000000..06d367e0808
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr124020-2.c
@@ -0,0 +1,28 @@
+/* PR rtl-optimization/124020 */
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-O2 -march=rv64gc_zbb_zbs -mabi=lp64d -mtune=rocket" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" "-Os" "-Oz" } } */
+
+typedef struct SHA {
+  unsigned char block[128];
+  unsigned int blockcnt;
+} SHA;
+
+#define BITSET(s, pos) s[(pos) >> 3] &  (char)  (0x01 << (7 - (pos) % 8))
+#define SETBIT(s, pos) s[(pos) >> 3] |= (char)  (0x01 << (7 - (pos) % 8))
+#define CLRBIT(s, pos) s[(pos) >> 3] &= (char) ~(0x01 << (7 - (pos) % 8))
+
+void
+shabits (char *bitstr, long bitcnt, SHA *s)
+{
+  unsigned long i;
+  for (i = 0UL; i < bitcnt; i++)
+    {
+      if (BITSET (bitstr, i))
+       SETBIT (s->block, s->blockcnt);
+      else
+       CLRBIT (s->block, s->blockcnt);
+    }
+}
+
+/* { dg-final { scan-assembler-not {\mandi\M[^\n]*0xff} } } */
\ No newline at end of file
-- 
2.34.1

Reply via email to