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" } } */

Reply via email to