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