This patch splits the canonical sign-bit checking idiom
into a 2-insn sequence when Zbb is available. Combine often normalizes
(xor (lshr A, (W - 1)) 1) to (ge A, 0). For width W = bitsize (mode), the
identity:

(a << 1) | (a >= 0)  ==  (a << 1) | ((a >> (W - 1)) ^ 1)  ==  ROL1 (a) ^ 1

lets us split:

(ior:X (ashift:X A 1) (ge:X A 0))

into:
  →  rotatert:X A, (W-1)
  →  xor:X        A, 1


2025-09-24  Dusan Stojkovic  <​[email protected]>

        PR target/121778

gcc/ChangeLog:

        * config/riscv/riscv.md: Add define_split pattern.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/pr121778-1.c: New test.
        * gcc.target/riscv/pr121778-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/riscv.md                   | 20 ++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr121778-1.c | 11 +++++++++++
 gcc/testsuite/gcc.target/riscv/pr121778-2.c | 11 +++++++++++
 3 files changed, 42 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr121778-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr121778-2.c

diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 2a3a20e122a..6ec62913f1b 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -4614,6 +4614,26 @@
     FAIL;
 })
 
+; Split (A<<1) | (A>=0) into a rotate + xor. Using two’s-complement 
identities:
+; (A>=0) == ((A >> (W-1)) ^ 1) and (A<<1) | (A>>(W-1)) == ROL1 (A), so the 
whole
+; expression equals ROL1 (A) ^ 1.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+     (ior:X
+       (ashift:X (match_operand:X 1 "register_operand")
+                 (const_int 1))
+               (ge:X (match_dup 1) (const_int 0))))]
+  "TARGET_ZBB"
+  [(set (match_dup 0)
+       (rotatert:X (match_dup 1) (match_operand 2 "const_int_operand")))
+   (set (match_dup 0)
+       (xor:X (match_dup 0) (const_int 1)))]
+  {
+    HOST_WIDE_INT rotval;
+    rotval = GET_MODE_BITSIZE (GET_MODE (operands[1])).to_constant () - 1;
+    operands[2] = GEN_INT (rotval);
+  })
+
 (define_insn "*large_load_address"
   [(set (match_operand:DI 0 "register_operand" "=r")
         (mem:DI (match_operand 1 "pcrel_symbol_operand" "")))]
diff --git a/gcc/testsuite/gcc.target/riscv/pr121778-1.c 
b/gcc/testsuite/gcc.target/riscv/pr121778-1.c
new file mode 100644
index 00000000000..2bb550a095a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr121778-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { rv32 } } } */
+/* { dg-options "-march=rv32gc_zbb -mabi=ilp32 -O2" } */
+
+unsigned int
+foo (unsigned int a)
+{
+  return (a << 1) | ((a >> 31) ^ 1);
+}
+
+ /* { dg-final { scan-assembler {\mrori} } } */
+ /* { dg-final { scan-assembler {\mxori} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/pr121778-2.c 
b/gcc/testsuite/gcc.target/riscv/pr121778-2.c
new file mode 100644
index 00000000000..a9460adeda5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr121778-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-options "-march=rv64gc_zbb -mabi=lp64 -O2" } */
+
+unsigned long
+foo (unsigned long a)
+{
+  return (a << 1) | ((a >> 63) ^ 1);
+}
+
+ /* { dg-final { scan-assembler {\mrori} } } */
+ /* { dg-final { scan-assembler {\mxori} } } */
-- 
2.43.0

Reply via email to