Another improvement for generating Zbs instructions.
In this case we're looking at stuff like (1 << N) | C where N varies and
C is a single bit constant.
In this pattern the (1 << N) happens in SImode, but is zero extended out
to DImode before the bit manipulation. The fact that we're modifying a
DImode object in the logical op is important as it means we don't have
to worry about whether or not the resulting value is sign extended from
SI to DI.
This has run through Ventana's CI system. I'll wait for it to roll
through pre-commit CI before moving forward.
Jeff
gcc/
* bitmanip.md ((1 << N) | C)): New splitter for IOR/XOR of
a single bit an a DImode object.
gcc/testsuite/
* gcc.target/riscv/zbs-zext.c: New test.
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 6c2736454aa..3cc244898e7 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -727,6 +727,21 @@ (define_insn "*bsetidisi"
"bseti\t%0,%1,%S2"
[(set_attr "type" "bitmanip")])
+;; We can easily handle zero extensions
+(define_split
+ [(set (match_operand:DI 0 "register_operand")
+ (any_or:DI (zero_extend:DI
+ (ashift:SI (const_int 1)
+ (match_operand:QI 1 "register_operand")))
+ (match_operand:DI 2 "single_bit_mask_operand")))
+ (clobber (match_operand:DI 3 "register_operand"))]
+ "TARGET_64BIT && TARGET_ZBS"
+ [(set (match_dup 3)
+ (match_dup 2))
+ (set (match_dup 0)
+ (any_or:DI (ashift:DI (const_int 1) (match_dup 1))
+ (match_dup 3)))])
+
(define_insn "*bclr<mode>"
[(set (match_operand:X 0 "register_operand" "=r")
(and:X (rotate:X (const_int -2)
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-zext.c
b/gcc/testsuite/gcc.target/riscv/zbs-zext.c
new file mode 100644
index 00000000000..5773b15d298
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zbs-zext.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */
+typedef unsigned long uint64_t;
+typedef unsigned int uint32_t;
+
+uint64_t bset (const uint32_t i)
+{
+ uint64_t checks = 8;
+ checks |= 1U << i;
+ return checks;
+}
+
+uint64_t binv (const uint32_t i)
+{
+ uint64_t checks = 8;
+ checks ^= 1U << i;
+ return checks;
+}
+
+uint64_t bclr (const uint32_t i)
+{
+ uint64_t checks = 10;
+ checks &= ~(1U << i);
+ return checks;
+}
+
+/* { dg-final { scan-assembler-times "bset\t" 1 } } */
+/* { dg-final { scan-assembler-times "binv\t" 1 } } */
+/* { dg-final { scan-assembler-times "bclr\t" 1 } } */
+/* { dg-final { scan-assembler-not "sllw\t"} } */