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 -> b != (a ^ 1)

Regression tested on aarch64-linux-gnu.

gcc/ChangeLog:
        * match.pd: Add simplifications for XORs 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                                  | 29 +++++++++++++++
 .../gcc.dg/tree-ssa/bool-eq-bitxor.c          |  4 +-
 .../tree-ssa/bool-xor-zero-one-valued.c       | 37 +++++++++++++++++++
 3 files changed, 67 insertions(+), 3 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 228bab78428..1be34516338 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3765,6 +3765,35 @@ 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  -> b != (a ^ 1).  */
+(simplify
+ (ne (convert:s (eq zero_one_valued_p@0 integer_zerop))
+     (convert:s zero_one_valued_p@1))
+ (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+  (ne @1 (bit_xor @0 { build_one_cst (TREE_TYPE (@0)); }))))
+
+/* For zero_one_valued operands:
+     (a == 0) != (b != 0)  -> a == b
+     (a != 0) != (b == 0)  -> a == b.  */
+(for op1 (eq ne)
+     op2 (ne eq)
+ (simplify
+  (ne:c (op1 zero_one_valued_p@0 integer_zerop)
+        (op2 zero_one_valued_p@1 integer_zerop))
+  (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+   (eq @0 @1))))
+
+/* For zero_one_valued operands:
+     (a == 0) != (b == 0)  -> a != b
+     (a != 0) != (b != 0)  -> a != b.  */
+(for op (eq ne)
+ (simplify
+  (ne:c (op zero_one_valued_p@0 integer_zerop)
+        (op zero_one_valued_p@1 integer_zerop))
+  (if (types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
+   (ne @0 @1))))
+
 /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */
 (for cmp (simple_comparison)
   (simplify
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 bc263e80977..e39e82589b6 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,5 @@ 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" } } */
+/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) \\^ b_\[0-9\]+\\(D\\)" 
4 "optimized" } } */
 
-/* xor_eq_ne not optimized yet due to zero_one_valued_p canonicalization.  */
-/* { dg-final { scan-tree-dump-times "& 1" 2 "optimized" { xfail *-*-* } } } */
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 00000000000..71f70f3cf0c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-xor-zero-one-valued.c
@@ -0,0 +1,37 @@
+/* { 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\\)" 
2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "a_\[0-9\]+\\(D\\) != b_\[0-9\]+\\(D\\)" 
2 "optimized" } } */
-- 
2.34.1

Reply via email to