[PATCH][PR target/121778] RISC-V: Improve rotation detection for RISC-V

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

	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.
This commit is contained in:
Dusan Stojkovic
2025-09-24 15:11:58 -06:00
committed by Jeff Law
parent dfbce1feae
commit d53f7ad85e
3 changed files with 42 additions and 0 deletions

View File

@@ -4614,6 +4614,26 @@
FAIL;
})
; Split (A<<1) | (A>=0) into a rotate + xor. Using twos-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" "")))]

View File

@@ -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} } } */

View File

@@ -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} } } */