Fold redundant count masks in inverted bit extraction using define_split.
Across the baseline and Zbs-only builds, C/C++ selftests and RV32/RV64
QEMU checks passed: 48 correctness runs and 8 benchmark binaries.
Performance was measured in 16 gem5 Minor/O3 runs.
For the RV64 microkernel, gem5 instruction counts decreased 11.11%;
cycles decreased 9.99% on Minor and 14.27% on O3. K1 reductions were
11.12% in instructions and 14.31% in cycles, from 15 paired measurements.
Changes in v2:
Use define_split, as suggested by Jeff.
gcc/ChangeLog:
* config/riscv/bitmanip.md: Add a splitter for masked inverted
bit extraction.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zbs-bext-3.c: New test.
---
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index
d710d594def0fcc41a6109c9eadef7704d24486e..4d390a7fab0638579d111e029e3651f04d2c95c7
100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -1101,6 +1101,32 @@
"operands[1] = gen_lowpart (word_mode, operands[1]);"
[(set_attr "type" "bitmanip")])
+;; Split inverted bit extraction with a masked count into bext and seqz.
+(define_split
+ [(set (match_operand:X 0 "register_operand")
+ (and:X
+ (not:X
+ (lshiftrt:X
+ (match_operand:X 1 "register_operand")
+ (match_operator 4 "subreg_lowpart_operator"
+ [(and:GPR (match_operand:GPR 2 "register_operand")
+ (match_operand 3 "<X:shiftm1>"))])))
+ (const_int 1)))]
+ "TARGET_ZBS"
+ [(set (match_dup 0)
+ (zero_extract:X (match_dup 1)
+ (const_int 1)
+ (match_dup 4)))
+ (set (match_dup 0) (eq:X (match_dup 0) (const_int 0)))]
+{
+ /* Keep the bit position in range in the split RTL. The masked bext
+ patterns omit this mask when emitting the instruction. */
+ operands[4] = gen_rtx_AND (<GPR:MODE>mode, operands[2],
+ GEN_INT (GET_MODE_BITSIZE (<X:MODE>mode) - 1));
+ if (<GPR:MODE>mode != <X:MODE>mode)
+ operands[4] = gen_rtx_ZERO_EXTEND (<X:MODE>mode, operands[4]);
+})
+
;; The logical-and against 0x1 implicitly extends the result. So we can treat
;; an SImode bext as-if it's DImode without any explicit extension.
(define_insn "*bextdisi"
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-bext-3.c
b/gcc/testsuite/gcc.target/riscv/zbs-bext-3.c
new file mode 100644
index
0000000000000000000000000000000000000000..cf4287c11b3a2a09df0f23fbc7a1b5d73eca365b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zbs-bext-3.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc_zbs -mabi=ilp32" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+unsigned long
+foo (unsigned long x, unsigned int n)
+{
+ return (~(x >> (n & (__riscv_xlen - 1)))) & 1UL;
+}
+
+/* A narrower mask must be retained. */
+unsigned long
+bar (unsigned long x, unsigned int n)
+{
+ return (~(x >> (n & 7))) & 1UL;
+}
+
+/* { dg-final { scan-assembler-times "bext\t" 2 } } */
+/* { dg-final { scan-assembler-times "seqz\t|xori\t" 2 } } */
+/* { dg-final { scan-assembler-times "andi\t" 1 } } */