Given a bit_ior in the format A | B, if we know for certain that
A != B then we can infer that A | B will always be nonzero.

Bootstrapped and regression tested in x86_64, aarch64 and riscv64.

        PR tree-optimization/126743

gcc/ChangeLog:

        * range-op-mixed.h: declare.
        * range-op.cc (operator_bitwise_or::op1_op2_relation_effect):
        add op1 NE op2 relation range for op1 | op2 as nonzero.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/pr126743.c: New test.
---
 gcc/range-op-mixed.h                     |  6 ++++++
 gcc/range-op.cc                          | 25 ++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr126743.c | 23 ++++++++++++++++++++++
 3 files changed, 54 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126743.c

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index a870a0c1211..0e97fb11688 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -849,6 +849,7 @@ public:
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation_effect;
   using range_operator::update_bitmask;
 
   bool fold_range (prange &r, tree type,
@@ -861,6 +862,11 @@ public:
   bool op2_range (irange &r, tree type,
                  const irange &lhs, const irange &op1,
                  relation_trio rel = TRIO_VARYING) const override;
+  bool op1_op2_relation_effect (irange &lhs_range,
+                               tree type,
+                               const irange &op1_range,
+                               const irange &op2_range,
+                               relation_kind rel) const final override;
   void update_bitmask (irange &r, const irange &lh,
                       const irange &rh) const override;
   // Check compatibility of all operands.
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 07413ef7054..b878a6052c6 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4060,6 +4060,31 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
   value_range_with_overflow (r, type, new_lb, new_ub);
 }
 
+bool
+operator_bitwise_or::op1_op2_relation_effect (irange &lhs_range,
+                                             tree type,
+                                             const irange &,
+                                             const irange &,
+                                             relation_kind rel) const
+{
+  if (rel == VREL_VARYING)
+    return false;
+
+  int_range<2> rel_range;
+
+  switch (rel)
+    {
+    case VREL_NE:
+      rel_range.set_nonzero (type);
+      break;
+    default:
+      return false;
+    }
+
+  lhs_range.intersect (rel_range);
+  return true;
+}
+
 bool
 operator_bitwise_or::op1_range (irange &r, tree type,
                                const irange &lhs,
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126743.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr126743.c
new file mode 100644
index 00000000000..a99e6efbff9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126743.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+unsigned int
+or_eq_zero (int a, int b)
+{
+  if (a == b)
+    __builtin_unreachable ();
+  // return 0;
+  return (a | b) == 0;
+}
+
+unsigned int
+or_ne_zero (int a, int b)
+{
+  if (a == b)
+    __builtin_unreachable ();
+  // return 1;
+  return (a | b) != 0;
+}
+
+/* { dg-final { scan-tree-dump-times "return 0;" 1 "evrp" } } */
+/* { dg-final { scan-tree-dump-times "return 1;" 1 "evrp" } } */
-- 
2.43.0

Reply via email to