https://gcc.gnu.org/g:b03e0d69b37f6ea7aef220652635031a89f56a11

commit r16-1594-gb03e0d69b37f6ea7aef220652635031a89f56a11
Author: Andrew MacLeod <amacl...@redhat.com>
Date:   Fri Jun 20 08:50:39 2025 -0400

    Fix range wrap check and enhance verify_range.
    
    when snapping range bounds to satidsdaybitmask constraints, end bound 
overflow
    and underflow checks were not working properly.
    Also Adjust some comments, and enhance verify_range to make sure range pairs
    are sorted properly.
    
            PR tree-optimization/120701
            gcc/
            * value-range.cc (irange::verify_range): Verify range pairs are
            sorted properly.
            (irange::snap): Check for over/underflow properly.
    
            gcc/testsuite/
            * gcc.dg/pr120701.c: New.

Diff:
---
 gcc/testsuite/gcc.dg/pr120701.c | 40 ++++++++++++++++++++++++++++++++++++++++
 gcc/value-range.cc              | 38 +++++++++++++++++++++-----------------
 2 files changed, 61 insertions(+), 17 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/pr120701.c b/gcc/testsuite/gcc.dg/pr120701.c
new file mode 100644
index 000000000000..09f7b6192eda
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr120701.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int a, b, c, e, f;
+int main() {
+  int d, g, i;
+j:
+  if (d >= 0)
+    goto k;
+  if (g >= 0)
+    goto l;
+k:
+  i = a + 3;
+m:
+  f = 652685095 + 818172564 * g;
+  if (-1101344938 * f - 1654872807 * d >= 0)
+    goto n;
+  goto l;
+o:
+  if (i) {
+    c = -b;
+    if (-c >= 0)
+      goto l;
+    g = b;
+    b = i + 5;
+    if (b * c)
+      goto n;
+    goto o;
+  }
+  if (e)
+    goto m;
+  goto j;
+n:
+  d = 978208086 * g - 1963072513;
+  if (d + i)
+    return 0;
+  goto k;
+l:
+  goto o;
+}
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 0f0770ad7051..ce13acc312d2 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1552,6 +1552,11 @@ irange::verify_range ()
       gcc_checking_assert (ub.get_precision () == prec);
       int c = wi::cmp (lb, ub, TYPE_SIGN (m_type));
       gcc_checking_assert (c == 0 || c == -1);
+      // Previous UB should be lower than LB
+      if (i > 0)
+       gcc_checking_assert (wi::lt_p (upper_bound (i - 1),
+                                      lb,
+                                      TYPE_SIGN (m_type)));
     }
   m_bitmask.verify_mask ();
 }
@@ -1628,7 +1633,7 @@ irange::contains_p (const wide_int &cst) const
   if (undefined_p ())
     return false;
 
-  // Check is the known bits in bitmask exclude CST.
+  // Check if the known bits in bitmask exclude CST.
   if (!m_bitmask.member_p (cst))
     return false;
 
@@ -2269,7 +2274,7 @@ irange::invert ()
 
 // This routine will take the bounds [LB, UB], and apply the bitmask to those
 // values such that both bounds satisfy the bitmask.  TRUE is returned
-// if either bound changes, and they are retuirned as [NEW_LB, NEW_UB].
+// if either bound changes, and they are returned as [NEW_LB, NEW_UB].
 // if NEW_UB < NEW_LB, then the entire bound is to be removed as none of
 // the values are valid.
 //   ie,   [4, 14] MASK 0xFFFE  VALUE 0x1
@@ -2285,30 +2290,29 @@ irange::snap (const wide_int &lb, const wide_int &ub,
   uint z = wi::ctz (m_bitmask.mask ());
   if (z == 0)
     return false;
-  const wide_int &wild_mask = m_bitmask.mask ();
 
   const wide_int step = (wi::one (TYPE_PRECISION (type ())) << z);
   const wide_int match_mask = step - 1;
   const wide_int value = m_bitmask.value () & match_mask;
 
-  wide_int rem_lb = lb & match_mask;
-
-  wi::overflow_type ov_sub;
-  wide_int diff = wi::sub(value, rem_lb, UNSIGNED, &ov_sub);
-  wide_int offset = diff & match_mask;
+  bool ovf = false;
 
-  wi::overflow_type ov1;
-  new_lb = wi::add (lb, offset, UNSIGNED, &ov1);
+  wide_int rem_lb = lb & match_mask;
+  wide_int offset = (value - rem_lb) & match_mask;
+  new_lb = lb + offset;
+  // Check for overflows at +INF
+  if (wi::lt_p (new_lb, lb, TYPE_SIGN (type ())))
+    ovf = true;
 
   wide_int rem_ub = ub & match_mask;
   wide_int offset_ub = (rem_ub - value) & match_mask;
-
-  wi::overflow_type ov2;
-  new_ub = wi::sub (ub, offset_ub, UNSIGNED, &ov2);
+  new_ub = ub - offset_ub;
+  // Check for underflows at -INF
+  if (wi::gt_p (new_ub, ub, TYPE_SIGN (type ())))
+    ovf = true;
 
   // Overflow or inverted range = invalid
-  if (ov1 != wi::OVF_NONE || ov2 != wi::OVF_NONE
-      || wi::lt_p (new_ub, new_lb, TYPE_SIGN (type ())))
+  if (ovf || wi::lt_p (new_ub, new_lb, TYPE_SIGN (type ())))
     {
       new_lb = wi::one (lb.get_precision ());
       new_ub = wi::zero (ub.get_precision ());
@@ -2454,7 +2458,7 @@ irange::set_range_from_bitmask ()
 
   // Make sure we call intersect, so do it first.
   changed = intersect (mask_range) | changed;
-  // Npw make sure each subrange endpoint matches the bitmask.
+  // Now make sure each subrange endpoint matches the bitmask.
   changed |= snap_subranges ();
 
   return changed;
@@ -2548,7 +2552,7 @@ irange::intersect_bitmask (const irange &r)
   irange_bitmask bm = get_bitmask ();
   irange_bitmask save = bm;
   bm.intersect (r.get_bitmask ());
-  // Use ths opportunity to make sure mask reflects always reflects the
+  // Use ths opportunity to make sure mask always reflects the
   // best mask we have.
   m_bitmask = bm;

Reply via email to