Another case of being able to safely use bset for 1 << n. In this case the (1 << n) is explicitly zero extended from SI to DI. Two things to keep in mind. The (1 << n) is done in SImode. So it doesn't directly define bits 32..63 and those bits are cleared by the explicit zero extension. Second if N is out of SImode's range, then the original source level construct was undefined.

Thus we can use bset with x0 as our source input.

I think this testcase was from the RAU team. It doesn't immediately look like something from SPEC, but that's where they were primarily focused.

This has been through Ventana's CI system in the past. I've also recently added zbs testing to my own tester and naturally this passed there as well. I'll wait for the pre-commit CI to do its thing before moving forward. The plan would be to commit after passing.



Jeff

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 0d35fb786e1..311f0d373c0 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -597,6 +597,18 @@ (define_insn "*bset<mode>_1"
   "bset\t%0,x0,%1"
   [(set_attr "type" "bitmanip")])
 
+;; The result will always have bits 32..63 clear, so the zero-extend
+;; is redundant.  We could split it to bset<mode>_1, but it seems
+;; unnecessary.
+(define_insn "*bsetdi_2"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (zero_extend:DI
+         (ashift:SI (const_int 1)
+                    (match_operand:QI 1 "register_operand" "r"))))]
+  "TARGET_64BIT && TARGET_ZBS"
+  "bset\t%0,x0,%1"
+  [(set_attr "type" "bitmanip")])
+
 (define_insn "*bset<mode>_1_mask"
   [(set (match_operand:X 0 "register_operand" "=r")
        (ashift:X (const_int 1)
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-zext-2.c 
b/gcc/testsuite/gcc.target/riscv/zbs-zext-2.c
new file mode 100644
index 00000000000..ebd269d1695
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zbs-zext-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */
+unsigned long long foo(long long symbol)
+{
+        return 1u << symbol;
+}
+
+/* { dg-final { scan-assembler-times "bset\t" 1 } } */
+/* { dg-final { scan-assembler-not "li\t"} } */
+/* { dg-final { scan-assembler-not "sllw\t"} } */
+/* { dg-final { scan-assembler-not "zext.w\t"} } */

Reply via email to