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

commit r17-2015-gd082f8f075aae207884370f96f27222e85d50c32
Author: Jeff Law <[email protected]>
Date:   Tue Jun 30 07:38:23 2026 -0600

    [RISC-V] Improve logicals when ~C is cheaper to synthesize than C when Zbb 
is enabled
    
    This patch covers another set of cases where we can improve synthesis of
    logical operations spotted by comparing LLVM and GCC generated code.
    
    With Zbb, we have andn, orn and xnor.  Right now we rely on combine to 
identify
    cases where the inverted constant is cheaper to produce than the original
    constant and then invert things via define_insn_and_split patterns.
    
    This interacts particularly poorly with mvconst_internal and we're generally
    moving towards trying to generate better code earlier in the RTL pipeline
    rather relying so much on combine to clean things up later.
    
    So in the logical synthesis code, if we've determined constant synthesis is
    necessary and Zbb is enabled, then we query to the cost on the original
    constant C and the adjusted constant ~C.  If ~C is cheaper to synthesize, 
then
    use that in combination with andn, orn or xnor.
    
    Bootstrapped and regression tested on the K3, the c920 is in flight.  Also
    tested on riscv64-elf and riscv32-elf without regressions.  As usual waiting
    for pre-commit CI to do its thing.
    
    gcc/
            * config/riscv/riscv.cc (synthesize_ior_xor): If we must synthesize 
a
            constant and Zbb is enabled, try both C and ~C to see which is 
cheaper.
            (synthesize_and): Likewise.
    
    gcc/testsuite
            * gcc.target/riscv/and-synthesis-2.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                        | 41 ++++++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/and-synthesis-2.c | 13 ++++++++
 2 files changed, 54 insertions(+)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index c2d64f63c491..d5eab5421318 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -15836,6 +15836,32 @@ synthesize_ior_xor (rtx_code code, rtx operands[3])
      is complete. */
   if (budget < 0)
     {
+      /* We're going to have to synthesize the constant.  However, if
+        we have Zbb, then we have XNOR and ORN.  So if the inverted constant
+        is cheaper, invert it and use XNOR/ORN.  */
+      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)))
+       {
+         rtx x = force_reg (word_mode, GEN_INT (~UINTVAL (operands[2])));
+
+         /* Unfortunately canonical forms vary here.  */
+         if (code == IOR)
+           {
+             x = gen_rtx_NOT (word_mode, x);
+             x = gen_rtx_IOR (word_mode, x, operands[1]);
+           }
+         else
+           {
+             x = gen_rtx_XOR (word_mode, x, operands[1]);
+             x = gen_rtx_NOT (word_mode, x);
+           }
+
+         emit_insn (gen_rtx_SET (operands[0], x));
+         return true;
+       }
+
       rtx x = force_reg (word_mode, operands[2]);
       x = gen_rtx_fmt_ee (code, word_mode, operands[1], x);
       emit_insn (gen_rtx_SET (operands[0], x));
@@ -16069,6 +16095,21 @@ synthesize_and (rtx operands[3])
      patch in the series is enabled.  */
   if (ival || budget < 0)
     {
+      /* We're going to have to synthesize the constant.  However, if
+        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)))
+       {
+         rtx x = force_reg (word_mode, GEN_INT (~UINTVAL (operands[2])));
+         x = gen_rtx_NOT (word_mode, x);
+         x = gen_rtx_AND (word_mode, x, operands[1]);
+         emit_insn (gen_rtx_SET (operands[0], x));
+         return true;
+       }
+
       rtx x = force_reg (word_mode, operands[2]);
       x = gen_rtx_AND (word_mode, operands[1], x);
       emit_insn (gen_rtx_SET (operands[0], x));
diff --git a/gcc/testsuite/gcc.target/riscv/and-synthesis-2.c 
b/gcc/testsuite/gcc.target/riscv/and-synthesis-2.c
new file mode 100644
index 000000000000..e56a672dc2a2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/and-synthesis-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target rv64 } } */
+/* { dg-options "-march=rv64gcb -mabi=lp64d" } */
+
+unsigned long xor(unsigned long x) { return x ^ 0xfff0000000000fffULL; }
+unsigned long ior(unsigned long x) { return x | 0xfff0000000000fffULL; }
+unsigned long and(unsigned long x) { return x & 0xfff0000000000fffULL; }
+
+/* { dg-final { scan-assembler-times "\\tli\\t" 3 } } */
+/* { dg-final { scan-assembler-times "\\tsrli\t" 3 } } */
+
+/* { dg-final { scan-assembler-times "\\txnor\t" 1 } } */
+/* { dg-final { scan-assembler-times "\\torn\t" 1 } } */
+/* { dg-final { scan-assembler-times "\\tandn\t" 1 } } */

Reply via email to