Given A div B, if we know for certain that A and B are positive
and A < B, we can infer that A div B is zero.

Bootstrapped and regression tested in x86_64, aarch64 and riscv64.

        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

Reply via email to