https://gcc.gnu.org/g:50adb5bb87d434467cf8d41b561a649db2473543
commit r17-411-g50adb5bb87d434467cf8d41b561a649db2473543 Author: Jeff Law <[email protected]> Date: Fri May 8 11:19:02 2026 -0600 [RISC-V][PR tree-optimization/93504] Handle (X & C) | ((X^Y) & ~C) -> X ^ ( Y & ~C) in simplify-rtx 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. 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: --- gcc/simplify-rtx.cc | 13 ++++++++----- gcc/testsuite/gcc.target/riscv/pr93504.c | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index bf625cdaf608..ee3d9ec32082 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 000000000000..149f111d35c2 --- /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" } } */
