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
//
// 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.
//
// 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;
}
}
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 ();
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.
{
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.
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))
{
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;
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)
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;
}
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;
{
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;
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));
}
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
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 ())
// 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;
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;
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
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.
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].
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
{
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;
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;
};
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.
{
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;
{
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 ();
}
{
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)
{
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.
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.
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.
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].
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.
// 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;
// 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;