[gcc r17-2291] match: Fix up `((a ^ b) & c) cmp d || a != b` pattern and add support for && case [PR116860]

Andrew Pinski via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:ad6087410356999730cbe9680ada3077f4afcf76

commit r17-2291-gad6087410356999730cbe9680ada3077f4afcf76
Author: Andrew Pinski <[email protected]>
Date:   Sat Jul 4 00:32:03 2026 -0700

    match: Fix up `((a ^ b) & c) cmp d || a != b` pattern and add support for && case [PR116860]
    
    Turns out it was easy to fix these patterns for
    `--param=logical-op-non-short-circuit=0` case after all.
    Just add support for `((a ^ b) & c) cmp d && a == b`
    which is the same as `!(((a ^ b) & c) cmp d || a != b)`.
    So this adds the bit_and case to support exactly that.
    Also fixes up some of the `:c` on the operands.
    `:c` needs to be on the outer bitop and does not need to be
    on the inner one for bit_xor as it will be the same order as ne/eq.
    
            PR tree-optimization/116860
            PR tree-optimization/114326
    gcc/ChangeLog:
    
            * match.pd (`((a ^ b) & c) cmp d || a != b`): Expand
            to support bit_and and fix up the :c.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/fold-xor-and-or-1.c: New test.
            * gcc.dg/tree-ssa/fold-xor-or-1.c: New test.
            * gcc.dg/tree-ssa/pr102793-1.c: Update for the optimization
            happening in pre.
    
    Signed-off-by: Andrew Pinski <[email protected]>

Diff:
---
 gcc/match.pd                                      | 32 ++++++-------
 gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c | 55 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c     | 55 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c        | 10 +++--
 4 files changed, 134 insertions(+), 18 deletions(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index a7b658e9e940..cf03333fdc6b 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3827,35 +3827,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (types_match (type, TREE_TYPE (@0)))
      (bit_xor @0 { build_one_cst (type); } ))))))
 
+
 /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */
-(for cmp (simple_comparison)
+/* ((a ^ b) & c) cmp d && a == b --> (0 cmp d && a == b). */
+(for bitop (bit_ior bit_and)
+     neeq  (ne      eq)
+ (for cmp  (simple_comparison)
   (simplify
-    (bit_ior
+    (bitop:c
       (cmp:c
 	(bit_and:c
-	  (bit_xor:c @0 @1)
+	  (bit_xor @0 @1)
 	  tree_expr_nonzero_p@2)
 	@3)
-      (ne@4 @0 @1))
-    (bit_ior
+      (neeq@4 @0 @1))
+    (bitop
       (cmp
 	{ build_zero_cst (TREE_TYPE (@0)); }
 	@3)
-      @4)))
-
+      @4))
 /* (a ^ b) cmp c || a != b --> (0 cmp c || a != b). */
-(for cmp (simple_comparison)
+/* (a ^ b) cmp c && a == b --> (0 cmp c || a == b). */
   (simplify
-    (bit_ior
+    (bitop:c
       (cmp:c
-	(bit_xor:c @0 @1)
+	(bit_xor @0 @1)
 	@2)
-      (ne@3 @0 @1))
-    (bit_ior
+      (neeq@3 @0 @1))
+    (bitop
       (cmp
-	{ build_zero_cst (TREE_TYPE (@0)); }
-	@2)
-      @3)))
+	{ build_zero_cst (TREE_TYPE (@0)); } @2)
+      @3))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c
new file mode 100644
index 000000000000..609532b9599c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-optimized --param logical-op-non-short-circuit=0" } */
+
+typedef unsigned long int uint64_t;
+
+int cmp1(int d1, int d2) {
+  if (((d1 ^ d2) & 0xabcd) == 0 || d1 != d2)
+    return 0;
+  return 1;
+}
+
+int cmp2(int d1, int d2) {
+  if (d1 != d2 || ((d1 ^ d2) & 0xabcd) == 0)
+    return 0;
+  return 1;
+}
+
+int cmp3(int d1, int d2) {
+  if (10 > (0xabcd & (d2 ^ d1)) || d2 != d1)
+    return 0;
+  return 1;
+}
+
+int cmp4(int d1, int d2) {
+  if (d2 != d1 || 10 > (0xabcd & (d2 ^ d1)))
+    return 0;
+  return 1;
+}
+
+int cmp1_64(uint64_t d1, uint64_t d2) {
+  if (((d1 ^ d2) & 0xabcd) == 0 || d1 != d2)
+    return 0;
+  return 1;
+}
+
+int cmp2_64(uint64_t d1, uint64_t d2) {
+  if (d1 != d2 || ((d1 ^ d2) & 0xabcd) == 0)
+    return 0;
+  return 1;
+}
+
+int cmp3_64(uint64_t d1, uint64_t d2) {
+  if (10 > (0xabcd & (d2 ^ d1)) || d2 != d1)
+    return 0;
+  return 1;
+}
+
+int cmp4_64(uint64_t d1, uint64_t d2) {
+  if (d2 != d1 || 10 > (0xabcd & (d2 ^ d1)))
+    return 0;
+  return 1;
+}
+
+/* The if should be removed, so the condition should not exist */
+/* { dg-final { scan-tree-dump-not "d1_\[0-9\]+.D. \\^ d2_\[0-9\]+.D." "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c
new file mode 100644
index 000000000000..be66dec523c4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-optimized --param logical-op-non-short-circuit=0" } */
+
+typedef unsigned long int uint64_t;
+
+int cmp1(int d1, int d2) {
+  if ((d1 ^ d2) == 0xabcd || d1 != d2)
+    return 0;
+  return 1;
+}
+
+int cmp2(int d1, int d2) {
+  if (d1 != d2 || (d1 ^ d2) == 0xabcd)
+    return 0;
+  return 1;
+}
+
+int cmp3(int d1, int d2) {
+  if (0xabcd > (d2 ^ d1) || d2 != d1)
+    return 0;
+  return 1;
+}
+
+int cmp4(int d1, int d2) {
+  if (d2 != d1 || 0xabcd > (d2 ^ d1))
+    return 0;
+  return 1;
+}
+
+int cmp1_64(uint64_t d1, uint64_t d2) {
+  if ((d1 ^ d2) == 0xabcd || d1 != d2)
+    return 0;
+  return 1;
+}
+
+int cmp2_64(uint64_t d1, uint64_t d2) {
+  if (d1 != d2 || (d1 ^ d2) == 0xabcd)
+    return 0;
+  return 1;
+}
+
+int cmp3_64(uint64_t d1, uint64_t d2) {
+  if (0xabcd > (d2 ^ d1) || d2 != d1)
+    return 0;
+  return 1;
+}
+
+int cmp4_64(uint64_t d1, uint64_t d2) {
+  if (d2 != d1 || 0xabcd > (d2 ^ d1))
+    return 0;
+  return 1;
+}
+
+/* The if should be removed, so the condition should not exist */
+/* { dg-final { scan-tree-dump-not "d1_\[0-9\]+.D. \\^ d2_\[0-9\]+.D." "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c
index 436b4e4bf058..c4c84dcbb467 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O3 -fdump-tree-pre --param logical-op-non-short-circuit=1" } */
+/* { dg-options "-O3 -fdump-tree-pre -fdump-tree-optimized --param logical-op-non-short-circuit=1" } */
 
 typedef __UINT64_TYPE__ uint64_t;
 
@@ -45,5 +45,9 @@ int noccmp1(uint64_t* s1, uint64_t* s2)
     return 0;
 }
 
-/* Check for condition assignments for noccmp0 and noccmp1.  */
-/* { dg-final { scan-tree-dump-times {_\d+ = d\d+_\d+ != d\d+_\d+;\n  _\d+ = bar_\d+ == 0;} 2 "pre" } } */
+/* Check for condition assignments for noccmp1 and noccmp0.  */
+/* { dg-final { scan-tree-dump-times {_\d+ = d\d+_\d+ != d\d+_\d+;\n  _\d+ = bar_\d+ == 0;} 1 "pre" } } */
+/* { dg-final { scan-tree-dump-times "optimizing two comparisons " 2 "pre" } } */
+/* The conditional in noccmp1 should be optimized in pre */
+/* { dg-final { scan-tree-dump-times " if " 1 "pre" } } */
+/* { dg-final { scan-tree-dump-times " if " 1 "optimized" } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.