From: Dusan Stojkovic Date: Wed, 24 Sep 2025 21:11:58 +0000 (-0600) Subject: [PATCH][PR target/121778] RISC-V: Improve rotation detection for RISC-V X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d53f7ad85e8aefc6f0cdc0dd2f541db59d1a0cd2;p=thirdparty%2Fgcc.git [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. --- diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 2a3a20e122a..843a048e9d8 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} } } */