]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
simplify-rtx: Simplify (cmp (and/ior x C1) C2)
authorBohan Lei <garthlei@linux.alibaba.com>
Tue, 31 Mar 2026 07:27:05 +0000 (15:27 +0800)
committerBohan Lei <garthlei@linux.alibaba.com>
Tue, 28 Apr 2026 09:17:35 +0000 (17:17 +0800)
This is v6 of
https://gcc.gnu.org/pipermail/gcc-patches/2026-March/711809.html, fixed
and enhanced as was suggested by Philipp and Andrew.  The previous
version:
https://gcc.gnu.org/pipermail/gcc-patches/2026-April/714878.html.
Andrew noticed the x86 regression and suggested updating the testcase.

This patch adds missing simplifications for (cmp (and/ior x C1) C2) in
special cases.  In the AND case, when (and C1 C2) is not equal to C1,
some bits set in C2 are not set in C1, and thus (eq (and x C1) C2) can
never be true.  The OR case is similar when (and C1 C2) is not equal to
C2.  As we know that the result of (and x C1) cannot be greater than C1,
and that that of (or x C1) cannot be less than C1 for unsigned integers,
LTU, LEU, GTU, GEU cases can be optimized, too.

The patch is meant to fix an ICE on RISC-V.  In a former patch, I tried
to change the insn condition directly, but Jeff pointed out that it was
more reasonable to optimize it out before the split.  As was suggested
by Jeff, this patch tries to simplify the expression in
simplify_relational_operation_1.

The URL for the former patch:
https://patchwork.sourceware.org/project/gcc/patch/20251229024238.15044-1-garthlei@linux.alibaba.com/

gcc/ChangeLog:

* simplify-rtx.cc (simplify_context::simplify_relational_operation_1):
Add simplifications for `(cmp (and/ior x C1) C2)`.

gcc/testsuite/ChangeLog:

* gcc.target/i386/pr113609-1.c: Change assembly check after
optimization.
* gcc.target/riscv/zbs-if_then_else-02.c: New test.

gcc/simplify-rtx.cc
gcc/testsuite/gcc.target/i386/pr113609-1.c
gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c [new file with mode: 0644]

index 73363a77a4e034df7ab34e54618a397146d1aa3a..a87d91884dfaad5be3c157c8190c690478d0ed4a 100644 (file)
@@ -6747,6 +6747,51 @@ simplify_context::simplify_relational_operation_1 (rtx_code code,
        }
     }
 
+  /* Optimize (cmp (and/ior x C1) C2) depending on the CMP and C1 and C2's
+     relationship.  */
+  if ((op0code == AND || op0code == IOR)
+      && CONST_INT_P (op1)
+      && CONST_INT_P (XEXP (op0, 1)))
+    {
+      unsigned HOST_WIDE_INT c1 = UINTVAL (XEXP (op0, 1));
+      unsigned HOST_WIDE_INT c2 = UINTVAL (op1);
+
+      /* For AND operations:
+          - (x & c1) == c2 when some bits are set in c2 but not in c1 -> false
+          - (x & c1) != c2 when some bits are set in c2 but not in c1 -> true
+          - (x & c1) >= c2 when c1 is less than c2 -> false
+          - (x & c1) < c2 when c1 is less than c2 -> true
+          - (x & c1) > c2 when c1 is less than or equal to c2 -> false
+          - (x & c1) <= c2 when c1 is less than or equal to c2 -> true
+
+        For IOR operations:
+          - (x | c1) == c2 when some bits are set in c1 but not in c2 -> false
+          - (x | c1) != c2 when some bits are set in c1 but not in c2 -> true
+          - (x | c1) <= c2 when c1 is greater than c2 -> false
+          - (x | c1) > c2 when c1 is greater than c2 -> true
+          - (x | c1) < c2 when c1 is greater than or equal to c2 -> false
+          - (x | c1) >= c2 when c1 is greater than or equal to c2 -> true */
+      if ((op0code == AND
+          && ((code == EQ && (c1 & c2) != c2)
+              || (code == GEU && c1 < c2)
+              || (code == GTU && c1 <= c2)))
+         || ((op0code == IOR
+             && ((code == EQ && (c1 & c2) != c1)
+                 || (code == LEU && c1 > c2)
+                 || (code == LTU && c1 >= c2)))))
+       return const0_rtx;
+
+      if ((op0code == AND
+          && ((code == NE && (c1 & c2) != c2)
+              || (code == LTU && c1 < c2)
+              || (code == LEU && c1 <= c2)))
+         || ((op0code == IOR
+             && ((code == NE && (c1 & c2) != c1)
+                 || (code == GTU && c1 > c2)
+                 || (code == GEU && c1 >= c2)))))
+       return const_true_rtx;
+    }
+
   /* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped.  */
   if ((code == EQ || code == NE)
       && GET_CODE (op0) == BSWAP
index f0639b8500a5296e9d4fd8b5a1fb08ca379f93b2..be20bbb86ee4f47a139d6a92df97c0ec9dd1d881 100644 (file)
@@ -9,9 +9,9 @@
 /* { dg-final { scan-assembler-times "\[ \\t\]+sete" 1 { target { ia32 } } } } */
 /* { dg-final { scan-assembler-times "\[ \\t\]+setne" 1 { target { ia32 } } } } */
 /* { dg-final { scan-assembler-times "\[ \\t\]+je" 1 { target { ia32 } } } } */
-/* { dg-final { scan-assembler-times "\[ \\t\]+jne" 2 { target { ia32 } } } } */
+/* { dg-final { scan-assembler-times "\[ \\t\]+jne" 1 { target { ia32 } } } } */
 /* { dg-final { scan-assembler-times "kortest" 12 { target { ia32 } } } } */
-/* { dg-final { scan-assembler-times "kortest" 17 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "kortest" 16 { target { ! ia32 } } } } */
 
 #include <immintrin.h>
 
diff --git a/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c b/gcc/testsuite/gcc.target/riscv/zbs-if_then_else-02.c
new file mode 100644 (file)
index 0000000..3393bea
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do link  { target { rv64 } } } */
+/* { dg-options "-march=rv64gc_zbb_zbs -mabi=lp64d -flto" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-O1" } } */
+
+struct S {
+  int a;
+  char b;
+  int c;
+} s;
+
+const signed char c = -37;
+int d;
+struct S v1[] = {{0, 8}, 0, 0, -108976}, v2[] = {{}, 0, 0, 2804};
+int a;
+struct S v3[3];
+int *p = &a;
+
+void foo() {
+  int a;
+  if (a)
+    ;
+  else if (v1[0].b)
+    s.a = 0;
+  else
+    d = 0;
+  if (*p)
+    if (v3[1].c)
+      if (1 ^ (d & c & v2[1].c & ~v1[1].c | s.a))
+        v3[2].c = 0;
+}
+
+int main() { foo(); }