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]>
---
 gcc/match.pd                                  | 21 +++++++++++
 .../gcc.dg/tree-ssa/bool-eq-bitxor.c          |  5 +--
 .../tree-ssa/bool-xor-zero-one-valued.c       | 36 +++++++++++++++++++
 3 files changed, 58 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 6addf8fee..edd6cd6a3 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3989,6 +3989,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 bc263e809..bfb3fe06b 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 000000000..95b369299
--- /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" } } */
-- 
2.43.0

Reply via email to