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.
Jeff
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 --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index dda17887019d..10f11d5f4007 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -15831,6 +15831,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));
@@ -16064,6 +16090,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 } } */