This is Shreya's work, my contribution was primarily covering the
testing. Bootstrapped and regression tested on x86 and riscv64. It's
also been tested on all the embedded targets in my tester without
regression.
While this improves code generation to optimal on riscv-64, I'm electing
to keep the BZ open because we probably should have the same kind of
simplification in match.pd. Shreya is just starting to write some
match.pd patterns and I expect we'll return to write a match.pd pattern
for this issue relatively soon.
Obviously waiting for pre-commit CI to chime in before moving forward.
Jeff
--
In PR52345, we have this testcase:
int f(int a, int b)
{
int c = a != 0;
int d = (c!=0|b!=0);
return d;
}
Basically, "d" will either be 0 or 1. Depending on "a", "c" will also
either be 0 or 1. So if "a" is 0 and "b" is 0, then "d" will also be 0.
Otherwise, it will be 1.
When the testcase is compiled, we get this generated assembly code:
snez a0,a0
or a0,a1,a0
snez a0,a0
RISC-V has a missed optimization here, as this can simply be done by
first computing a|b and checking if the result is equal to 0. If "a" is
0 and "b" is 0, we will get 0. Otherwise, we will get 1. Doing this
removes the unnecessary first snez instruction.
When we looked at the combine pass, it was trying:
Failed to match this instruction:
(set (reg/i:DI 10 a0)
(ne:DI (ior:DI (ne:DI (reg:DI 151 [ a ])
(const_int 0 [0]))
(reg:DI 152 [ b ]))
(const_int 0 [0])))
In simplify_relational_operation_1 of simplify-rtx.cc, we added a
condition. For cases where the outer code is a "not equal to" (NE) and
the operands match the pattern above, we simply emit an NE of an IOR of
the two registers, giving us:
or a0,a0,a1
snez a0,a0
We then generalized this to include the case where the outer code is an
"equal to" (EQ). With the logic working in the same way, we simply
adjust the recognition code to check that the outer code is either an NE
or EQ and generalize the NE we emit to match the outer code.
--
PR target/52345
gcc/
* simplify-rtx.cc (simplify_relational_operation_1): Optimize boolean
IOR equality tests.
gcc/testsuite/
* gcc.target/riscv/pr52345.c: Add new test cases.
diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index b9591eb6bb71..989cf9c2c82f 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -6451,6 +6451,21 @@ simplify_context::simplify_relational_operation_1
(rtx_code code,
/* Canonicalize (LEU x 0) as (EQ x 0). */
if (code == LEU)
return simplify_gen_relational (EQ, mode, cmp_mode, op0, op1);
+
+ if ((code == NE || code == EQ)
+ /* Verify op0 is IOR */
+ && GET_CODE (op0) == IOR
+ /* only enters if op1 is 0 */
+ /* Verify IOR operand is NE */
+ && GET_CODE (XEXP (op0, 0)) == NE
+ /* Verfiy second NE operand is 0 */
+ && XEXP (XEXP (op0, 0), 1) == CONST0_RTX (mode))
+ {
+ rtx t = gen_rtx_IOR (mode, XEXP (XEXP (op0, 0), 0), XEXP (op0, 1));
+ t = gen_rtx_fmt_ee (code, mode, t, CONST0_RTX (mode));
+ return t;
+ }
+
}
else if (op1 == const1_rtx)
{
diff --git a/gcc/testsuite/gcc.target/riscv/pr52345.c
b/gcc/testsuite/gcc.target/riscv/pr52345.c
new file mode 100644
index 000000000000..9836dd078d79
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr52345.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gcbv_zicond -mabi=lp64d" { target { rv64 } } }
*/
+/* { dg-options "-O2 -march=rv32gcbv_zicond -mabi=ilp322" { target { rv32 } }
} */
+
+int f(int a, int b)
+{
+ int c = a != 0;
+ int d = (c!=0|b!=0);
+ return d;
+}
+
+int h (int a, int b)
+{
+ int c = (a!=0|b);
+ int d = c==0;
+ return d;
+}
+
+/* { dg-final { scan-assembler-times {\tor} 2 } } */
+/* { dg-final { scan-assembler-times {\tsnez} 1 } } */
+/* { dg-final { scan-assembler-times {\tseqz} 1 } } */