[gcc(refs/vendors/riscv/heads/gcc-15-with-riscv-opts)] [RISC-V] shift+and+shift for logical and synthesis
Jeff Law
law@gcc.gnu.org
Sat Jan 17 06:54:12 GMT 2026
https://gcc.gnu.org/g:edc2eca95b35a444b310790990757d583d6f6ed9
commit edc2eca95b35a444b310790990757d583d6f6ed9
Author: Shreya Munnangi <smunnangi1@ventanamicro.com>
Date: Sat May 24 13:52:55 2025 -0600
[RISC-V] shift+and+shift for logical and synthesis
The next chunk of Shreya's work.
For this expansion we want to detect cases when the mask fits in a simm12 after
shifting right by the number of trailing zeros in the mask.
In that case we can synthesize the AND with a shift right, andi and shift left.
I saw this case come up when doing some experimentation with mvconst_internal
removed.
This doesn't make any difference in spec right now, mvconst_internal will turn
the sequence back into a constant load + and with register. But Shreya and I
have reviewed the .expand dump on hand written tests and verified we're getting
the synthesis we want.
Tested on riscv32-elf and riscv64-elf. Waiting on upstream CI's verdict before
moving forward.
gcc/
* config/riscv/riscv.cc (synthesize_and): Use a srl+andi+sll
sequence when the mask fits in a simm12 after shifting by the
number of trailing zeros.
Co-authored-by: Jeff Law <jlaw@ventanamicro.com>
(cherry picked from commit 2e2557d160cc0b893a7bcad1bee1683ad948dc60)
Diff:
---
gcc/config/riscv/riscv.cc | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index f5bfeafbb0f0..ce5090392609 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -14581,6 +14581,36 @@ synthesize_and (rtx operands[3])
return true;
}
+ /* If we shift right to eliminate the trailing zeros and
+ the result is a SMALL_OPERAND, then it's a shift right,
+ andi and shift left. */
+ t = INTVAL (operands[2]);
+ t >>= ctz_hwi (t);
+ if (budget >= 3 && SMALL_OPERAND (t) && popcount_hwi (t) > 2)
+ {
+ /* Shift right to clear the low order bits. */
+ unsigned HOST_WIDE_INT count = ctz_hwi (INTVAL (operands[2]));
+ rtx x = gen_rtx_LSHIFTRT (word_mode, operands[1], GEN_INT (count));
+ output = gen_reg_rtx (word_mode);
+ emit_insn (gen_rtx_SET (output, x));
+ input = output;
+
+ /* Now emit the ANDI. */
+ unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
+ mask >>= ctz_hwi (mask);
+ x = gen_rtx_AND (word_mode, input, GEN_INT (mask));
+ output = gen_reg_rtx (word_mode);
+ emit_insn (gen_rtx_SET (output, x));
+ input = output;
+
+ /* Shift left to move bits into position. */
+ count = INTVAL (operands[2]);
+ count = ctz_hwi (count);
+ x = gen_rtx_ASHIFT (word_mode, input, GEN_INT (count));
+ emit_insn (gen_rtx_SET (operands[0], x));
+ return true;
+ }
+
/* If there are all zeros, except for a run of 1s somewhere in the middle
of the constant, then this is at worst 3 shifts. */
t = INTVAL (operands[2]);
More information about the Gcc-cvs
mailing list