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]);

Reply via email to