]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V] shift+and+shift for logical and synthesis
authorShreya Munnangi <smunnangi1@ventanamicro.com>
Sat, 24 May 2025 19:52:55 +0000 (13:52 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Sat, 24 May 2025 19:55:12 +0000 (13:55 -0600)
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>
gcc/config/riscv/riscv.cc

index 18c8e188f23b73bfd1befbbedcf188191df65673..eaaca36498350e8d12ee2b4eb8c0843d339aaa9b 100644 (file)
@@ -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]);