https://gcc.gnu.org/g:af13bb056c65532fc4b3cecd06f51f82a7c70149

commit r17-2119-gaf13bb056c65532fc4b3cecd06f51f82a7c70149
Author: Jeff Law <[email protected]>
Date:   Fri Jul 3 07:47:09 2026 -0600

    [RISC-V] Improve AND synthesis
    
    So a couple changes to AND synthesis.
    
    First much like the ADD, IOR/XOR cases we should be using riscv_integer_cost
    rather than riscv_const_insns.  This results in improvement for the exact 
same
    constants in the IOR/XOR case. This also introduces the ability to use 
rotation
    to help AND synthesis.
    
    Let's consider x & 0xff000000000000ff.  It currently generates this:
    
            li      a5,-1
            slli    a5,a5,56
            addi    a5,a5,255
            and     a0,a0,a5
    
    The trick here is to realize we only have 16 bits that are relevant and the 
can
    be clustered together.  So we rotate x right by 56 bit positions, then turn 
off
    the high bits using zext.h then rotate 8 more positions to put the bits back
    into the proper position.  That looks like this:
    
            rori    a0,a0,56
            zext.h  a0,a0
            rori    a0,a0,8
    
    We can also use zext.w and andi for the bit clearing step.
    
    Built and tested on riscv32-elf and riscv64-elf and bootstrapped + 
regression
    tested on the c920 and k3.  Waiting on pre-commit CI before moving forward.
    
    gcc/
            * config/riscv/riscv.cc (and_synthesis): Use riscv_integer_cost 
rather
            than riscv_const_insns.  Use rotate+clear_bits+rotate when useful.
    
    gcc/testsuite/
            * gcc.target/riscv/and-synthesis-3.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                        | 55 ++++++++++++++++++++++--
 gcc/testsuite/gcc.target/riscv/and-synthesis-3.c | 23 ++++++++++
 2 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index d31d4a8aeabf..d5d073f37a46 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -15949,7 +15949,7 @@ synthesize_and (rtx operands[3])
      execution and fusion in the constant synthesis those would naturally
      decrease the budget.  It also does not account for the AND at
      the end of the sequence which would increase the budget. */
-  int budget = riscv_const_insns (operands[2], true);
+  int budget = riscv_integer_cost (INTVAL (operands[2]), true);
   rtx input = NULL_RTX;
   rtx output = NULL_RTX;
 
@@ -16037,6 +16037,53 @@ synthesize_and (rtx operands[3])
       return true;
     }
 
+  /* Similarly if there's a run of 1s on the ends and all zeros in the middle
+     then rotation to get all the 1s in the mask into the LSB may result in
+     a SMALL_OPERAND or perhaps a mode mask.  In those cases its rotate,
+     mask, rotate back into position.  */
+  t = INTVAL (operands[2]);
+  if (TARGET_64BIT
+      && (TARGET_ZBB || TARGET_XTHEADBB || TARGET_ZBKB)
+      && budget >= 3
+      && consecutive_bits_operand (GEN_INT (~t), word_mode)
+      && ((TARGET_ZBA && popcount_hwi (t) == 32)
+         || popcount_hwi (t) == 16
+         || popcount_hwi (t) <= 11))
+    {
+      /* First rotate the relevant bits into the low position.  */
+      int count = BITS_PER_WORD - clz_hwi (~t);
+      rtx x = gen_rtx_ROTATERT (word_mode, operands[1], GEN_INT (count));
+      output = gen_reg_rtx (word_mode);
+      emit_insn (gen_rtx_SET (output, x));
+      input = output;
+
+      /* Now clear bits according to the mask.  */
+      if (popcount_hwi (t) == 32)
+       {
+         x = gen_rtx_ZERO_EXTEND (word_mode, gen_lowpart (SImode, input));
+         emit_insn (gen_rtx_SET (output, x));
+         input = output;
+       }
+      else if (popcount_hwi (t) == 16)
+       {
+         x = gen_rtx_ZERO_EXTEND (word_mode, gen_lowpart (HImode, input));
+         emit_insn (gen_rtx_SET (output, x));
+         input = output;
+       }
+      else
+       {
+         x = GEN_INT ((HOST_WIDE_INT_1U << popcount_hwi (t)) - 1);
+         x = gen_rtx_AND (word_mode, input, x);
+         emit_insn (gen_rtx_SET (output, x));
+         input = output;
+       }
+
+      /* Now we just need to rotate the bits back into position.  */
+      x = gen_rtx_ROTATERT (word_mode, input, GEN_INT (BITS_PER_WORD - 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]);
@@ -16098,9 +16145,9 @@ synthesize_and (rtx operands[3])
         we have Zbb, then we have ANDN.  So if the inverted constant
         is cheaper, invert it and use ANDN.  */
       if (TARGET_ZBB
-         && riscv_const_insns (GEN_INT (~UINTVAL (operands[2])), true) > 0
-         && (riscv_const_insns (operands[2], true)
-             > riscv_const_insns (GEN_INT (~UINTVAL (operands[2])), true)))
+         && riscv_integer_cost (~UINTVAL (operands[2]), true) > 0
+         && (riscv_integer_cost (UINTVAL (operands[2]), true)
+             > riscv_integer_cost (~UINTVAL (operands[2]), true)))
        {
          rtx x = force_reg (word_mode, GEN_INT (~UINTVAL (operands[2])));
          x = gen_rtx_NOT (word_mode, x);
diff --git a/gcc/testsuite/gcc.target/riscv/and-synthesis-3.c 
b/gcc/testsuite/gcc.target/riscv/and-synthesis-3.c
new file mode 100644
index 000000000000..c9b63aeec09d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/and-synthesis-3.c
@@ -0,0 +1,23 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" } */
+
+
+
+#define T(X) long andn##X(long x) { return x & X; }
+
+T(0x000200c3233fffffUL)
+T(0x300000000003ffffUL)
+T(0x00004f10000a0fffUL)
+T(0x0000c7f3801fefffUL)
+T(0xe00000000000fc00UL)
+T(0x0eef7ffffffbbfffUL)
+T(0xff0000000000ff00UL)
+T(0xff000000000000ffUL)
+T(0xfffff00000000fffUL)
+T(0xf00000000000000fUL)
+
+/* { dg-final { scan-assembler-times "\\tandn\\t" 7 } } */
+/* { dg-final { scan-assembler-times "\\trori\\t" 6 } } */
+/* { dg-final { scan-assembler-times "\\tzext.h\\t" 1 } } */
+/* { dg-final { scan-assembler-times "\\tzext.w\\t" 1 } } */
+/* { dg-final { scan-assembler-times "\\tandi\\t" 1 } } */

Reply via email to