From 48ed18e9e7886f4ec3b5e61bec560a0ea01ecc68 Mon Sep 17 00:00:00 2001
From: Matteo Nicoli <matteo.nicoli001@gmail.com>
Date: Tue, 23 Sep 2025 21:06:17 +0000
Subject: [PATCH] [PATCH] tree-optimization/117760 - `a != b` implies that a or
 b is also non-zero

        * match.pd: added the following optimizations for bitwise operations:
                - (a != b) & ((a|b) != 0) -> (a != b)
                - (a != b) | ((a|b) != 0) -> ((a|b) != 0)
                - (a == b) & ((a|b) == 0) -> ((a|b) == 0)
                - (a == b) | ((a|b) == 0) -> (a == b)
                - (a != b) & ((a|b) == 0) -> false
                - (a == b) | ((a|b) != 0) -> true

        * gcc.dg/int-bwise-opt-1.c: Tests the following optimization patterns:
                - (a != b) & ((a|b) != 0) -> (a != b)
                - (a == b) | ((a|b) == 0) -> (a == b)
                - (a != b) & ((a|b) == 0) -> false
                - (a == b) | ((a|b) != 0) -> true
        * gcc.dg/int-bwise-opt-2.c: Tests the following optimization patterns:
                - (a != b) | ((a|b) != 0) -> ((a|b) != 0)
                - (a == b) & ((a|b) == 0) -> ((a|b) == 0)

Signed-off-by: Matteo Nicoli <matteo.nicoli001@gmail.com>
---
 gcc/match.pd                           | 28 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/int-bwise-opt-1.c | 31 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/int-bwise-opt-2.c | 15 +++++++++++++
 3 files changed, 74 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/int-bwise-opt-1.c
 create mode 100644 gcc/testsuite/gcc.dg/int-bwise-opt-2.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 2e629fd31ce..1bfe5187d90 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6803,6 +6803,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    @2))
 )
 
+#if GIMPLE
+/* Given two integers a and b:
+   (a != b) & ((a|b) != 0) -> (a != b)
+   (a != b) | ((a|b) != 0) -> ((a|b) != 0)
+   (a == b) & ((a|b) == 0) -> ((a|b) == 0)
+   (a == b) | ((a|b) == 0) -> (a == b)
+   (a != b) & ((a|b) == 0) -> false
+   (a == b) | ((a|b) != 0) -> true  */
+(simplify
+ (bit_and:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
+ (ne @0 @1))
+(simplify
+ (bit_ior:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
+ (ne (bit_ior @0 @1) { integer_zero_node; }))
+(simplify
+ (bit_and:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
+ (eq (bit_ior @0 @1) { integer_zero_node; }))
+(simplify
+ (bit_ior:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
+ (eq @0 @1))
+(simplify
+ (bit_and:c (ne:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
+ { build_zero_cst (type); })
+(simplify
+ (bit_ior:c (eq:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
+ { build_one_cst (type); })
+#endif
+
 /* These was part of minmax phiopt.  */
 /* Optimize (a CMP b) ? minmax<a, c> : minmax<b, c>
    to minmax<min/max<a, b>, c> */
diff --git a/gcc/testsuite/gcc.dg/int-bwise-opt-1.c b/gcc/testsuite/gcc.dg/int-bwise-opt-1.c
new file mode 100644
index 00000000000..11ea9acb3fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/int-bwise-opt-1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int f1(int a, int b)
+{
+  return (a != b) & ((a | b) != 0);
+}
+
+int f2(int a, int b)
+{
+  return (a == b) | ((a | b) == 0);
+}
+
+int f3(int a, int b)
+{
+  return (a != b) & ((a | b) == 0);
+}
+
+int f4(int a, int b)
+{
+  return (a == b) | ((a | b) != 0);
+}
+
+/* { dg-final { scan-tree-dump-times "\\\|" 0 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\&" 0 "optimized" } } */
+
+/* f3 should fold to `1` (true).  */
+/* { dg-final { scan-tree-dump-times "return 1;" 1 "optimized" } } */
+
+/* f4 should fold to `0` (false).  */
+/* { dg-final { scan-tree-dump-times "return 0;" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/int-bwise-opt-2.c b/gcc/testsuite/gcc.dg/int-bwise-opt-2.c
new file mode 100644
index 00000000000..cc1a48b061a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/int-bwise-opt-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int f1(int a, int b)
+{
+  return (a != b) | ((a | b) != 0);
+}
+
+int f2(int a, int b)
+{
+  return (a == b) & ((a | b) == 0);
+}
+
+ /* { dg-final { scan-tree-dump-times "a == b" 0 "optimized" } } */
+ /* { dg-final { scan-tree-dump-times "a != b" 0 "optimized" } } */
-- 
2.47.2

