]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[frange] Rewrite intersect to meet sub-ranges pairwise.
authorAldy Hernandez <aldy@quesejoda.com>
Tue, 28 Jul 2026 11:23:16 +0000 (11:23 +0000)
committerAldy Hernandez <aldy@quesejoda.com>
Thu, 30 Jul 2026 14:05:28 +0000 (16:05 +0200)
Replace the single-interval intersect with a sub-range aware one.

MAX_PAIRS is still 1, so the cross product yields at most one piece.
No functional change, for now.

Tested on ppc64le: regstrap, LAPACK, no changes on a corpus of Fortran
files.

gcc/ChangeLog:

* value-range.cc (frange_min, frange_max): New.
(frange::intersect_nans): Use set_nan.
(frange::intersect): Meet every sub-range against every other.

gcc/value-range.cc

index ac8096746e37fae4f9db568fdff4b89f78f741f8..472ff37a1df209320e5d835f90b4422ea530d48b 100644 (file)
@@ -1013,6 +1013,18 @@ frange_cmp (const REAL_VALUE_TYPE &a, const REAL_VALUE_TYPE &b)
   return 0;
 }
 
+static inline const REAL_VALUE_TYPE &
+frange_min (const REAL_VALUE_TYPE &a, const REAL_VALUE_TYPE &b)
+{
+  return frange_cmp (a, b) <= 0 ? a : b;
+}
+
+static inline const REAL_VALUE_TYPE &
+frange_max (const REAL_VALUE_TYPE &a, const REAL_VALUE_TYPE &b)
+{
+  return frange_cmp (a, b) >= 0 ? a : b;
+}
+
 // Return TRUE if [..., A_MAX] and [B_MIN, ...] can be fused into one interval,
 // either because they overlap or because no representable value exists between
 // them.  The latter is how -0.0 and +0.0 abut: there is nothing in between, so
@@ -1347,11 +1359,9 @@ frange::intersect_nans (const frange &r)
   m_pos_nan &= r.m_pos_nan;
   m_neg_nan &= r.m_neg_nan;
   if (maybe_isnan ())
-    m_kind = VR_NAN;
+    set_nan (m_type, get_nan_state ());
   else
     set_undefined ();
-  if (flag_checking)
-    verify_range ();
   return true;
 }
 
@@ -1376,43 +1386,44 @@ frange::intersect (const vrange &v)
   // Combine NAN info.
   if (known_isnan () || r.known_isnan ())
     return intersect_nans (r);
-  bool changed = false;
-  if (m_pos_nan != r.m_pos_nan || m_neg_nan != r.m_neg_nan)
-    {
-      m_pos_nan &= r.m_pos_nan;
-      m_neg_nan &= r.m_neg_nan;
-      changed = true;
-    }
 
-  // FIXME: Rewrite for sub-ranges.
-  // Combine endpoints.
-  if (frange_cmp (m_pairs[0].min, r.m_pairs[0].min) < 0)
-    {
-      m_pairs[0].min = r.m_pairs[0].min;
-      changed = true;
-    }
-  if (frange_cmp (r.m_pairs[0].max, m_pairs[0].max) < 0)
-    {
-      m_pairs[0].max = r.m_pairs[0].max;
-      changed = true;
-    }
+  frange save = *this;
+  m_pos_nan &= r.m_pos_nan;
+  m_neg_nan &= r.m_neg_nan;
 
-  // FIXME: Rewrite for sub-ranges.
-  // If the endpoints are swapped, the resulting range is empty.  This also
-  // catches [+0.0, -0.0], which is also empty.
-  if (frange_cmp (m_pairs[0].max, m_pairs[0].min) < 0)
+  // Meet every sub-range against every other.  Two sorted, disjoint sets of at
+  // most MAX_PAIRS each cannot yield more than MAX_PAIRS^2 pieces.
+  //
+  // NOTE: Since both operands are sorted, a merge-style meet like irange would
+  // be O(n) and leave set_pairs nothing to sort.  Not worth it while MAX_PAIRS
+  // is tiny; revisit if it grows.
+  frange_pair pairs[MAX_PAIRS * MAX_PAIRS];
+  unsigned n = 0;
+  for (unsigned i = 0; i < save.m_num_ranges; ++i)
+    for (unsigned j = 0; j < r.m_num_ranges; ++j)
+      {
+       const REAL_VALUE_TYPE &min
+         = frange_max (save.m_pairs[i].min, r.m_pairs[j].min);
+       const REAL_VALUE_TYPE &max
+         = frange_min (save.m_pairs[i].max, r.m_pairs[j].max);
+       // A reversed interval means these two do not overlap.  This also
+       // catches [+0.0, -0.0], which is empty rather than nonsensical.
+       if (frange_cmp (min, max) <= 0)
+         pairs[n++] = { min, max };
+      }
+
+  // Nothing but a possible NAN survives.
+  if (n == 0)
     {
       if (maybe_isnan ())
-       m_kind = VR_NAN;
+       set_nan (m_type, get_nan_state ());
       else
        set_undefined ();
-      if (flag_checking)
-       verify_range ();
       return true;
     }
 
-  changed |= normalize_kind ();
-  return changed;
+  set_pairs (pairs, n);
+  return *this != save;
 }
 
 frange &