PR tree-optimization/126748
gcc/ChangeLog:
* range-op.cc (class operator_div): declarations.
(operator_div::op1_op2_relation_effect): add op1/op2 relation
range equal zero for op1/op2 if op1 < op2 and both op1 and op2
are positives.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr126748.c: New test.
---
gcc/range-op.cc | 35 ++++++++++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr126748.c | 26 ++++++++++++++++++
2 files changed, 61 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126748.c
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index b878a6052c6..85755ef679e 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2497,6 +2497,7 @@ class operator_div : public cross_product_operator
{
using range_operator::update_bitmask;
using range_operator::op2_range;
+ using range_operator::op1_op2_relation_effect;
public:
operator_div (tree_code div_kind) { m_code = div_kind; }
bool op2_range (irange &r, tree type, const irange &lhs, const irange &,
@@ -2509,6 +2510,11 @@ public:
virtual bool wi_op_overflows (wide_int &res, tree type,
const wide_int &, const wide_int &)
const final 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 final override
{ update_known_bitmask (r, m_code, lh, rh); }
@@ -2622,6 +2628,35 @@ operator_div::wi_fold (irange &r, tree type,
gcc_checking_assert (!r.undefined_p ());
}
+bool
+operator_div::op1_op2_relation_effect (irange &lhs_range,
+ tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const
+{
+ if (rel == VREL_VARYING)
+ return false;
+
+ int_range<2> rel_range;
+
+ switch (rel)
+ {
+ /* op1/op2 = 0 if op1 < op2 and both op1 and op2
+ are known positives. */
+ case VREL_LT:
+ if (TYPE_UNSIGNED (type)
+ || (wi::ge_p (op1_range.lower_bound (), 0, SIGNED)
+ && wi::ge_p (op2_range.lower_bound (), 0, SIGNED)))
+ rel_range.set_zero (type);
+ break;
+ default:
+ return false;
+ }
+
+ lhs_range.intersect (rel_range);
+ return true;
+}
class operator_exact_divide : public operator_div
{
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126748.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr126748.c
new file mode 100644
index 00000000000..063187a904c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126748.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+unsigned f(unsigned a, unsigned b)
+{
+ if (b >= a) __builtin_unreachable();
+ return b / a;
+}
+
+int fs(int a, int b)
+{
+ a = __builtin_abs(a);
+ b = __builtin_abs(b);
+ if (b >= a) __builtin_unreachable();
+ return b / a;
+}
+
+/* This can't be simplified. */
+int fs2(int a, int b)
+{
+ if (b >= a) __builtin_unreachable();
+ return b / a;
+}
+
+/* { dg-final { scan-tree-dump-times "return 0;" 2 "evrp" } } */
+/* { dg-final { scan-tree-dump-times " / " 1 "evrp" } } */
--
2.43.0