[gcc r17-3465] match.pd: Simplify XORs of zero_one_valued comparisons

Richard Biener via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:7f6a999da640a9d33fa8d572c805884eeaac2935

commit r17-3465-g7f6a999da640a9d33fa8d572c805884eeaac2935
Author: Shivam Gupta <[email protected]>
Date:   Sun Aug 16 00:13:44 2026 +0530

    match.pd: Simplify XORs of zero_one_valued comparisons
    
    Recognize XOR patterns involving zero_one_valued operands compared
    against zero and simplify them to direct equality or inequality tests.
    
    Specifically:
    
    (a == 0) ^ (b != 0)  -> a == b
    (a != 0) ^ (b == 0)  -> a == b
    (a == 0) ^ (b == 0)  -> a != b
    (a != 0) ^ (b != 0)  -> a != b
    
    Also handle a specific case:
    (a == 0) ^ b -> a == b
    
    Extend the simplifications to handle the corresponding boolean
    equality forms as well:
    (a == 0) == (b != 0) -> a != b
    (a != 0) == (b == 0) -> a != b
    (a == 0) == (b == 0) -> a == b
    (a != 0) == (b != 0) -> a == b
    
    Regression tested on aarch64-linux-gnu with RUNTESTFLAGS="tree-ssa.exp".
    
    Changes since v1:
    * v3: Merge the op1 == op2 and op1 != op2 comparison patterns into a
          single pattern using out_cmp.
          Wrap the pattern inside (if (INTEGRAL_TYPE_P (type))) to explicitly guard
          against vector types instead of relying on zero_one_valued_p internals.
          Drop unnecessary ':s' tree flags and remove outer convert.
          Update the regression test to check for the expected canonical
          XOR form rather than the absence of comparisons against zero.
    
    * v2: Simplify (a == 0) ^ b to a == b.
          Handle outer EQ as well as outer NE forms.
          Use convert:type to handle differing operand types.
    
    gcc/ChangeLog:
            * match.pd: Add simplifications for XORs and boolean
            comparisons of zero_one_valued comparisons against zero.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/tree-ssa/bool-eq-bitxor.c: Update expected number
            of optimized XOR forms.
            * gcc.dg/tree-ssa/bool-xor-zero-one-valued.c: New test.
    
    Signed-off-by: Shivam Gupta <[email protected]>

Diff:
---
 gcc/match.pd                                       | 21 +++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c     |  5 +--
 .../gcc.dg/tree-ssa/bool-xor-zero-one-valued.c     | 36 ++++++++++++++++++++++
 3 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index 3cb5cfbe6926..0d1a61321d49 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4037,6 +4037,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (types_match (type, TREE_TYPE (@0)))
      (bit_xor @0 { build_one_cst (type); } ))))))
 
+/* For zero_one_valued operands:
+   (a == 0) != b -> a == b.  */
+(simplify
+ (ne:c (convert (eq zero_one_valued_p@0 integer_zerop))
+       (convert zero_one_valued_p@1))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+      && types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+  (eq @0 @1)))
+
+/* For zero_one_valued operands:
+   (a op1 0) cmp (b op2 0) -> a out_cmp b
+   where out_cmp is cmp if op1 == op2, and the inverse of cmp otherwise.  */
+(if (INTEGRAL_TYPE_P (type))
+  (for cmp     (ne ne eq eq ne ne eq eq)
+       op1     (eq ne eq ne eq ne eq ne)
+       op2     (eq ne eq ne ne eq ne eq)
+       out_cmp (ne ne eq eq eq eq ne ne)
+    (simplify
+      (cmp:c (op1 zero_one_valued_p@0 integer_zerop)
+             (op2 zero_one_valued_p@1 integer_zerop))
+      (out_cmp (convert:type @0) (convert:type @1)))))
 
 /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */
 /* ((a ^ b) & c) cmp d && a == b --> (0 cmp d && a == b). */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
index bc263e809770..bfb3fe06bc9a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-eq-bitxor.c
@@ -36,7 +36,4 @@ xor_ne_ne (u32 a, u32 b)
 }
 
 /* Verify all functions canonicalize to xor-mask tests.  */
-/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ b_\[0-9\]+\\(D\\)" 3 "optimized" } } */
-
-/* xor_eq_ne not optimized yet due to zero_one_valued_p canonicalization.  */
-/* { dg-final { scan-tree-dump-times "& 1" 2 "optimized" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ b_\[0-9\]+\\(D\\)" 4 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
new file mode 100644
index 000000000000..95b369299398
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+_Bool
+f1 (unsigned a, unsigned b)
+{
+  if (a != 0 && a != 1) __builtin_unreachable();
+  if (b != 0 && b != 1) __builtin_unreachable();
+  return (a == 0) ^ (b != 0);
+}
+
+_Bool
+f2 (unsigned a, unsigned b)
+{
+  if (a != 0 && a != 1) __builtin_unreachable();
+  if (b != 0 && b != 1) __builtin_unreachable();
+  return (a != 0) ^ (b == 0);
+}
+
+_Bool
+f3 (unsigned a, unsigned b)
+{
+  if (a != 0 && a != 1) __builtin_unreachable();
+  if (b != 0 && b != 1) __builtin_unreachable();
+  return (a == 0) ^ (b == 0);
+}
+
+_Bool
+f4 (unsigned a, unsigned b)
+{
+  if (a != 0 && a != 1) __builtin_unreachable();
+  if (b != 0 && b != 1) __builtin_unreachable();
+  return (a != 0) ^ (b != 0);
+}
+
+/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ b_\[0-9\]+\\(D\\)" 4 "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.