https://gcc.gnu.org/g:b2e7fd2c4fa3a8a094d03d71cdb2526f2a2dcbff
commit b2e7fd2c4fa3a8a094d03d71cdb2526f2a2dcbff Author: Shreya Munnangi <smunnan...@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 <j...@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 18c8e188f23b..eaaca3649835 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -14563,6 +14563,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]);