This is a trivial generalization of existing simplify-rtx code.
Essentially the code in question was handling IOR, but not XOR. I'm
keeping the bz open as this probably should have been cleaned up before
getting into RTL.
The net is something like this:
#define N 0x202
#define OP ^
unsigned f(unsigned a, unsigned b)
{
unsigned t = a OP b;
unsigned t1 = t&N;
unsigned t2 = a&~N;
return t1 | t2;
}
Originally compiled into:
xor a1,a0,a1
andi a1,a1,514
andi a0,a0,-515
or a0,a1,a0
ret
After it compiles into:
andi a1,a1,514
xor a0,a1,a0
ret
Bootstrapped and regression tested on x86, aarch64 and various targets
in qemu. Also tested on the usual embedded targets.
Jeff
PR tree-optimization/93504
gcc/
* simplify-rtx.cc (simplify_context::simplify_binary_operation_1):
Generalize existing code for (X & C) | ((X|Y) & ~C) to handle
(X & C) | ((X^Y) & ~C) as well.
gcc/testsuite
* gcc.target/riscv/pr93504.c: New test.
diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index bf625cdaf60..ee3d9ec3208 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -3854,15 +3854,17 @@ simplify_context::simplify_binary_operation_1 (rtx_code
code,
&& (INTVAL (XEXP (op0, 1))
== ~INTVAL (XEXP (op1, 1))))
{
- /* The IOR may be on both sides. */
+ /* The IOR/XOR may be on both sides. */
rtx top0 = NULL_RTX, top1 = NULL_RTX;
- if (GET_CODE (XEXP (op1, 0)) == IOR)
+ if (GET_CODE (XEXP (op1, 0)) == IOR
+ || GET_CODE (XEXP (op1, 0)) == XOR)
top0 = op0, top1 = op1;
- else if (GET_CODE (XEXP (op0, 0)) == IOR)
+ else if (GET_CODE (XEXP (op0, 0)) == IOR
+ || GET_CODE (XEXP (op0, 0)) == XOR)
top0 = op1, top1 = op0;
if (top0 && top1)
{
- /* X may be on either side of the inner IOR. */
+ /* X may be on either side of the inner IOR/XOR. */
rtx tem = NULL_RTX;
if (rtx_equal_p (XEXP (top0, 0),
XEXP (XEXP (top1, 0), 0)))
@@ -3871,7 +3873,8 @@ simplify_context::simplify_binary_operation_1 (rtx_code
code,
XEXP (XEXP (top1, 0), 1)))
tem = XEXP (XEXP (top1, 0), 0);
if (tem)
- return simplify_gen_binary (IOR, mode, XEXP (top0, 0),
+ return simplify_gen_binary (GET_CODE (XEXP (top1, 0)),
+ mode, XEXP (top0, 0),
simplify_gen_binary
(AND, mode, tem, XEXP (top1, 1)));
}
diff --git a/gcc/testsuite/gcc.target/riscv/pr93504.c
b/gcc/testsuite/gcc.target/riscv/pr93504.c
new file mode 100644
index 00000000000..149f111d35c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr93504.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gc_zicond -mabi=lp64d" { target rv64 }
} */
+/* { dg-additional-options "-march=rv32gc_zicond -mabi=ilp32" { target rv32 }
} */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Og" } } */
+
+#define N 0x202
+#define OP ^
+
+unsigned f(unsigned a, unsigned b)
+{
+ unsigned t = a OP b;
+ unsigned t1 = t&N;
+ unsigned t2 = a&~N;
+ return t1 | t2;
+}
+
+/* { dg-final { scan-assembler-times "andi\t" 1 } } */
+/* { dg-final { scan-assembler-times "xor\t" 1 } } */
+/* { dg-final { scan-assembler-not "\tor\t" } } */