[gcc r17-2758] [frange] Store a single sub-range in an array slot.

Aldy Hernandez via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:bbf71b94fc1af926cb9dfe3934e716ced755dc8b

commit r17-2758-gbbf71b94fc1af926cb9dfe3934e716ced755dc8b
Author: Aldy Hernandez <[email protected]>
Date:   Sun Jul 19 09:38:49 2026 +0000

    [frange] Store a single sub-range in an array slot.
    
    To prepare for holding more than one sub-range, move the endpoints
    m_min/m_max into a one-element array.
    
    While here, pick the low-hanging multi-range fruit so the follow-up
    patches stay small: consumers that walk every sub-range now loop over
    m_num_ranges, and the inherently single-range ones (normalize_kind,
    singleton_p, etc) gain an m_num_ranges == 1 guard.  The hard cases
    (union_/intersect, etc) are left with FIXMEs for later.
    
    No change to functionality as MAX_PAIRS is 1.  I'll bump this to 2 in
    a subequent patch, and implement union/intersect and all the other
    little things.
    
    Tested on ppc64le Linux.  No change to assembly over the LAPACK
    preprocessed-Fortran corpus; LAPACK and GCC tests pass.
    
    gcc/ChangeLog:
    
            * value-range.h (struct frange_pair): New.
            (class frange): Replace m_min and m_max with m_pairs[MAX_PAIRS]
            and m_num_ranges.  Add MAX_PAIRS, num_pairs, and the indexed
            lower_bound and upper_bound.  Have canonicalize_zeros take an
            frange_pair.
            (frange::lower_bound, frange::upper_bound): Adjust.
            (frange::set_varying, frange::set_undefined, frange::set_nan)
            (frange::known_isfinite, frange::known_isnormal)
            (frange::known_isdenormal_or_zero, frange::maybe_isinf)
            (frange::known_isinf, frange::signbit_p): Adjust.
            * value-range.cc (frange::flush_denormals_to_zero): Adjust.
            (frange::canonicalize_zeros): Take an frange_pair.
            (frange::set, frange::normalize_kind, frange::union_nans)
            (frange::union_, frange::intersect, frange::operator=)
            (frange::operator==, frange::contains_p)
            (frange::internal_singleton_p, frange::singleton_p)
            (frange::verify_range, frange::zero_p): Adjust.
            * value-range-storage.h (class frange_storage): Replace m_min
            and m_max with m_pairs and m_num_ranges.
            * value-range-storage.cc (frange_storage::set_frange): Adjust.
            (frange_storage::get_frange): Adjust.

Diff:
---
 gcc/value-range-storage.cc |  17 +++--
 gcc/value-range-storage.h  |   4 +-
 gcc/value-range.cc         | 175 ++++++++++++++++++++++++++-------------------
 gcc/value-range.h          |  84 ++++++++++++++++------
 4 files changed, 175 insertions(+), 105 deletions(-)

diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 837c40bb72e6..6f8b53814a8d 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -524,8 +524,9 @@ frange_storage::set_frange (const frange &r)
   gcc_checking_assert (fits_p (r));
 
   m_kind = r.m_kind;
-  m_min = r.m_min;
-  m_max = r.m_max;
+  m_num_ranges = r.m_num_ranges;
+  for (unsigned i = 0; i < r.m_num_ranges; ++i)
+    m_pairs[i] = r.m_pairs[i];
   m_pos_nan = r.m_pos_nan;
   m_neg_nan = r.m_neg_nan;
 }
@@ -555,13 +556,11 @@ frange_storage::get_frange (frange &r, tree type) const
       return;
     }
 
-  // We use the constructor to create the new range instead of writing
-  // out the bits into the frange directly, because the global range
-  // being read may be being inlined into a function with different
-  // restrictions as when it was originally written.  We want to make
-  // sure the resulting range is canonicalized correctly for the new
-  // consumer.
-  r = frange (type, m_min, m_max, m_kind);
+  // FIXME: Rewrite for sub-ranges.  This only reconstructs the first pair.
+  // Eventually do it piecewise like irange_storage::get_irange: start
+  // undefined and union each sub-range built through the constructor (so
+  // every piece is re-canonicalized).
+  r = frange (type, m_pairs[0].min, m_pairs[0].max, m_kind);
 
   // The constructor will set the NAN bits for HONOR_NANS, but we must
   // make sure to set the NAN sign if known.
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index e289765cfe01..a7369d1eb0f7 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -167,8 +167,8 @@ class GTY((tag ("VR_FRANGE"))) frange_storage : public vrange_storage
   DISABLE_COPY_AND_ASSIGN (frange_storage);
 
   enum value_range_kind m_kind;
-  REAL_VALUE_TYPE m_min;
-  REAL_VALUE_TYPE m_max;
+  frange_pair m_pairs[frange::MAX_PAIRS];
+  unsigned char m_num_ranges;
   bool m_pos_nan;
   bool m_neg_nan;
 };
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 4e1be3b0ed67..09381e626026 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1023,6 +1023,7 @@ frange::flush_denormals_to_zero ()
 
   machine_mode mode = TYPE_MODE (type ());
 
+  // FIXME: Rewrite for sub-ranges.
   // Flush a denormal endpoint to a zero of the same sign: a +denormal lower
   // bound to +0.0, and a -denormal upper bound to -0.0.  Then call
   // canonicalize_zeros to rewrite the sign to whatever the flags make
@@ -1033,15 +1034,15 @@ frange::flush_denormals_to_zero ()
   //
   // keeping contains_p (-0.0) true; under HONOR_SIGNED_ZEROS the sign stands and
   // it stays [ +0.0, 5.0 ].
-  if (real_isdenormal (&m_max, mode) && real_isneg (&m_max))
-    m_max = dconstm0;
-  if (real_isdenormal (&m_min, mode) && !real_isneg (&m_min))
-    m_min = dconst0;
-  canonicalize_zeros (m_min, m_max);
+  if (real_isdenormal (&m_pairs[0].max, mode) && real_isneg (&m_pairs[0].max))
+    m_pairs[0].max = dconstm0;
+  if (real_isdenormal (&m_pairs[0].min, mode) && !real_isneg (&m_pairs[0].min))
+    m_pairs[0].min = dconst0;
+  canonicalize_zeros (m_pairs[0]);
 }
 
-// Canonicalize the signed zeros of the endpoints MIN and MAX according with what
-// the target and flags want:
+// Canonicalize the signed zeros of a sub-range according with what the target
+// and flags want:
 //
 //   !MODE_HAS_SIGNED_ZEROS: the mode has no signed zero, so any zero is +0.0.
 //
@@ -1051,21 +1052,21 @@ frange::flush_denormals_to_zero ()
 //   Otherwise the sign is a real distinction, and we keep it.
 
 void
-frange::canonicalize_zeros (REAL_VALUE_TYPE &min, REAL_VALUE_TYPE &max)
+frange::canonicalize_zeros (frange_pair &p)
 {
   if (!MODE_HAS_SIGNED_ZEROS (TYPE_MODE (m_type)))
     {
-      if (real_iszero (&min, 1))
-	min.sign = 0;
-      if (real_iszero (&max, 1))
-	max.sign = 0;
+      if (real_iszero (&p.min, 1))
+	p.min.sign = 0;
+      if (real_iszero (&p.max, 1))
+	p.max.sign = 0;
     }
   else if (!HONOR_SIGNED_ZEROS (m_type))
     {
-      if (real_iszero (&max, 1))
-	max.sign = 0;
-      if (real_iszero (&min, 0))
-	min.sign = 1;
+      if (real_iszero (&p.max, 1))
+	p.max.sign = 0;
+      if (real_iszero (&p.min, 0))
+	p.min.sign = 1;
     }
 }
 
@@ -1095,8 +1096,9 @@ frange::set (tree type,
 
   m_kind = kind;
   m_type = type;
-  m_min = min;
-  m_max = max;
+  m_num_ranges = 1;
+  m_pairs[0].min = min;
+  m_pairs[0].max = max;
   if (HONOR_NANS (m_type))
     {
       m_pos_nan = nan.pos_p ();
@@ -1108,7 +1110,7 @@ frange::set (tree type,
       m_neg_nan = false;
     }
 
-  canonicalize_zeros (m_min, m_max);
+  canonicalize_zeros (m_pairs[0]);
 
   // For -ffinite-math-only we can drop ranges outside the
   // representable numbers to min/max for the type.
@@ -1116,14 +1118,14 @@ frange::set (tree type,
     {
       REAL_VALUE_TYPE min_repr = frange_val_min (m_type);
       REAL_VALUE_TYPE max_repr = frange_val_max (m_type);
-      if (real_less (&m_min, &min_repr))
-	m_min = min_repr;
-      else if (real_less (&max_repr, &m_min))
-	m_min = max_repr;
-      if (real_less (&max_repr, &m_max))
-	m_max = max_repr;
-      else if (real_less (&m_max, &min_repr))
-	m_max = min_repr;
+      if (real_less (&m_pairs[0].min, &min_repr))
+	m_pairs[0].min = min_repr;
+      else if (real_less (&max_repr, &m_pairs[0].min))
+	m_pairs[0].min = max_repr;
+      if (real_less (&max_repr, &m_pairs[0].max))
+	m_pairs[0].max = max_repr;
+      else if (real_less (&m_pairs[0].max, &min_repr))
+	m_pairs[0].max = min_repr;
     }
 
   // Check for swapped ranges.
@@ -1162,8 +1164,9 @@ bool
 frange::normalize_kind ()
 {
   if (m_kind == VR_RANGE
-      && frange_val_is_min (m_min, m_type)
-      && frange_val_is_max (m_max, m_type))
+      && m_num_ranges == 1
+      && frange_val_is_min (m_pairs[0].min, m_type)
+      && frange_val_is_max (m_pairs[0].max, m_type))
     {
       if (!HONOR_NANS (m_type) || (m_pos_nan && m_neg_nan))
 	{
@@ -1176,8 +1179,9 @@ frange::normalize_kind ()
       if (HONOR_NANS (m_type) && (!m_pos_nan || !m_neg_nan))
 	{
 	  m_kind = VR_RANGE;
-	  m_min = frange_val_min (m_type);
-	  m_max = frange_val_max (m_type);
+	  m_num_ranges = 1;
+	  m_pairs[0].min = frange_val_min (m_type);
+	  m_pairs[0].max = frange_val_max (m_type);
 	  if (flag_checking)
 	    verify_range ();
 	  return true;
@@ -1199,8 +1203,9 @@ frange::union_nans (const frange &r)
   if (known_isnan () && m_kind != r.m_kind)
     {
       m_kind = r.m_kind;
-      m_min = r.m_min;
-      m_max = r.m_max;
+      m_num_ranges = r.m_num_ranges;
+      for (unsigned i = 0; i < r.m_num_ranges; ++i)
+	m_pairs[i] = r.m_pairs[i];
       changed = true;
     }
   if (m_pos_nan != r.m_pos_nan || m_neg_nan != r.m_neg_nan)
@@ -1241,15 +1246,16 @@ frange::union_ (const vrange &v)
       changed = true;
     }
 
-  // Combine endpoints.
-  if (frange_cmp (r.m_min, m_min) < 0)
+  // FIXME: Rewrite for sub-ranges.
+  // Combine endpoints.  This needs to be rewritten for sub-ranges.
+  if (frange_cmp (r.m_pairs[0].min, m_pairs[0].min) < 0)
     {
-      m_min = r.m_min;
+      m_pairs[0].min = r.m_pairs[0].min;
       changed = true;
     }
-  if (frange_cmp (m_max, r.m_max) < 0)
+  if (frange_cmp (m_pairs[0].max, r.m_pairs[0].max) < 0)
     {
-      m_max = r.m_max;
+      m_pairs[0].max = r.m_pairs[0].max;
       changed = true;
     }
 
@@ -1304,21 +1310,23 @@ frange::intersect (const vrange &v)
       changed = true;
     }
 
+  // FIXME: Rewrite for sub-ranges.
   // Combine endpoints.
-  if (frange_cmp (m_min, r.m_min) < 0)
+  if (frange_cmp (m_pairs[0].min, r.m_pairs[0].min) < 0)
     {
-      m_min = r.m_min;
+      m_pairs[0].min = r.m_pairs[0].min;
       changed = true;
     }
-  if (frange_cmp (r.m_max, m_max) < 0)
+  if (frange_cmp (r.m_pairs[0].max, m_pairs[0].max) < 0)
     {
-      m_max = r.m_max;
+      m_pairs[0].max = r.m_pairs[0].max;
       changed = true;
     }
 
+  // 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_max, m_min) < 0)
+  if (frange_cmp (m_pairs[0].max, m_pairs[0].min) < 0)
     {
       if (maybe_isnan ())
 	m_kind = VR_NAN;
@@ -1338,8 +1346,9 @@ frange::operator= (const frange &src)
 {
   m_kind = src.m_kind;
   m_type = src.m_type;
-  m_min = src.m_min;
-  m_max = src.m_max;
+  m_num_ranges = src.m_num_ranges;
+  for (unsigned i = 0; i < src.m_num_ranges; ++i)
+    m_pairs[i] = src.m_pairs[i];
   m_pos_nan = src.m_pos_nan;
   m_neg_nan = src.m_neg_nan;
 
@@ -1369,9 +1378,14 @@ frange::operator== (const frange &src) const
 	  return false;
 	}
 
-      return (real_identical (&m_min, &src.m_min)
-	      && real_identical (&m_max, &src.m_max)
-	      && m_pos_nan == src.m_pos_nan
+      if (m_num_ranges != src.m_num_ranges)
+	return false;
+      for (unsigned i = 0; i < m_num_ranges; ++i)
+	if (!real_identical (&m_pairs[i].min, &src.m_pairs[i].min)
+	    || !real_identical (&m_pairs[i].max, &src.m_pairs[i].max))
+	  return false;
+
+      return (m_pos_nan == src.m_pos_nan
 	      && m_neg_nan == src.m_neg_nan
 	      && types_compatible_p (m_type, src.m_type));
     }
@@ -1404,7 +1418,12 @@ frange::contains_p (const REAL_VALUE_TYPE &r) const
   if (known_isnan ())
     return false;
 
-  return frange_cmp (r, m_min) >= 0 && frange_cmp (r, m_max) <= 0;
+  for (unsigned i = 0; i < m_num_ranges; ++i)
+    if (frange_cmp (r, m_pairs[i].min) >= 0
+	&& frange_cmp (r, m_pairs[i].max) <= 0)
+      return true;
+
+  return false;
 }
 
 // If range is a singleton, place it in RESULT and return TRUE.  If
@@ -1415,7 +1434,9 @@ frange::contains_p (const REAL_VALUE_TYPE &r) const
 bool
 frange::internal_singleton_p (REAL_VALUE_TYPE *result) const
 {
-  if (m_kind == VR_RANGE && real_identical (&m_min, &m_max))
+  if (m_kind == VR_RANGE
+      && m_num_ranges == 1
+      && real_identical (&m_pairs[0].min, &m_pairs[0].max))
     {
       // Return false for any singleton that may be a NAN.
       if (HONOR_NANS (m_type) && maybe_isnan ())
@@ -1428,16 +1449,16 @@ frange::internal_singleton_p (REAL_VALUE_TYPE *result) const
 	  // or -0.0.  Since this means there is more than one way to
 	  // represent a value, return false to avoid propagating it.
 	  // See libgcc/config/rs6000/ibm-ldouble-format for details.
-	  if (real_isinf (&m_min))
+	  if (real_isinf (&m_pairs[0].min))
 	    return false;
 	  REAL_VALUE_TYPE r;
-	  real_convert (&r, DFmode, &m_min);
-	  if (real_identical (&r, &m_min))
+	  real_convert (&r, DFmode, &m_pairs[0].min);
+	  if (real_identical (&r, &m_pairs[0].min))
 	    return false;
 	}
 
       if (result)
-	*result = m_min;
+	*result = m_pairs[0].min;
       return true;
     }
   return false;
@@ -1449,7 +1470,7 @@ frange::singleton_p (tree *result) const
   if (internal_singleton_p ())
     {
       if (result)
-	*result = build_real (m_type, m_min);
+	*result = build_real (m_type, m_pairs[0].min);
       return true;
     }
   return false;
@@ -1479,8 +1500,9 @@ frange::verify_range () const
       return;
     case VR_VARYING:
       gcc_checking_assert (m_type);
-      gcc_checking_assert (frange_val_is_min (m_min, m_type));
-      gcc_checking_assert (frange_val_is_max (m_max, m_type));
+      gcc_checking_assert (m_num_ranges == 1);
+      gcc_checking_assert (frange_val_is_min (m_pairs[0].min, m_type));
+      gcc_checking_assert (frange_val_is_max (m_pairs[0].max, m_type));
       if (HONOR_NANS (m_type))
 	gcc_checking_assert (m_pos_nan && m_neg_nan);
       else
@@ -1497,24 +1519,32 @@ frange::verify_range () const
       gcc_unreachable ();
     }
 
-  // NANs cannot appear in the endpoints of a range.
-  gcc_checking_assert (!real_isnan (&m_min) && !real_isnan (&m_max));
+  for (unsigned i = 0; i < m_num_ranges; ++i)
+    {
+      // NANs cannot appear in the endpoints of a range.
+      gcc_checking_assert (!real_isnan (&m_pairs[i].min)
+			   && !real_isnan (&m_pairs[i].max));
 
-  // Make sure we don't have swapped ranges.  This also catches [ +0.0, -0.0].
-  gcc_checking_assert (frange_cmp (m_min, m_max) <= 0);
+      // Make sure we don't have swapped ranges.
+      // This also catches [ +0.0, -0.0].
+      gcc_checking_assert (frange_cmp (m_pairs[i].min, m_pairs[i].max) <= 0);
 
-  // A zero endpoint must carry its canonical sign.  Every producer runs
-  // canonicalize_zeros, so a zero bound can only descend from a canonical one.
-  if (!MODE_HAS_SIGNED_ZEROS (TYPE_MODE (m_type)))
-    gcc_checking_assert (!real_iszero (&m_min, 1) && !real_iszero (&m_max, 1));
-  else if (!HONOR_SIGNED_ZEROS (m_type))
-    gcc_checking_assert (!real_iszero (&m_min, 0) && !real_iszero (&m_max, 1));
+      // A zero endpoint must carry its canonical sign.  Every producer runs
+      // canonicalize_zeros, so a zero bound can only descend from a canonical
+      // one.
+      if (!MODE_HAS_SIGNED_ZEROS (TYPE_MODE (m_type)))
+	gcc_checking_assert (!real_iszero (&m_pairs[i].min, 1)
+			     && !real_iszero (&m_pairs[i].max, 1));
+      else if (!HONOR_SIGNED_ZEROS (m_type))
+	gcc_checking_assert (!real_iszero (&m_pairs[i].min, 0)
+			     && !real_iszero (&m_pairs[i].max, 1));
+    }
 
   // If all the properties are clear, we better not span the entire
   // domain, because that would make us varying.
-  if (m_pos_nan && m_neg_nan)
-    gcc_checking_assert (!frange_val_is_min (m_min, m_type)
-			 || !frange_val_is_max (m_max, m_type));
+  if (m_num_ranges == 1 && m_pos_nan && m_neg_nan)
+    gcc_checking_assert (!frange_val_is_min (m_pairs[0].min, m_type)
+			 || !frange_val_is_max (m_pairs[0].max, m_type));
 }
 
 // We can't do much with nonzeros yet.
@@ -1552,8 +1582,9 @@ bool
 frange::zero_p () const
 {
   return (m_kind == VR_RANGE
-	  && real_iszero (&m_min)
-	  && real_iszero (&m_max));
+	  && m_num_ranges == 1
+	  && real_iszero (&m_pairs[0].min)
+	  && real_iszero (&m_pairs[0].max));
 }
 
 // Set the range to non-negative numbers, that is [+0.0, +INF].
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 5bea3cbc9d4c..2ea0006ba9fd 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -584,10 +584,18 @@ nan_state::neg_p () const
   return m_neg_nan;
 }
 
+// A sub-range in an frange.
+
+struct frange_pair
+{
+  REAL_VALUE_TYPE min;
+  REAL_VALUE_TYPE max;
+};
+
 // A subset of possible values for a floating point type.
 //
-// The representation is a type with a couple of endpoints, unioned
-// with a subset of { -NaN, +NaN }.
+// The representation is a single interval, unioned with a subset of
+// { -NaN, +NaN }.
 
 class frange final : public vrange
 {
@@ -657,6 +665,11 @@ public:
   bool known_isnormal () const;
   bool known_isdenormal_or_zero () const;
   virtual void verify_range () const override;
+
+  static const unsigned int MAX_PAIRS = 1;
+  unsigned num_pairs () const { return m_num_ranges; }
+  const REAL_VALUE_TYPE &lower_bound (unsigned pair) const;
+  const REAL_VALUE_TYPE &upper_bound (unsigned pair) const;
 protected:
   virtual bool contains_p (tree cst) const override;
   virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
@@ -666,11 +679,11 @@ private:
   bool normalize_kind ();
   bool union_nans (const frange &);
   bool intersect_nans (const frange &);
-  void canonicalize_zeros (REAL_VALUE_TYPE &, REAL_VALUE_TYPE &);
+  void canonicalize_zeros (frange_pair &);
 
   tree m_type;
-  REAL_VALUE_TYPE m_min;
-  REAL_VALUE_TYPE m_max;
+  frange_pair m_pairs[MAX_PAIRS];
+  unsigned char m_num_ranges;
   bool m_pos_nan;
   bool m_neg_nan;
 };
@@ -679,14 +692,30 @@ inline const REAL_VALUE_TYPE &
 frange::lower_bound () const
 {
   gcc_checking_assert (!undefined_p () && !known_isnan ());
-  return m_min;
+  return m_pairs[0].min;
 }
 
 inline const REAL_VALUE_TYPE &
 frange::upper_bound () const
 {
   gcc_checking_assert (!undefined_p () && !known_isnan ());
-  return m_max;
+  return m_pairs[m_num_ranges - 1].max;
+}
+
+inline const REAL_VALUE_TYPE &
+frange::lower_bound (unsigned pair) const
+{
+  gcc_checking_assert (!undefined_p () && !known_isnan ());
+  gcc_checking_assert (pair < m_num_ranges);
+  return m_pairs[pair].min;
+}
+
+inline const REAL_VALUE_TYPE &
+frange::upper_bound (unsigned pair) const
+{
+  gcc_checking_assert (!undefined_p () && !known_isnan ());
+  gcc_checking_assert (pair < m_num_ranges);
+  return m_pairs[pair].max;
 }
 
 // Return the NAN state.
@@ -1634,8 +1663,9 @@ frange::set_varying (tree type)
 {
   m_kind = VR_VARYING;
   m_type = type;
-  m_min = frange_val_min (type);
-  m_max = frange_val_max (type);
+  m_num_ranges = 1;
+  m_pairs[0].min = frange_val_min (type);
+  m_pairs[0].max = frange_val_max (type);
   if (HONOR_NANS (m_type))
     {
       m_pos_nan = true;
@@ -1653,9 +1683,10 @@ frange::set_undefined ()
 {
   m_kind = VR_UNDEFINED;
   m_type = NULL;
+  m_num_ranges = 1;
   m_pos_nan = false;
   m_neg_nan = false;
-  // m_min and m_min are uninitialized as they are REAL_VALUE_TYPE ??.
+  // Leave the rest undefined; as it speeds up initializing undefined ranges.
   if (flag_checking)
     verify_range ();
 }
@@ -1789,6 +1820,7 @@ frange::set_nan (tree type, const nan_state &nan)
     {
       m_kind = VR_NAN;
       m_type = type;
+      m_num_ranges = 1;
       m_neg_nan = nan.neg_p ();
       m_pos_nan = nan.pos_p ();
       if (flag_checking)
@@ -1823,7 +1855,9 @@ frange::known_isfinite () const
 {
   if (undefined_p () || varying_p () || m_kind == VR_ANTI_RANGE)
     return false;
-  return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max));
+  return (!maybe_isnan ()
+	  && !real_isinf (&lower_bound ())
+	  && !real_isinf (&upper_bound ()));
 }
 
 // Return TRUE if range is known to be normal.
@@ -1835,9 +1869,11 @@ frange::known_isnormal () const
     return false;
 
   machine_mode mode = TYPE_MODE (type ());
-  return (!real_isdenormal (&m_min, mode) && !real_isdenormal (&m_max, mode)
-	  && !real_iszero (&m_min) && !real_iszero (&m_max)
-	  && (!real_isneg (&m_min) || real_isneg (&m_max)));
+  const REAL_VALUE_TYPE &min = lower_bound ();
+  const REAL_VALUE_TYPE &max = upper_bound ();
+  return (!real_isdenormal (&min, mode) && !real_isdenormal (&max, mode)
+	  && !real_iszero (&min) && !real_iszero (&max)
+	  && (!real_isneg (&min) || real_isneg (&max)));
 }
 
 // Return TRUE if range is known to be denormal.
@@ -1849,8 +1885,10 @@ frange::known_isdenormal_or_zero () const
     return false;
 
   machine_mode mode = TYPE_MODE (type ());
-  return ((real_isdenormal (&m_min, mode) || real_iszero (&m_min))
-	  && (real_isdenormal (&m_max, mode) || real_iszero (&m_max)));
+  const REAL_VALUE_TYPE &min = lower_bound ();
+  const REAL_VALUE_TYPE &max = upper_bound ();
+  return ((real_isdenormal (&min, mode) || real_iszero (&min))
+	  && (real_isdenormal (&max, mode) || real_iszero (&max)));
 }
 
 // Return TRUE if range may be infinite.
@@ -1862,7 +1900,7 @@ frange::maybe_isinf () const
     return false;
   if (varying_p ())
     return true;
-  return real_isinf (&m_min) || real_isinf (&m_max);
+  return real_isinf (&lower_bound ()) || real_isinf (&upper_bound ());
 }
 
 // Return TRUE if range is known to be the [-INF,-INF] or [+INF,+INF].
@@ -1871,9 +1909,10 @@ inline bool
 frange::known_isinf () const
 {
   return (m_kind == VR_RANGE
+	  && m_num_ranges == 1
 	  && !maybe_isnan ()
-	  && real_identical (&m_min, &m_max)
-	  && real_isinf (&m_min));
+	  && real_identical (&m_pairs[0].min, &m_pairs[0].max)
+	  && real_isinf (&m_pairs[0].min));
 }
 
 // Return TRUE if range is possibly a NAN.
@@ -1921,9 +1960,9 @@ frange::signbit_p (bool &signbit) const
   // No NAN.
   if (!m_pos_nan && !m_neg_nan)
     {
-      if (m_min.sign == m_max.sign)
+      if (lower_bound ().sign == upper_bound ().sign)
 	{
-	  signbit = m_min.sign;
+	  signbit = lower_bound ().sign;
 	  return true;
 	}
       return false;
@@ -1931,7 +1970,8 @@ frange::signbit_p (bool &signbit) const
   // NAN with known sign.
   bool nan_sign = m_neg_nan;
   if (known_isnan ()
-      || (nan_sign == m_min.sign && nan_sign == m_max.sign))
+      || (nan_sign == lower_bound ().sign
+	  && nan_sign == upper_bound ().sign))
     {
       signbit = nan_sign;
       return true;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.