aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/range-op-float.cc79
-rw-r--r--gcc/value-query.cc9
-rw-r--r--gcc/value-range-pretty-print.cc14
-rw-r--r--gcc/value-range-storage.cc12
-rw-r--r--gcc/value-range.cc462
-rw-r--r--gcc/value-range.h88
6 files changed, 585 insertions, 79 deletions
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index ff9fe31..ca41136 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -150,6 +150,18 @@ range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) cons
return VREL_VARYING;
}
+// Set R to [NAN, NAN].
+
+static inline void
+frange_set_nan (frange &r, tree type)
+{
+ REAL_VALUE_TYPE rv;
+ bool res = real_nan (&rv, "", 1, TYPE_MODE (type));
+ if (flag_checking)
+ gcc_assert (res);
+ r.set (type, rv, rv);
+}
+
// Return TRUE if OP1 and OP2 are known to be free of NANs.
static inline bool
@@ -178,6 +190,40 @@ frelop_early_resolve (irange &r, tree type,
&& relop_early_resolve (r, type, op1, op2, rel, my_rel));
}
+// Crop R to [-INF, MAX] where MAX is the maximum representable number
+// for TYPE.
+
+static inline void
+frange_drop_inf (frange &r, tree type)
+{
+ // FIXME: build_real() bails on decimal float modes when called with
+ // a max representable endpoint.
+ if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
+ return;
+
+ REAL_VALUE_TYPE max;
+ real_max_representable (&max, type);
+ frange tmp (type, r.lower_bound (), max);
+ r.intersect (tmp);
+}
+
+// Crop R to [MIN, +INF] where MIN is the minimum representable number
+// for TYPE.
+
+static inline void
+frange_drop_ninf (frange &r, tree type)
+{
+ // FIXME: build_real() bails on decimal float modes when called with
+ // a max representable endpoint.
+ if (DECIMAL_FLOAT_MODE_P (TYPE_MODE (type)))
+ return;
+
+ REAL_VALUE_TYPE min;
+ real_min_representable (&min, type);
+ frange tmp (type, min, r.upper_bound ());
+ r.intersect (tmp);
+}
+
// Default implementation of fold_range for relational operators.
// This amounts to passing on any known relations from the oracle, iff
// we know the operands are not NAN or -ffinite-math-only holds.
@@ -252,21 +298,8 @@ foperator_equal::op1_range (frange &r, tree type,
switch (get_bool_state (r, lhs, type))
{
case BRS_TRUE:
- if (HONOR_SIGNED_ZEROS (type)
- && op2.contains_p (build_zero_cst (type)))
- {
- // With signed zeros, x == -0.0 does not mean we can replace
- // x with -0.0, because x may be either +0.0 or -0.0.
- r.set_varying (type);
- }
- else
- {
- // If it's true, the result is the same as OP2.
- //
- // If the range does not actually contain zeros, this should
- // always be OK.
- r = op2;
- }
+ // If it's true, the result is the same as OP2.
+ r = op2;
// The TRUE side of op1 == op2 implies op1 is !NAN.
r.set_nan (fp_prop::NO);
break;
@@ -275,7 +308,7 @@ foperator_equal::op1_range (frange &r, tree type,
r.set_varying (type);
// The FALSE side of op1 == op1 implies op1 is a NAN.
if (rel == VREL_EQ)
- r.set_nan (fp_prop::YES);
+ frange_set_nan (r, type);
break;
default:
@@ -365,7 +398,8 @@ foperator_lt::op1_range (frange &r,
r.set_varying (type);
// The TRUE side of op1 < op2 implies op1 is !NAN and !INF.
r.set_nan (fp_prop::NO);
- r.set_inf (fp_prop::NO);
+ // x < y implies x is not +INF.
+ frange_drop_inf (r, type);
break;
case BRS_FALSE:
@@ -391,7 +425,8 @@ foperator_lt::op2_range (frange &r,
r.set_varying (type);
// The TRUE side of op1 < op2 implies op2 is !NAN and !NINF.
r.set_nan (fp_prop::NO);
- r.set_ninf (fp_prop::NO);
+ // x < y implies y is not -INF.
+ frange_drop_ninf (r, type);
break;
case BRS_FALSE:
@@ -493,7 +528,8 @@ foperator_gt::op1_range (frange &r,
r.set_varying (type);
// The TRUE side of op1 > op2 implies op1 is !NAN and !NINF.
r.set_nan (fp_prop::NO);
- r.set_ninf (fp_prop::NO);
+ // x > y implies x is not -INF.
+ frange_drop_ninf (r, type);
break;
case BRS_FALSE:
@@ -519,7 +555,8 @@ foperator_gt::op2_range (frange &r,
r.set_varying (type);
// The TRUE side of op1 > op2 implies op2 is !NAN and !INF.
r.set_nan (fp_prop::NO);
- r.set_inf (fp_prop::NO);
+ // x > y implies y is not +INF.
+ frange_drop_inf (r, type);
break;
case BRS_FALSE:
@@ -636,7 +673,7 @@ foperator_unordered::op1_range (frange &r, tree type,
// Since at least one operand must be NAN, if one of them is
// not, the other must be.
if (op2.get_nan ().no_p ())
- r.set_nan (fp_prop::YES);
+ frange_set_nan (r, type);
break;
case BRS_FALSE:
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 4af8eca..4637fb4 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -211,10 +211,19 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
switch (TREE_CODE (expr))
{
case INTEGER_CST:
+ if (TREE_OVERFLOW_P (expr))
+ expr = drop_tree_overflow (expr);
+ r.set (expr, expr);
+ return true;
+
case REAL_CST:
if (TREE_OVERFLOW_P (expr))
expr = drop_tree_overflow (expr);
r.set (expr, expr);
+ if (real_isnan (TREE_REAL_CST_PTR (expr)))
+ as_a <frange> (r).set_nan (fp_prop::YES);
+ else
+ as_a <frange> (r).set_nan (fp_prop::NO);
return true;
case SSA_NAME:
diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc
index cbf50d3..e66d56d 100644
--- a/gcc/value-range-pretty-print.cc
+++ b/gcc/value-range-pretty-print.cc
@@ -122,22 +122,30 @@ vrange_printer::print_irange_bitmasks (const irange &r) const
void
vrange_printer::visit (const frange &r) const
{
+ tree type = r.type ();
+
pp_string (pp, "[frange] ");
if (r.undefined_p ())
{
pp_string (pp, "UNDEFINED");
return;
}
- dump_generic_node (pp, r.type (), 0, TDF_NONE, false);
+ dump_generic_node (pp, type, 0, TDF_NONE, false);
pp_string (pp, " ");
if (r.varying_p ())
{
pp_string (pp, "VARYING");
return;
}
+ pp_character (pp, '[');
+ dump_generic_node (pp,
+ build_real (type, r.lower_bound ()), 0, TDF_NONE, false);
+ pp_string (pp, ", ");
+ dump_generic_node (pp,
+ build_real (type, r.upper_bound ()), 0, TDF_NONE, false);
+ pp_string (pp, "] ");
+
print_frange_prop ("NAN", r.get_nan ());
- print_frange_prop ("INF", r.get_inf ());
- print_frange_prop ("NINF", r.get_ninf ());
}
// Print the FP properties in an frange.
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index ea3b83c..adf23c3 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -261,6 +261,18 @@ frange_storage_slot::get_frange (frange &r, tree type) const
{
gcc_checking_assert (r.supports_type_p (type));
+ // FIXME: NANs get special treatment, because we need [NAN, NAN] in
+ // the range to properly represent it, not just the NAN flag in the
+ // property bits. This will go away when we stream out the
+ // endpoints.
+ if (m_props.get_nan ().yes_p ())
+ {
+ REAL_VALUE_TYPE rv;
+ real_nan (&rv, "", 1, TYPE_MODE (type));
+ r.set (type, rv, rv);
+ return;
+ }
+
r.set_varying (type);
r.m_props = m_props;
r.normalize_kind ();
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index edd10bf..bcc6651 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -291,41 +291,20 @@ frange::set (tree min, tree max, value_range_kind kind)
m_kind = kind;
m_type = TREE_TYPE (min);
m_props.set_varying ();
+ m_min = *TREE_REAL_CST_PTR (min);
+ m_max = *TREE_REAL_CST_PTR (max);
- bool is_min = vrp_val_is_min (min);
- bool is_max = vrp_val_is_max (max);
bool is_nan = (real_isnan (TREE_REAL_CST_PTR (min))
|| real_isnan (TREE_REAL_CST_PTR (max)));
// Ranges with a NAN and a non-NAN endpoint are nonsensical.
gcc_checking_assert (!is_nan || operand_equal_p (min, max));
- // The properties for singletons can be all set ahead of time.
- if (operand_equal_p (min, max))
- {
- // Set INF properties.
- if (is_min)
- m_props.ninf_set_yes ();
- else
- m_props.ninf_set_no ();
- if (is_max)
- m_props.inf_set_yes ();
- else
- m_props.inf_set_no ();
- // Set NAN property.
- if (is_nan)
- m_props.nan_set_yes ();
- else
- m_props.nan_set_no ();
- }
- else
- {
- // Mark when the endpoints can't be +-INF.
- if (!is_min)
- m_props.ninf_set_no ();
- if (!is_max)
- m_props.inf_set_no ();
- }
+ // Set NAN property if we're absolutely sure.
+ if (is_nan && operand_equal_p (min, max))
+ m_props.nan_set_yes ();
+ else if (!HONOR_NANS (m_type))
+ m_props.nan_set_no ();
// Check for swapped ranges.
gcc_checking_assert (is_nan || tree_compare (LE_EXPR, min, max));
@@ -336,6 +315,16 @@ frange::set (tree min, tree max, value_range_kind kind)
verify_range ();
}
+// Setter for frange from REAL_VALUE_TYPE endpoints.
+
+void
+frange::set (tree type,
+ const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max,
+ value_range_kind kind)
+{
+ set (build_real (type, min), build_real (type, max), kind);
+}
+
// Normalize range to VARYING or UNDEFINED, or vice versa. Return
// TRUE if anything changed.
//
@@ -347,7 +336,15 @@ frange::set (tree min, tree max, value_range_kind kind)
bool
frange::normalize_kind ()
{
- if (m_kind == VR_RANGE)
+ // Undefined is viral.
+ if (m_props.nan_undefined_p ())
+ {
+ set_undefined ();
+ return true;
+ }
+ if (m_kind == VR_RANGE
+ && real_isinf (&m_min, 1)
+ && real_isinf (&m_max, 0))
{
// No FP properties set means varying.
if (m_props.varying_p ())
@@ -355,14 +352,6 @@ frange::normalize_kind ()
set_varying (m_type);
return true;
}
- // Undefined is viral.
- if (m_props.nan_undefined_p ()
- || m_props.inf_undefined_p ()
- || m_props.ninf_undefined_p ())
- {
- set_undefined ();
- return true;
- }
}
else if (m_kind == VR_VARYING)
{
@@ -370,12 +359,32 @@ frange::normalize_kind ()
if (!m_props.varying_p ())
{
m_kind = VR_RANGE;
+ real_inf (&m_min, 1);
+ real_inf (&m_max, 0);
return true;
}
}
return false;
}
+// If both operands are definitely NAN, do nothing as they combine
+// perfectly. If OTOH, only one is a NAN, set R to VARYING as they
+// can't be neither unioned nor intersected. Return TRUE if we
+// changed anything.
+
+static inline bool
+early_nan_resolve (frange &r, const frange &other)
+{
+ gcc_checking_assert (r.get_nan ().yes_p () || other.get_nan ().yes_p ());
+
+ // There's nothing to do for both NANs.
+ if (r.get_nan ().yes_p () == other.get_nan ().yes_p ())
+ return false;
+ // But only one NAN complicates things.
+ r.set_varying (r.type ());
+ return true;
+}
+
bool
frange::union_ (const vrange &v)
{
@@ -388,13 +397,34 @@ frange::union_ (const vrange &v)
*this = r;
return true;
}
+ // ?? We could do better here. [5,6] U NAN should be [5,6] with the
+ // NAN maybe bits set. For now, this is conservatively correct.
+ if (get_nan ().yes_p () || r.get_nan ().yes_p ())
+ return early_nan_resolve (*this, r);
- bool ret = m_props.union_ (r.m_props);
- ret |= normalize_kind ();
+ bool changed = m_props.union_ (r.m_props);
+
+ // Note: for the combination of zeros that differ in sign we keep
+ // the endpoints untouched. This means that for -0.0 U +0.0, the
+ // result will be -0.0. Ultimately this doesn't matter, because we
+ // keep singleton zeros ambiguous throughout to avoid propagating
+ // them. See frange::singleton_p().
+
+ if (real_less (&r.m_min, &m_min))
+ {
+ m_min = r.m_min;
+ changed = true;
+ }
+ if (real_less (&m_max, &r.m_max))
+ {
+ m_max = r.m_max;
+ changed = true;
+ }
+ changed |= normalize_kind ();
if (flag_checking)
verify_range ();
- return ret;
+ return changed;
}
bool
@@ -414,13 +444,38 @@ frange::intersect (const vrange &v)
*this = r;
return true;
}
+ if (get_nan ().yes_p () || r.get_nan ().yes_p ())
+ return early_nan_resolve (*this, r);
+
+ bool changed = m_props.intersect (r.m_props);
+
+ // Note: for the combination of zeros that differ in sign we keep
+ // the endpoints untouched. This means that for -0.0 ^ +0.0, the
+ // result will be -0.0. Ultimately this doesn't matter, because we
+ // keep singleton zeros ambiguous throughout to avoid propagating
+ // them. See frange::singleton_p().
- bool ret = m_props.intersect (r.m_props);
- ret |= normalize_kind ();
+ if (real_less (&m_min, &r.m_min))
+ {
+ m_min = r.m_min;
+ changed = true;
+ }
+ if (real_less (&r.m_max, &m_max))
+ {
+ m_max = r.m_max;
+ changed = true;
+ }
+ // If the endpoints are swapped, the ranges are disjoint.
+ if (real_less (&m_max, &m_min))
+ {
+ set_undefined ();
+ return true;
+ }
+ changed |= normalize_kind ();
if (flag_checking)
verify_range ();
- return ret;
+ return changed;
}
frange &
@@ -428,6 +483,8 @@ 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_props = src.m_props;
if (flag_checking)
@@ -446,7 +503,59 @@ frange::operator== (const frange &src) const
if (varying_p ())
return types_compatible_p (m_type, src.m_type);
- return m_props == src.m_props;
+ if (m_props.get_nan ().yes_p ()
+ || src.m_props.get_nan ().yes_p ())
+ return false;
+
+ return (real_identical (&m_min, &src.m_min)
+ && real_identical (&m_max, &src.m_max)
+ && m_props == src.m_props
+ && types_compatible_p (m_type, src.m_type));
+ }
+ return false;
+}
+
+// Return TRUE if range contains the TREE_REAL_CST_PTR in CST.
+
+bool
+frange::contains_p (tree cst) const
+{
+ if (undefined_p ())
+ return false;
+
+ if (varying_p ())
+ return true;
+
+ gcc_checking_assert (m_kind == VR_RANGE);
+
+ return (real_compare (GE_EXPR, TREE_REAL_CST_PTR (cst), &m_min)
+ && real_compare (LE_EXPR, TREE_REAL_CST_PTR (cst), &m_max));
+}
+
+// If range is a singleton, place it in RESULT and return TRUE. If
+// RESULT is NULL, just return TRUE.
+//
+// A NAN can never be a singleton, and neither can a 0.0 if we're
+// honoring signed zeros because we have no way of telling which zero
+// it is.
+
+bool
+frange::singleton_p (tree *result) const
+{
+ if (m_kind == VR_RANGE && real_identical (&m_min, &m_max))
+ {
+ // If we're honoring signed zeros, fail because we don't know
+ // which zero we have. This avoids propagating the wrong zero.
+ if (HONOR_SIGNED_ZEROS (m_type) && zero_p ())
+ return false;
+
+ // Return false for any singleton that may be a NAN.
+ if (HONOR_NANS (m_type) && !get_nan ().no_p ())
+ return false;
+
+ if (result)
+ *result = build_real (m_type, m_min);
+ return true;
}
return false;
}
@@ -465,13 +574,82 @@ frange::verify_range ()
gcc_checking_assert (m_props.undefined_p ());
return;
}
+ gcc_checking_assert (!m_props.undefined_p ());
+
if (varying_p ())
{
gcc_checking_assert (m_props.varying_p ());
return;
}
+
+ // We don't support the inverse of an frange (yet).
gcc_checking_assert (m_kind == VR_RANGE);
- gcc_checking_assert (!m_props.varying_p () && !m_props.undefined_p ());
+
+ bool is_nan = real_isnan (&m_min) || real_isnan (&m_max);
+ if (is_nan)
+ {
+ // If either is a NAN, both must be a NAN.
+ gcc_checking_assert (real_identical (&m_min, &m_max));
+ gcc_checking_assert (get_nan ().yes_p ());
+ }
+ else
+ // Make sure we don't have swapped ranges.
+ gcc_checking_assert (!real_less (&m_max, &m_min));
+
+ // If we're absolutely sure we have a NAN, the endpoints should
+ // reflect this, otherwise we'd have more than one way to represent
+ // a NAN.
+ if (m_props.get_nan ().yes_p ())
+ {
+ gcc_checking_assert (real_isnan (&m_min));
+ gcc_checking_assert (real_isnan (&m_max));
+ }
+
+ // If all the properties are clear, we better not span the entire
+ // domain, because that would make us varying.
+ if (m_props.varying_p ())
+ gcc_checking_assert (!real_isinf (&m_min, 1) || !real_isinf (&m_max, 0));
+}
+
+// We can't do much with nonzeros yet.
+void
+frange::set_nonzero (tree type)
+{
+ set_varying (type);
+}
+
+// We can't do much with nonzeros yet.
+bool
+frange::nonzero_p () const
+{
+ return false;
+}
+
+// Set range to [+0.0, +0.0].
+
+void
+frange::set_zero (tree type)
+{
+ tree zero = build_zero_cst (type);
+ set (zero, zero);
+}
+
+// Return TRUE for any [0.0, 0.0] regardless of sign.
+
+bool
+frange::zero_p () const
+{
+ return (m_kind == VR_RANGE
+ && real_iszero (&m_min)
+ && real_iszero (&m_max));
+}
+
+void
+frange::set_nonnegative (tree type)
+{
+ tree zero = build_zero_cst (type);
+ tree inf = vrp_val_max (type);
+ set (zero, inf);
}
// Here we copy between any two irange's. The ranges can be legacy or
@@ -3304,6 +3482,199 @@ range_tests_nonzero_bits ()
ASSERT_TRUE (r0.varying_p ());
}
+// Build an frange from string endpoints.
+
+static inline frange
+frange_float (const char *lb, const char *ub, tree type = float_type_node)
+{
+ REAL_VALUE_TYPE min, max;
+ gcc_assert (real_from_string (&min, lb) == 0);
+ gcc_assert (real_from_string (&max, ub) == 0);
+ return frange (type, min, max);
+}
+
+// Build a NAN of type TYPE.
+
+static inline frange
+frange_nan (tree type = float_type_node)
+{
+ REAL_VALUE_TYPE r;
+
+ gcc_assert (real_nan (&r, "", 1, TYPE_MODE (type)));
+ return frange (type, r, r);
+}
+
+static void
+range_tests_nan ()
+{
+ frange r0, r1;
+
+ // Equal ranges but with differing NAN bits are not equal.
+ r1 = frange_float ("10", "12");
+ r0 = r1;
+ ASSERT_EQ (r0, r1);
+ r0.set_nan (fp_prop::NO);
+ ASSERT_NE (r0, r1);
+ r0.set_nan (fp_prop::YES);
+ ASSERT_NE (r0, r1);
+ r0.set_nan (fp_prop::VARYING);
+ ASSERT_EQ (r0, r1);
+
+ // NAN ranges are not equal to each other.
+ r0 = frange_nan ();
+ r1 = r0;
+ ASSERT_FALSE (r0 == r1);
+ ASSERT_FALSE (r0 == r0);
+ ASSERT_TRUE (r0 != r0);
+
+ // Make sure that combining NAN and INF doesn't give any crazy results.
+ r0 = frange_nan ();
+ ASSERT_TRUE (r0.get_nan ().yes_p ());
+ r1 = frange_float ("+Inf", "+Inf");
+ r0.union_ (r1);
+ // [INF, INF] U NAN = VARYING
+ ASSERT_TRUE (r0.varying_p ());
+
+ // [INF, INF] ^ NAN = VARYING
+ r0 = frange_nan ();
+ r1 = frange_float ("+Inf", "+Inf");
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.varying_p ());
+
+ // NAN ^ NAN = NAN
+ r0 = frange_nan ();
+ r1 = frange_nan ();
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.get_nan ().yes_p ());
+
+ // VARYING ^ NAN = NAN.
+ r0 = frange_nan ();
+ r1.set_varying (float_type_node);
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.get_nan ().yes_p ());
+}
+
+static void
+range_tests_signed_zeros ()
+{
+ tree zero = build_zero_cst (float_type_node);
+ tree neg_zero = fold_build1 (NEGATE_EXPR, float_type_node, zero);
+ frange r0, r1;
+
+ // ?? If -0.0 == +0.0, then a range of [-0.0, -0.0] should
+ // contain +0.0 and vice versa. We probably need a property to
+ // track signed zeros in the frange like we do for NAN, to
+ // properly model all this.
+ r0 = frange (zero, zero);
+ r1 = frange (neg_zero, neg_zero);
+ ASSERT_TRUE (r0.contains_p (zero));
+ ASSERT_TRUE (r0.contains_p (neg_zero));
+ ASSERT_TRUE (r1.contains_p (zero));
+ ASSERT_TRUE (r1.contains_p (neg_zero));
+}
+
+static void
+range_tests_floats ()
+{
+ frange r0, r1;
+
+ range_tests_nan ();
+
+ if (HONOR_SIGNED_ZEROS (float_type_node))
+ range_tests_signed_zeros ();
+
+ // A range of [-INF,+INF] is actually VARYING...
+ r0 = frange_float ("-Inf", "+Inf");
+ ASSERT_TRUE (r0.varying_p ());
+ // ...unless it has some special property...
+ r0.set_nan (fp_prop::NO);
+ ASSERT_FALSE (r0.varying_p ());
+
+ // The endpoints of a VARYING are +-INF.
+ REAL_VALUE_TYPE inf, ninf;
+ real_inf (&inf, 0);
+ real_inf (&ninf, 1);
+ r0.set_varying (float_type_node);
+ ASSERT_TRUE (real_identical (&r0.lower_bound (), &ninf));
+ ASSERT_TRUE (real_identical (&r0.upper_bound (), &inf));
+
+ // The maximum representable range for a type is still a subset of VARYING.
+ REAL_VALUE_TYPE q, r;
+ real_min_representable (&q, float_type_node);
+ real_max_representable (&r, float_type_node);
+ r0 = frange (float_type_node, q, r);
+ // r0 is not a varying, because it does not include -INF/+INF.
+ ASSERT_FALSE (r0.varying_p ());
+ // The upper bound of r0 must be less than +INF.
+ ASSERT_TRUE (real_less (&r0.upper_bound (), &inf));
+ // The lower bound of r0 must be greater than -INF.
+ ASSERT_TRUE (real_less (&ninf, &r0.lower_bound ()));
+
+ // For most architectures, where float and double are different
+ // sizes, having the same endpoints does not necessarily mean the
+ // ranges are equal.
+ if (!types_compatible_p (float_type_node, double_type_node))
+ {
+ r0 = frange_float ("3.0", "3.0", float_type_node);
+ r1 = frange_float ("3.0", "3.0", double_type_node);
+ ASSERT_NE (r0, r1);
+ }
+
+ // [3,5] U [10,12] = [3,12].
+ r0 = frange_float ("3", "5");
+ r1 = frange_float ("10", "12");
+ r0.union_ (r1);
+ ASSERT_EQ (r0, frange_float ("3", "12"));
+
+ // [5,10] U [4,8] = [4,10]
+ r0 = frange_float ("5", "10");
+ r1 = frange_float ("4", "8");
+ r0.union_ (r1);
+ ASSERT_EQ (r0, frange_float ("4", "10"));
+
+ // [3,5] U [4,10] = [3,10]
+ r0 = frange_float ("3", "5");
+ r1 = frange_float ("4", "10");
+ r0.union_ (r1);
+ ASSERT_EQ (r0, frange_float ("3", "10"));
+
+ // [4,10] U [5,11] = [4,11]
+ r0 = frange_float ("4", "10");
+ r1 = frange_float ("5", "11");
+ r0.union_ (r1);
+ ASSERT_EQ (r0, frange_float ("4", "11"));
+
+ // [3,12] ^ [10,12] = [10,12].
+ r0 = frange_float ("3", "12");
+ r1 = frange_float ("10", "12");
+ r0.intersect (r1);
+ ASSERT_EQ (r0, frange_float ("10", "12"));
+
+ // [10,12] ^ [11,11] = [11,11]
+ r0 = frange_float ("10", "12");
+ r1 = frange_float ("11", "11");
+ r0.intersect (r1);
+ ASSERT_EQ (r0, frange_float ("11", "11"));
+
+ // [10,20] ^ [5,15] = [10,15]
+ r0 = frange_float ("10", "20");
+ r1 = frange_float ("5", "15");
+ r0.intersect (r1);
+ ASSERT_EQ (r0, frange_float ("10", "15"));
+
+ // [10,20] ^ [15,25] = [15,20]
+ r0 = frange_float ("10", "20");
+ r1 = frange_float ("15", "25");
+ r0.intersect (r1);
+ ASSERT_EQ (r0, frange_float ("15", "20"));
+
+ // [10,20] ^ [21,25] = []
+ r0 = frange_float ("10", "20");
+ r1 = frange_float ("21", "25");
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.undefined_p ());
+}
+
void
range_tests ()
{
@@ -3312,6 +3683,7 @@ range_tests ()
range_tests_int_range_max ();
range_tests_strict_enum ();
range_tests_nonzero_bits ();
+ range_tests_floats ();
range_tests_misc ();
}
diff --git a/gcc/value-range.h b/gcc/value-range.h
index f0075d0..43b231b 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -314,14 +314,10 @@ public:
bool intersect (const frange_props &other);
bool operator== (const frange_props &other) const;
FP_PROP_ACCESSOR(nan)
- FP_PROP_ACCESSOR(inf)
- FP_PROP_ACCESSOR(ninf)
private:
union {
struct {
unsigned char nan : 2;
- unsigned char inf : 2;
- unsigned char ninf : 2;
} bits;
unsigned char bytes;
} u;
@@ -345,34 +341,62 @@ class frange : public vrange
public:
frange ();
frange (const frange &);
+ frange (tree, tree, value_range_kind = VR_RANGE);
+ frange (tree type, const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max,
+ value_range_kind = VR_RANGE);
static bool supports_p (const_tree type)
{
return SCALAR_FLOAT_TYPE_P (type);
}
virtual tree type () const override;
virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
+ void set (tree type, const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &,
+ value_range_kind = VR_RANGE);
virtual void set_varying (tree type) override;
virtual void set_undefined () override;
virtual bool union_ (const vrange &) override;
virtual bool intersect (const vrange &) override;
+ virtual bool contains_p (tree) const override;
+ virtual bool singleton_p (tree *result = NULL) const override;
virtual bool supports_type_p (const_tree type) const override;
virtual void accept (const vrange_visitor &v) const override;
+ virtual bool zero_p () const;
+ virtual bool nonzero_p () const;
+ virtual void set_nonzero (tree type);
+ virtual void set_zero (tree type);
+ virtual void set_nonnegative (tree type);
frange& operator= (const frange &);
bool operator== (const frange &) const;
bool operator!= (const frange &r) const { return !(*this == r); }
+ const REAL_VALUE_TYPE &lower_bound () const;
+ const REAL_VALUE_TYPE &upper_bound () const;
// Each fp_prop can be accessed with get_PROP() and set_PROP().
FRANGE_PROP_ACCESSOR(nan)
- FRANGE_PROP_ACCESSOR(inf)
- FRANGE_PROP_ACCESSOR(ninf)
private:
void verify_range ();
bool normalize_kind ();
frange_props m_props;
tree m_type;
+ REAL_VALUE_TYPE m_min;
+ REAL_VALUE_TYPE m_max;
};
+inline const REAL_VALUE_TYPE &
+frange::lower_bound () const
+{
+ gcc_checking_assert (!undefined_p ());
+ return m_min;
+}
+
+inline const REAL_VALUE_TYPE &
+frange::upper_bound () const
+{
+ gcc_checking_assert (!undefined_p ());
+ return m_max;
+}
+
// is_a<> and as_a<> implementation for vrange.
// Anything we haven't specialized is a hard fail.
@@ -1050,10 +1074,9 @@ vrp_val_min (const_tree type)
return build_zero_cst (const_cast<tree> (type));
if (frange::supports_p (type))
{
- REAL_VALUE_TYPE real, real_ninf;
- real_inf (&real);
- real_ninf = real_value_negate (&real);
- return build_real (const_cast <tree> (type), real_ninf);
+ REAL_VALUE_TYPE ninf;
+ real_inf (&ninf, 1);
+ return build_real (const_cast <tree> (type), ninf);
}
return NULL_TREE;
}
@@ -1096,6 +1119,26 @@ frange::frange (const frange &src)
*this = src;
}
+// frange constructor from REAL_VALUE_TYPE endpoints.
+
+inline
+frange::frange (tree type,
+ const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max,
+ value_range_kind kind)
+{
+ m_discriminator = VR_FRANGE;
+ set (type, min, max, kind);
+}
+
+// frange constructor from trees.
+
+inline
+frange::frange (tree min, tree max, value_range_kind kind)
+{
+ m_discriminator = VR_FRANGE;
+ set (min, max, kind);
+}
+
inline tree
frange::type () const
{
@@ -1107,6 +1150,8 @@ frange::set_varying (tree type)
{
m_kind = VR_VARYING;
m_type = type;
+ real_inf (&m_min, 1);
+ real_inf (&m_max, 0);
m_props.set_varying ();
}
@@ -1116,6 +1161,29 @@ frange::set_undefined ()
m_kind = VR_UNDEFINED;
m_type = NULL;
m_props.set_undefined ();
+ memset (&m_min, 0, sizeof (m_min));
+ memset (&m_max, 0, sizeof (m_max));
+}
+
+// Set R to maximum representable value for TYPE.
+
+inline void
+real_max_representable (REAL_VALUE_TYPE *r, tree type)
+{
+ char buf[128];
+ get_max_float (REAL_MODE_FORMAT (TYPE_MODE (type)),
+ buf, sizeof (buf), false);
+ int res = real_from_string (r, buf);
+ gcc_checking_assert (!res);
+}
+
+// Set R to minimum representable value for TYPE.
+
+inline void
+real_min_representable (REAL_VALUE_TYPE *r, tree type)
+{
+ real_max_representable (r, type);
+ *r = real_value_negate (r);
}
#endif // GCC_VALUE_RANGE_H