]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V][PR tree-optimization/93504] Handle (X & C) | ((X^Y) & ~C) -> X ^ ( Y & ...
authorJeff Law <jeffrey.law@oss.qualcomm.com>
Fri, 8 May 2026 17:19:02 +0000 (11:19 -0600)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Fri, 8 May 2026 17:19:02 +0000 (11:19 -0600)
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.

gcc/simplify-rtx.cc
gcc/testsuite/gcc.target/riscv/pr93504.c [new file with mode: 0644]

index bf625cdaf608e7e64de6ad16ca4e1e73b771b834..ee3d9ec32082954af577bd31ad503de06bc6c07c 100644 (file)
@@ -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 (file)
index 0000000..149f111
--- /dev/null
@@ -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" } } */