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.
Jeff
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. diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 18c8e188f23..24c7acab744 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]);