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