aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-range-fold.cc2
-rw-r--r--gcc/range-op-float.cc38
-rw-r--r--gcc/value-query.cc11
-rw-r--r--gcc/value-range-pretty-print.cc45
-rw-r--r--gcc/value-range-pretty-print.h2
-rw-r--r--gcc/value-range-storage.cc9
-rw-r--r--gcc/value-range-storage.h7
-rw-r--r--gcc/value-range.cc621
-rw-r--r--gcc/value-range.h231
9 files changed, 481 insertions, 485 deletions
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 85ed6f9..a45fc7a 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -1030,7 +1030,7 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
if (src.get_operand (tmp, arg))
{
bool signbit;
- if (tmp.known_signbit (signbit))
+ if (tmp.signbit_p (signbit))
{
if (signbit)
r.set_nonzero (type);
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index fbc14a7..1e39a07 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -155,7 +155,7 @@ range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) cons
static inline bool
finite_operand_p (const frange &op1)
{
- return flag_finite_math_only || !op1.maybe_nan ();
+ return flag_finite_math_only || !op1.maybe_isnan ();
}
// Return TRUE if OP1 and OP2 are known to be free of NANs.
@@ -163,7 +163,7 @@ finite_operand_p (const frange &op1)
static inline bool
finite_operands_p (const frange &op1, const frange &op2)
{
- return flag_finite_math_only || (!op1.maybe_nan () && !op2.maybe_nan ());
+ return flag_finite_math_only || (!op1.maybe_isnan () && !op2.maybe_isnan ());
}
// Floating version of relop_early_resolve that takes into account NAN
@@ -213,12 +213,16 @@ frange_drop_ninf (frange &r, tree type)
static inline void
frange_add_zeros (frange &r, tree type)
{
- if (r.undefined_p () || r.known_nan ())
+ if (r.undefined_p () || r.known_isnan ())
return;
if (HONOR_SIGNED_ZEROS (type)
&& (real_iszero (&r.lower_bound ()) || real_iszero (&r.upper_bound ())))
- r.set_signbit (fp_prop::VARYING);
+ {
+ frange zero;
+ zero.set_zero (type);
+ r.union_ (zero);
+ }
}
// Build a range that is <= VAL and store it in R.
@@ -226,7 +230,7 @@ frange_add_zeros (frange &r, tree type)
static bool
build_le (frange &r, tree type, const frange &val)
{
- if (val.known_nan ())
+ if (val.known_isnan ())
{
r.set_undefined ();
return false;
@@ -244,7 +248,7 @@ build_le (frange &r, tree type, const frange &val)
static bool
build_lt (frange &r, tree type, const frange &val)
{
- if (val.known_nan ())
+ if (val.known_isnan ())
{
r.set_undefined ();
return false;
@@ -268,7 +272,7 @@ build_lt (frange &r, tree type, const frange &val)
static bool
build_ge (frange &r, tree type, const frange &val)
{
- if (val.known_nan ())
+ if (val.known_isnan ())
{
r.set_undefined ();
return false;
@@ -286,7 +290,7 @@ build_ge (frange &r, tree type, const frange &val)
static bool
build_gt (frange &r, tree type, const frange &val)
{
- if (val.known_nan ())
+ if (val.known_isnan ())
{
r.set_undefined ();
return false;
@@ -551,7 +555,7 @@ foperator_lt::fold_range (irange &r, tree type,
else
r = range_true_and_false (type);
}
- else if (op1.known_nan () || op2.known_nan ())
+ else if (op1.known_isnan () || op2.known_isnan ())
r = range_false (type);
else
r = range_true_and_false (type);
@@ -653,7 +657,7 @@ foperator_le::fold_range (irange &r, tree type,
else
r = range_true_and_false (type);
}
- else if (op1.known_nan () || op2.known_nan ())
+ else if (op1.known_isnan () || op2.known_isnan ())
r = range_false (type);
else
r = range_true_and_false (type);
@@ -747,7 +751,7 @@ foperator_gt::fold_range (irange &r, tree type,
else
r = range_true_and_false (type);
}
- else if (op1.known_nan () || op2.known_nan ())
+ else if (op1.known_isnan () || op2.known_isnan ())
r = range_false (type);
else
r = range_true_and_false (type);
@@ -849,7 +853,7 @@ foperator_ge::fold_range (irange &r, tree type,
else
r = range_true_and_false (type);
}
- else if (op1.known_nan () || op2.known_nan ())
+ else if (op1.known_isnan () || op2.known_isnan ())
r = range_false (type);
else
r = range_true_and_false (type);
@@ -932,10 +936,10 @@ foperator_unordered::fold_range (irange &r, tree type,
relation_kind) const
{
// UNORDERED is TRUE if either operand is a NAN.
- if (op1.known_nan () || op2.known_nan ())
+ if (op1.known_isnan () || op2.known_isnan ())
r = range_true (type);
// UNORDERED is FALSE if neither operand is a NAN.
- else if (!op1.maybe_nan () && !op2.maybe_nan ())
+ else if (!op1.maybe_isnan () && !op2.maybe_isnan ())
r = range_false (type);
else
r = range_true_and_false (type);
@@ -954,7 +958,7 @@ foperator_unordered::op1_range (frange &r, tree type,
r.set_varying (type);
// Since at least one operand must be NAN, if one of them is
// not, the other must be.
- if (!op2.maybe_nan ())
+ if (!op2.maybe_isnan ())
r.set_nan (type);
break;
@@ -998,9 +1002,9 @@ foperator_ordered::fold_range (irange &r, tree type,
const frange &op1, const frange &op2,
relation_kind) const
{
- if (!op1.maybe_nan () && !op2.maybe_nan ())
+ if (!op1.maybe_isnan () && !op2.maybe_isnan ())
r = range_true (type);
- else if (op1.known_nan () || op2.known_nan ())
+ else if (op1.known_isnan () || op2.known_isnan ())
r = range_false (type);
else
r = range_true_and_false (type);
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index ea6e4b9..0bdd670 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -219,17 +219,8 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
{
frange &f = as_a <frange> (r);
f.set (expr, expr);
-
- // Singletons from the tree world have known properties.
- REAL_VALUE_TYPE *rv = TREE_REAL_CST_PTR (expr);
- if (real_isnan (rv))
- f.update_nan (fp_prop::YES);
- else
+ if (!real_isnan (TREE_REAL_CST_PTR (expr)))
f.clear_nan ();
- if (real_isneg (rv))
- f.set_signbit (fp_prop::YES);
- else
- f.set_signbit (fp_prop::NO);
return true;
}
diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc
index b124e46..eb74422 100644
--- a/gcc/value-range-pretty-print.cc
+++ b/gcc/value-range-pretty-print.cc
@@ -134,34 +134,39 @@ vrange_printer::visit (const frange &r) const
if (r.varying_p ())
{
pp_string (pp, "VARYING");
+ print_frange_nan (r);
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 ("SIGN", r.get_signbit ());
+ bool has_endpoints = !r.known_isnan ();
+ if (has_endpoints)
+ {
+ 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_character (pp, ']');
+ print_frange_nan (r);
}
-// Print the FP properties in an frange.
+// Print the NAN info for an frange.
void
-vrange_printer::print_frange_prop (const char *str, const fp_prop &prop) const
+vrange_printer::print_frange_nan (const frange &r) const
{
- if (prop.varying_p ())
- return;
-
- if (prop.yes_p ())
- pp_string (pp, str);
- else if (prop.no_p ())
+ if (r.maybe_isnan ())
{
- pp_character (pp, '!');
- pp_string (pp, str);
+ if (r.m_pos_nan && r.m_neg_nan)
+ {
+ pp_string (pp, " +-NAN");
+ return;
+ }
+ bool nan_sign = r.m_neg_nan;
+ if (nan_sign)
+ pp_string (pp, " -NAN");
+ else
+ pp_string (pp, " +NAN");
}
- pp_character (pp, ' ');
}
diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h
index ad06c93..20c2659 100644
--- a/gcc/value-range-pretty-print.h
+++ b/gcc/value-range-pretty-print.h
@@ -31,7 +31,7 @@ public:
private:
void print_irange_bound (const wide_int &w, tree type) const;
void print_irange_bitmasks (const irange &) const;
- void print_frange_prop (const char *str, const fp_prop &) const;
+ void print_frange_nan (const frange &) const;
pretty_printer *pp;
};
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index b7a23fa..de7575e 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -253,9 +253,11 @@ frange_storage_slot::set_frange (const frange &r)
gcc_checking_assert (fits_p (r));
gcc_checking_assert (!r.undefined_p ());
+ m_kind = r.m_kind;
m_min = r.m_min;
m_max = r.m_max;
- m_props = r.m_props;
+ m_pos_nan = r.m_pos_nan;
+ m_neg_nan = r.m_neg_nan;
}
void
@@ -264,11 +266,12 @@ frange_storage_slot::get_frange (frange &r, tree type) const
gcc_checking_assert (r.supports_type_p (type));
r.set_undefined ();
- r.m_kind = VR_RANGE;
- r.m_props = m_props;
+ r.m_kind = m_kind;
r.m_type = type;
r.m_min = m_min;
r.m_max = m_max;
+ r.m_pos_nan = m_pos_nan;
+ r.m_neg_nan = m_neg_nan;
r.normalize_kind ();
if (flag_checking)
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index f506789..0cf95eb 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -113,12 +113,11 @@ class GTY (()) frange_storage_slot
frange_storage_slot (const frange &r) { set_frange (r); }
DISABLE_COPY_AND_ASSIGN (frange_storage_slot);
- // We can get away with just storing the properties and the
- // endpoints because the type can be gotten from the SSA, and
- // UNDEFINED is unsupported, so it can only be a VR_RANGE.
+ enum value_range_kind m_kind;
REAL_VALUE_TYPE m_min;
REAL_VALUE_TYPE m_max;
- frange_props m_props;
+ bool m_pos_nan;
+ bool m_neg_nan;
};
class obstack_vrange_allocator final: public vrange_allocator
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index d759fcf..55a216e 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -267,106 +267,24 @@ tree_compare (tree_code code, tree op1, tree op2)
return !integer_zerop (fold_build2 (code, integer_type_node, op1, op2));
}
-// Set the NAN property. Adjust the range if appopriate.
-
-void
-frange::update_nan (fp_prop::kind k)
-{
- if (k == fp_prop::YES)
- {
- if (!maybe_nan ())
- {
- set_undefined ();
- return;
- }
- gcc_checking_assert (!undefined_p ());
- set_nan (m_type);
- return;
- }
-
- if (k == fp_prop::NO && known_nan ())
- {
- set_undefined ();
- return;
- }
-
- // Setting VARYING on an obviously NAN range is a no-op.
- if (k == fp_prop::VARYING && real_isnan (&m_min))
- return;
-
- m_props.set_nan (k);
- normalize_kind ();
- if (flag_checking)
- verify_range ();
-}
-
-// Set the SIGNBIT property. Adjust the range if appropriate.
-
-void
-frange::set_signbit (fp_prop::kind k)
-{
- gcc_checking_assert (m_type);
-
- // No additional adjustments are needed for a NAN.
- if (known_nan ())
- {
- m_props.set_signbit (k);
- return;
- }
- // Ignore sign changes when they're set correctly.
- if (!maybe_nan ())
- {
- // It's negative and we're trying to make it negative or varying.
- if (real_less (&m_max, &dconst0) && (k == fp_prop::YES
- || k == fp_prop::VARYING))
- return;
- // It's positive and we're trying to make it positive or varying.
- if (real_less (&dconst0, &m_min) && (k == fp_prop::NO
- || k == fp_prop::VARYING))
- return;
- }
- // Adjust the range depending on the sign bit.
- if (k == fp_prop::YES)
- {
- // Crop the range to [-INF, 0].
- frange crop (m_type, dconstninf, dconst0);
- intersect (crop);
- if (!undefined_p ())
- m_props.set_signbit (fp_prop::YES);
- }
- else if (k == fp_prop::NO)
- {
- // Crop the range to [0, +INF].
- frange crop (m_type, dconst0, dconstinf);
- intersect (crop);
- if (!undefined_p ())
- m_props.set_signbit (fp_prop::NO);
- }
- else
- {
- m_props.set_signbit (fp_prop::VARYING);
- normalize_kind ();
- }
-
- if (flag_checking)
- verify_range ();
-}
-
// Setter for franges.
void
frange::set (tree min, tree max, value_range_kind kind)
{
- if (kind == VR_UNDEFINED)
+ switch (kind)
{
+ case VR_UNDEFINED:
set_undefined ();
return;
- }
- // Treat VR_ANTI_RANGE and VR_VARYING as varying.
- if (kind != VR_RANGE)
- {
+ case VR_VARYING:
+ case VR_ANTI_RANGE:
set_varying (TREE_TYPE (min));
return;
+ case VR_RANGE:
+ break;
+ default:
+ gcc_unreachable ();
}
// Handle NANs.
@@ -375,24 +293,25 @@ frange::set (tree min, tree max, value_range_kind kind)
gcc_checking_assert (real_identical (TREE_REAL_CST_PTR (min),
TREE_REAL_CST_PTR (max)));
tree type = TREE_TYPE (min);
- set_nan (type);
+ bool sign = real_isneg (TREE_REAL_CST_PTR (min));
+ set_nan (type, sign);
return;
}
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);
-
- // Set SIGNBIT property for positive and negative ranges.
- if (real_less (&m_max, &dconst0))
- m_props.signbit_set_yes ();
- else if (real_less (&dconst0, &m_min))
- m_props.signbit_set_no ();
-
- if (!HONOR_NANS (m_type))
- m_props.nan_set_no ();
+ if (HONOR_NANS (m_type))
+ {
+ m_pos_nan = true;
+ m_neg_nan = true;
+ }
+ else
+ {
+ m_pos_nan = false;
+ m_neg_nan = false;
+ }
// Check for swapped ranges.
gcc_checking_assert (tree_compare (LE_EXPR, min, max));
@@ -423,18 +342,11 @@ frange::set (tree type,
bool
frange::normalize_kind ()
{
- // Undefined is viral.
- if (m_props.nan_undefined_p () || m_props.signbit_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 ())
+ if (m_pos_nan && m_neg_nan)
{
set_varying (m_type);
return true;
@@ -442,8 +354,7 @@ frange::normalize_kind ()
}
else if (m_kind == VR_VARYING)
{
- // If a VARYING has any FP properties, it's no longer VARYING.
- if (!m_props.varying_p ())
+ if (!m_pos_nan || !m_neg_nan)
{
m_kind = VR_RANGE;
m_min = dconstninf;
@@ -451,9 +362,70 @@ frange::normalize_kind ()
return true;
}
}
+ else if (m_kind == VR_NAN && !m_pos_nan && !m_neg_nan)
+ set_undefined ();
return false;
}
+// Union or intersect the zero endpoints of two ranges. For example:
+// [-0, x] U [+0, x] => [-0, x]
+// [ x, -0] U [ x, +0] => [ x, +0]
+// [-0, x] ^ [+0, x] => [+0, x]
+// [ x, -0] ^ [ x, +0] => [ x, -0]
+//
+// UNION_P is true when performing a union, or false when intersecting.
+
+bool
+frange::combine_zeros (const frange &r, bool union_p)
+{
+ gcc_checking_assert (!undefined_p () && !known_isnan ());
+
+ bool changed = false;
+ if (real_iszero (&m_min) && real_iszero (&r.m_min)
+ && real_isneg (&m_min) != real_isneg (&r.m_min))
+ {
+ m_min.sign = union_p;
+ changed = true;
+ }
+ if (real_iszero (&m_max) && real_iszero (&r.m_max)
+ && real_isneg (&m_max) != real_isneg (&r.m_max))
+ {
+ m_max.sign = !union_p;
+ changed = true;
+ }
+ // If the signs are swapped, the resulting range is empty.
+ if (m_min.sign == 0 && m_max.sign == 1)
+ {
+ if (maybe_isnan ())
+ m_kind = VR_NAN;
+ else
+ m_kind = VR_UNDEFINED;
+ changed = true;
+ }
+ return changed;
+}
+
+// Union two ranges when one is known to be a NAN.
+
+bool
+frange::union_nans (const frange &r)
+{
+ gcc_checking_assert (known_isnan () || r.known_isnan ());
+
+ if (known_isnan ())
+ {
+ m_kind = r.m_kind;
+ m_min = r.m_min;
+ m_max = r.m_max;
+ }
+ m_pos_nan |= r.m_pos_nan;
+ m_neg_nan |= r.m_neg_nan;
+ normalize_kind ();
+ if (flag_checking)
+ verify_range ();
+ return true;
+}
+
bool
frange::union_ (const vrange &v)
{
@@ -467,29 +439,18 @@ frange::union_ (const vrange &v)
return true;
}
- // If one side has a NAN, the union is the other side, plus the union
- // of the properties and the possibility of a NAN.
- if (known_nan ())
+ // Combine NAN info.
+ if (known_isnan () || r.known_isnan ())
+ return union_nans (r);
+ bool changed = false;
+ if (m_pos_nan != r.m_pos_nan || m_neg_nan != r.m_neg_nan)
{
- frange_props save = m_props;
- *this = r;
- m_props = save;
- m_props.union_ (r.m_props);
- update_nan (fp_prop::VARYING);
- if (flag_checking)
- verify_range ();
- return true;
- }
- if (r.known_nan ())
- {
- m_props.union_ (r.m_props);
- update_nan (fp_prop::VARYING);
- if (flag_checking)
- verify_range ();
- return true;
+ m_pos_nan |= r.m_pos_nan;
+ m_neg_nan |= r.m_neg_nan;
+ changed = true;
}
- bool changed = m_props.union_ (r.m_props);
+ // Combine endpoints.
if (real_less (&r.m_min, &m_min))
{
m_min = r.m_min;
@@ -500,13 +461,34 @@ frange::union_ (const vrange &v)
m_max = r.m_max;
changed = true;
}
- changed |= normalize_kind ();
+ if (HONOR_SIGNED_ZEROS (m_type))
+ changed |= combine_zeros (r, true);
+
+ changed |= normalize_kind ();
if (flag_checking)
verify_range ();
return changed;
}
+// Intersect two ranges when one is known to be a NAN.
+
+bool
+frange::intersect_nans (const frange &r)
+{
+ gcc_checking_assert (known_isnan () || r.known_isnan ());
+
+ m_pos_nan &= r.m_pos_nan;
+ m_neg_nan &= r.m_neg_nan;
+ if (maybe_isnan ())
+ m_kind = VR_NAN;
+ else
+ m_kind = VR_UNDEFINED;
+ if (flag_checking)
+ verify_range ();
+ return true;
+}
+
bool
frange::intersect (const vrange &v)
{
@@ -525,25 +507,18 @@ frange::intersect (const vrange &v)
return true;
}
- // If two NANs are not exactly the same, drop to an unknown NAN,
- // otherwise there's nothing to do.
- if (known_nan () && r.known_nan ())
- {
- if (m_props == r.m_props)
- return false;
-
- set_nan (m_type);
- return true;
- }
- // ?? Perhaps the intersection of a NAN and anything is a NAN ??.
- if (known_nan () || r.known_nan ())
+ // 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)
{
- set_varying (m_type);
- return true;
+ m_pos_nan &= r.m_pos_nan;
+ m_neg_nan &= r.m_neg_nan;
+ changed = true;
}
- bool changed = m_props.intersect (r.m_props);
-
+ // Combine endpoints.
if (real_less (&m_min, &r.m_min))
{
m_min = r.m_min;
@@ -554,14 +529,22 @@ frange::intersect (const vrange &v)
m_max = r.m_max;
changed = true;
}
- // If the endpoints are swapped, the ranges are disjoint.
+ // If the endpoints are swapped, the resulting range is empty.
if (real_less (&m_max, &m_min))
{
- set_undefined ();
+ if (maybe_isnan ())
+ m_kind = VR_NAN;
+ else
+ m_kind = VR_UNDEFINED;
+ if (flag_checking)
+ verify_range ();
return true;
}
- changed |= normalize_kind ();
+ if (HONOR_SIGNED_ZEROS (m_type))
+ changed |= combine_zeros (r, false);
+
+ changed |= normalize_kind ();
if (flag_checking)
verify_range ();
return changed;
@@ -574,7 +557,8 @@ frange::operator= (const frange &src)
m_type = src.m_type;
m_min = src.m_min;
m_max = src.m_max;
- m_props = src.m_props;
+ m_pos_nan = src.m_pos_nan;
+ m_neg_nan = src.m_neg_nan;
if (flag_checking)
verify_range ();
@@ -592,12 +576,13 @@ frange::operator== (const frange &src) const
if (varying_p ())
return types_compatible_p (m_type, src.m_type);
- if (known_nan () || src.known_nan ())
+ if (known_isnan () || src.known_isnan ())
return false;
return (real_identical (&m_min, &src.m_min)
&& real_identical (&m_max, &src.m_max)
- && m_props == src.m_props
+ && m_pos_nan == src.m_pos_nan
+ && m_neg_nan == src.m_neg_nan
&& types_compatible_p (m_type, src.m_type));
}
return false;
@@ -617,21 +602,24 @@ frange::contains_p (tree cst) const
if (varying_p ())
return true;
+ if (real_isnan (rv))
+ {
+ // No NAN in range.
+ if (!m_pos_nan && !m_neg_nan)
+ return false;
+ // Both +NAN and -NAN are present.
+ if (m_pos_nan && m_neg_nan)
+ return true;
+ return m_neg_nan == rv->sign;
+ }
+ if (known_isnan ())
+ return false;
if (real_compare (GE_EXPR, rv, &m_min) && real_compare (LE_EXPR, rv, &m_max))
{
+ // Make sure the signs are equal for signed zeros.
if (HONOR_SIGNED_ZEROS (m_type) && real_iszero (rv))
- {
- // FIXME: This is still using get_signbit() instead of
- // known_signbit() because the latter bails on possible NANs
- // (for now).
- if (get_signbit ().yes_p ())
- return real_isneg (rv);
- else if (get_signbit ().no_p ())
- return !real_isneg (rv);
- else
- return true;
- }
+ return m_min.sign == m_max.sign && m_min.sign == rv->sign;
return true;
}
return false;
@@ -648,29 +636,9 @@ frange::singleton_p (tree *result) const
if (m_kind == VR_RANGE && real_identical (&m_min, &m_max))
{
// Return false for any singleton that may be a NAN.
- if (HONOR_NANS (m_type) && maybe_nan ())
+ if (HONOR_NANS (m_type) && maybe_isnan ())
return false;
- // Return the appropriate zero if known.
- if (HONOR_SIGNED_ZEROS (m_type) && zero_p ())
- {
- bool signbit;
- if (known_signbit (signbit))
- {
- if (signbit)
- {
- if (result)
- *result = build_real (m_type, real_value_negate (&dconst0));
- }
- else
- {
- if (result)
- *result = build_real (m_type, dconst0);
- }
- return true;
- }
- return false;
- }
if (result)
*result = build_real (m_type, m_min);
return true;
@@ -687,57 +655,40 @@ frange::supports_type_p (const_tree type) const
void
frange::verify_range ()
{
- if (undefined_p ())
+ switch (m_kind)
{
- gcc_checking_assert (m_props.undefined_p ());
+ case VR_UNDEFINED:
+ // m_type is ignored.
return;
- }
- gcc_checking_assert (!m_props.undefined_p ());
-
- if (varying_p ())
- {
- gcc_checking_assert (m_props.varying_p ());
+ case VR_VARYING:
+ gcc_checking_assert (m_type);
+ gcc_checking_assert (m_pos_nan && m_neg_nan);
+ gcc_checking_assert (real_isinf (&m_min, 1));
+ gcc_checking_assert (real_isinf (&m_max, 0));
return;
+ case VR_RANGE:
+ gcc_checking_assert (m_type);
+ break;
+ case VR_NAN:
+ gcc_checking_assert (m_type);
+ gcc_checking_assert (m_pos_nan || m_neg_nan);
+ return;
+ default:
+ gcc_unreachable ();
}
- // We don't support the inverse of an frange (yet).
- gcc_checking_assert (m_kind == VR_RANGE);
+ // NANs cannot appear in the endpoints of a range.
+ gcc_checking_assert (!real_isnan (&m_min) && !real_isnan (&m_max));
- 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 (known_nan ());
- }
- else
- // Make sure we don't have swapped ranges.
- gcc_checking_assert (!real_less (&m_max, &m_min));
+ // 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 (known_nan ())
- {
- gcc_checking_assert (real_isnan (&m_min));
- gcc_checking_assert (real_isnan (&m_max));
- }
- else
- {
- // Make sure the signbit and range agree.
- bool signbit;
- if (known_signbit (signbit))
- {
- if (signbit)
- gcc_checking_assert (real_compare (LE_EXPR, &m_max, &dconst0));
- else
- gcc_checking_assert (real_compare (GE_EXPR, &m_min, &dconst0));
- }
- }
+ // [ +0.0, -0.0 ] is nonsensical.
+ gcc_checking_assert (!(real_iszero (&m_min, 0) && real_iszero (&m_max, 1)));
// If all the properties are clear, we better not span the entire
// domain, because that would make us varying.
- if (m_props.varying_p ())
+ if (m_pos_nan && m_neg_nan)
gcc_checking_assert (!real_isinf (&m_min, 1) || !real_isinf (&m_max, 0));
}
@@ -755,16 +706,24 @@ frange::nonzero_p () const
return false;
}
-// Set range to [+0.0, +0.0].
+// Set range to [+0.0, +0.0] if honoring signed zeros, or [0.0, 0.0]
+// otherwise.
void
frange::set_zero (tree type)
{
- tree zero = build_zero_cst (type);
- set (zero, zero);
+ if (HONOR_SIGNED_ZEROS (type))
+ {
+ REAL_VALUE_TYPE dconstm0 = dconst0;
+ dconstm0.sign = 1;
+ set (type, dconstm0, dconst0);
+ clear_nan ();
+ }
+ else
+ set (type, dconst0, dconst0);
}
-// Return TRUE for any [0.0, 0.0] regardless of sign.
+// Return TRUE for any zero regardless of sign.
bool
frange::zero_p () const
@@ -777,9 +736,7 @@ frange::zero_p () const
void
frange::set_nonnegative (tree type)
{
- tree zero = build_zero_cst (type);
- tree inf = vrp_val_max (type);
- set (zero, inf);
+ set (type, dconst0, dconstinf);
}
// Here we copy between any two irange's. The ranges can be legacy or
@@ -3637,8 +3594,21 @@ range_tests_nan ()
ASSERT_EQ (r0, r1);
r0.clear_nan ();
ASSERT_NE (r0, r1);
+ r0.update_nan ();
+ ASSERT_EQ (r0, r1);
+
+ // [10, 20] NAN ^ [30, 40] NAN = NAN.
+ r0 = frange_float ("10", "20");
+ r1 = frange_float ("30", "40");
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.known_isnan ());
+
+ // [3,5] U [5,10] NAN = ... NAN
+ r0 = frange_float ("3", "5");
r0.clear_nan ();
- ASSERT_NE (r0, r1);
+ r1 = frange_float ("5", "10");
+ r0.union_ (r1);
+ ASSERT_TRUE (r0.maybe_isnan ());
}
// NAN ranges are not equal to each other.
@@ -3657,40 +3627,75 @@ range_tests_nan ()
real_from_string (&r, "6");
ASSERT_TRUE (real_identical (&q, &r0.lower_bound ()));
ASSERT_TRUE (real_identical (&r, &r0.upper_bound ()));
- ASSERT_TRUE (r0.maybe_nan ());
+ ASSERT_TRUE (r0.maybe_isnan ());
// NAN U NAN = NAN
r0.set_nan (float_type_node);
r1.set_nan (float_type_node);
r0.union_ (r1);
- ASSERT_TRUE (real_isnan (&r0.lower_bound ()));
- ASSERT_TRUE (real_isnan (&r1.upper_bound ()));
- ASSERT_TRUE (r0.known_nan ());
+ ASSERT_TRUE (r0.known_isnan ());
- // [INF, INF] ^ NAN = VARYING
+ // [INF, INF] NAN ^ NAN = NAN
r0.set_nan (float_type_node);
r1 = frange_float ("+Inf", "+Inf");
+ if (!HONOR_NANS (float_type_node))
+ r1.update_nan ();
r0.intersect (r1);
- ASSERT_TRUE (r0.varying_p ());
+ ASSERT_TRUE (r0.known_isnan ());
// NAN ^ NAN = NAN
r0.set_nan (float_type_node);
r1.set_nan (float_type_node);
r0.intersect (r1);
- ASSERT_TRUE (r0.known_nan ());
+ ASSERT_TRUE (r0.known_isnan ());
+
+ // +NAN ^ -NAN = UNDEFINED
+ r0.set_nan (float_type_node, false);
+ r1.set_nan (float_type_node, true);
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.undefined_p ());
// VARYING ^ NAN = NAN.
r0.set_nan (float_type_node);
r1.set_varying (float_type_node);
r0.intersect (r1);
- ASSERT_TRUE (r0.known_nan ());
+ ASSERT_TRUE (r0.known_isnan ());
+
+ // [3,4] ^ NAN = UNDEFINED.
+ r0 = frange_float ("3", "4");
+ r0.clear_nan ();
+ r1.set_nan (float_type_node);
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.undefined_p ());
+
+ // [-3, 5] ^ NAN = UNDEFINED
+ r0 = frange_float ("-3", "5");
+ r0.clear_nan ();
+ r1.set_nan (float_type_node);
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.undefined_p ());
+
+ // Setting the NAN bit to yes does not make us a known NAN.
+ r0.set_varying (float_type_node);
+ r0.update_nan ();
+ ASSERT_FALSE (r0.known_isnan ());
- // Setting the NAN bit to yes, forces to range to [NAN, NAN].
+ // NAN is in a VARYING.
r0.set_varying (float_type_node);
- r0.update_nan (fp_prop::YES);
- ASSERT_TRUE (r0.known_nan ());
- ASSERT_TRUE (real_isnan (&r0.lower_bound ()));
- ASSERT_TRUE (real_isnan (&r0.upper_bound ()));
+ real_nan (&r, "", 1, TYPE_MODE (float_type_node));
+ tree nan = build_real (float_type_node, r);
+ ASSERT_TRUE (r0.contains_p (nan));
+
+ // -NAN is in a VARYING.
+ r0.set_varying (float_type_node);
+ q = real_value_negate (&r);
+ tree neg_nan = build_real (float_type_node, q);
+ ASSERT_TRUE (r0.contains_p (neg_nan));
+
+ // Clearing the NAN on a [] NAN is the empty set.
+ r0.set_nan (float_type_node);
+ r0.clear_nan ();
+ ASSERT_TRUE (r0.undefined_p ());
}
static void
@@ -3702,49 +3707,84 @@ range_tests_signed_zeros ()
frange r0, r1;
bool signbit;
- // Since -0.0 == +0.0, a range of [-0.0, -0.0] should contain +0.0
- // and vice versa.
+ // [0,0] contains [0,0] but not [-0,-0] and vice versa.
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 (!r0.contains_p (neg_zero));
ASSERT_TRUE (r1.contains_p (neg_zero));
+ ASSERT_TRUE (!r1.contains_p (zero));
// Test contains_p() when we know the sign of the zero.
- r0 = frange(zero, zero);
- r0.set_signbit (fp_prop::NO);
+ r0 = frange (zero, zero);
ASSERT_TRUE (r0.contains_p (zero));
ASSERT_FALSE (r0.contains_p (neg_zero));
- r0.set_signbit (fp_prop::YES);
+ r0 = frange (neg_zero, neg_zero);
ASSERT_TRUE (r0.contains_p (neg_zero));
ASSERT_FALSE (r0.contains_p (zero));
- // The intersection of zeros that differ in sign is the empty set.
- r0 = frange (zero, zero);
- r0.set_signbit (fp_prop::YES);
+ // The intersection of zeros that differ in sign is a NAN (or
+ // undefined if not honoring NANs).
+ r0 = frange (neg_zero, neg_zero);
r1 = frange (zero, zero);
- r1.set_signbit (fp_prop::NO);
r0.intersect (r1);
- ASSERT_TRUE (r0.undefined_p ());
+ if (HONOR_NANS (float_type_node))
+ ASSERT_TRUE (r0.known_isnan ());
+ else
+ ASSERT_TRUE (r0.undefined_p ());
// The union of zeros that differ in sign is a zero with unknown sign.
r0 = frange (zero, zero);
- r0.set_signbit (fp_prop::NO);
- r1 = frange (zero, zero);
- r1.set_signbit (fp_prop::YES);
+ r1 = frange (neg_zero, neg_zero);
r0.union_ (r1);
- ASSERT_TRUE (r0.zero_p () && !r0.known_signbit (signbit));
+ ASSERT_TRUE (r0.zero_p () && !r0.signbit_p (signbit));
- // NAN U [5,6] should be [5,6] with no sign info.
+ // [-0, +0] has an unknown sign.
+ r0 = frange (neg_zero, zero);
+ ASSERT_TRUE (r0.zero_p () && !r0.signbit_p (signbit));
+
+ // [-0, +0] ^ [0, 0] is [0, 0]
+ r0 = frange (neg_zero, zero);
+ r1 = frange (zero, zero);
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.zero_p ());
+
+ // NAN U [5,6] should be [5,6] NAN.
r0.set_nan (float_type_node);
r1 = frange_float ("5", "6");
+ r1.clear_nan ();
r0.union_ (r1);
real_from_string (&q, "5");
real_from_string (&r, "6");
ASSERT_TRUE (real_identical (&q, &r0.lower_bound ()));
ASSERT_TRUE (real_identical (&r, &r0.upper_bound ()));
- ASSERT_TRUE (!r0.known_signbit (signbit));
+ ASSERT_TRUE (!r0.signbit_p (signbit));
+ ASSERT_TRUE (r0.maybe_isnan ());
+
+ r0 = frange_float ("+0", "5");
+ r0.clear_nan ();
+ ASSERT_TRUE (r0.signbit_p (signbit) && !signbit);
+
+ r0 = frange_float ("-0", "5");
+ r0.clear_nan ();
+ ASSERT_TRUE (!r0.signbit_p (signbit));
+
+ r0 = frange_float ("-0", "10");
+ r1 = frange_float ("0", "5");
+ r0.intersect (r1);
+ ASSERT_TRUE (real_iszero (&r0.lower_bound (), false));
+
+ r0 = frange_float ("-0", "5");
+ r1 = frange_float ("0", "5");
+ r0.union_ (r1);
+ ASSERT_TRUE (real_iszero (&r0.lower_bound (), true));
+
+ r0 = frange_float ("-5", "-0");
+ r0.update_nan ();
+ r1 = frange_float ("0", "0");
+ r1.update_nan ();
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.known_isnan ());
}
static void
@@ -3753,52 +3793,25 @@ range_tests_signbit ()
frange r0, r1;
bool signbit;
- // Setting the signbit drops the range to [-INF, 0].
- r0.set_varying (float_type_node);
- r0.set_signbit (fp_prop::YES);
- ASSERT_TRUE (real_isinf (&r0.lower_bound (), 1));
- ASSERT_TRUE (real_iszero (&r0.upper_bound ()));
-
- // Setting the signbit for [-5, 10] crops the range to [-5, 0] with
- // the signbit property set.
- r0 = frange_float ("-5", "10");
- r0.set_signbit (fp_prop::YES);
- r0.clear_nan ();
- ASSERT_TRUE (r0.known_signbit (signbit) && signbit);
- r1 = frange_float ("-5", "0");
- ASSERT_TRUE (real_identical (&r0.lower_bound (), &r1.lower_bound ()));
- ASSERT_TRUE (real_identical (&r0.upper_bound (), &r1.upper_bound ()));
-
// Negative numbers should have the SIGNBIT set.
r0 = frange_float ("-5", "-1");
r0.clear_nan ();
- ASSERT_TRUE (r0.known_signbit (signbit) && signbit);
+ ASSERT_TRUE (r0.signbit_p (signbit) && signbit);
// Positive numbers should have the SIGNBIT clear.
r0 = frange_float ("1", "10");
r0.clear_nan ();
- ASSERT_TRUE (r0.known_signbit (signbit) && !signbit);
+ ASSERT_TRUE (r0.signbit_p (signbit) && !signbit);
// Numbers containing zero should have an unknown SIGNBIT.
r0 = frange_float ("0", "10");
r0.clear_nan ();
- ASSERT_TRUE (!r0.known_signbit (signbit));
+ ASSERT_TRUE (r0.signbit_p (signbit) && !signbit);
// Numbers spanning both positive and negative should have an
// unknown SIGNBIT.
r0 = frange_float ("-10", "10");
r0.clear_nan ();
- ASSERT_TRUE (!r0.known_signbit (signbit));
+ ASSERT_TRUE (!r0.signbit_p (signbit));
r0.set_varying (float_type_node);
- ASSERT_TRUE (!r0.known_signbit (signbit));
-
- // Ignore signbit changes when the sign bit is obviously known from
- // the range.
- r0 = frange_float ("5", "10");
- r0.clear_nan ();
- r0.set_signbit (fp_prop::VARYING);
- ASSERT_TRUE (r0.known_signbit (signbit) && !signbit);
- r0 = frange_float ("-5", "-1");
- r0.set_signbit (fp_prop::NO);
- r0.clear_nan ();
- ASSERT_TRUE (r0.undefined_p ());
+ ASSERT_TRUE (!r0.signbit_p (signbit));
}
static void
@@ -3815,7 +3828,7 @@ range_tests_floats ()
// A range of [-INF,+INF] is actually VARYING if no other properties
// are set.
r0 = frange_float ("-Inf", "+Inf");
- if (r0.maybe_nan ())
+ if (r0.maybe_isnan ())
ASSERT_TRUE (r0.varying_p ());
// ...unless it has some special property...
r0.clear_nan ();
@@ -3896,9 +3909,19 @@ range_tests_floats ()
r0.intersect (r1);
ASSERT_EQ (r0, frange_float ("15", "20"));
+ // [10,20] NAN ^ [21,25] NAN = [NAN]
+ r0 = frange_float ("10", "20");
+ r0.update_nan ();
+ r1 = frange_float ("21", "25");
+ r1.update_nan ();
+ r0.intersect (r1);
+ ASSERT_TRUE (r0.known_isnan ());
+
// [10,20] ^ [21,25] = []
r0 = frange_float ("10", "20");
+ r0.clear_nan ();
r1 = frange_float ("21", "25");
+ r1.clear_nan ();
r0.intersect (r1);
ASSERT_TRUE (r0.undefined_p ());
}
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 4392de8..3a401f3 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -35,6 +35,8 @@ enum value_range_kind
VR_RANGE,
/* Range is ~[MIN, MAX]. */
VR_ANTI_RANGE,
+ /* Range is a NAN. */
+ VR_NAN,
/* Range is a nice guy. */
VR_LAST
};
@@ -263,69 +265,10 @@ public:
virtual void accept (const vrange_visitor &v) const override;
};
-// Floating point property to represent possible values of a NAN, INF, etc.
-
-class fp_prop
-{
-public:
- enum kind {
- UNDEFINED = 0x0, // Prop is impossible.
- YES = 0x1, // Prop is definitely set.
- NO = 0x2, // Prop is definitely not set.
- VARYING = (YES | NO) // Prop may hold.
- };
- fp_prop (kind f) : m_kind (f) { }
- bool varying_p () const { return m_kind == VARYING; }
- bool undefined_p () const { return m_kind == UNDEFINED; }
- bool yes_p () const { return m_kind == YES; }
- bool no_p () const { return m_kind == NO; }
-private:
- unsigned char m_kind : 2;
-};
-
-// Accessors for individual FP properties.
-
-#define FP_PROP_ACCESSOR(NAME) \
- void NAME##_set_varying () { u.bits.NAME = fp_prop::VARYING; } \
- void NAME##_set_yes () { u.bits.NAME = fp_prop::YES; } \
- void NAME##_set_no () { u.bits.NAME = fp_prop::NO; } \
- bool NAME##_varying_p () const { return u.bits.NAME == fp_prop::VARYING; } \
- bool NAME##_undefined_p () const { return u.bits.NAME == fp_prop::UNDEFINED; } \
- bool NAME##_yes_p () const { return u.bits.NAME == fp_prop::YES; } \
- bool NAME##_no_p () const { return u.bits.NAME == fp_prop::NO; } \
- fp_prop get_##NAME () const \
- { return fp_prop ((fp_prop::kind) u.bits.NAME); } \
- void set_##NAME (fp_prop::kind f) { u.bits.NAME = f; }
-
-// Aggregate of all the FP properties in an frange packed into one
-// structure to save space. Using explicit fp_prop's in the frange,
-// would take one byte per property because of padding. Instead, we
-// can save all properties into one byte.
-
-class frange_props
-{
-public:
- frange_props () { set_varying (); }
- void set_varying () { u.bytes = 0xff; }
- void set_undefined () { u.bytes = 0; }
- bool varying_p () { return u.bytes == 0xff; }
- bool undefined_p () { return u.bytes == 0; }
- bool union_ (const frange_props &other);
- bool intersect (const frange_props &other);
- bool operator== (const frange_props &other) const;
- FP_PROP_ACCESSOR(nan)
- FP_PROP_ACCESSOR(signbit)
-private:
- union {
- struct {
- unsigned char nan : 2;
- unsigned char signbit : 2;
- } bits;
- unsigned char bytes;
- } u;
-};
-
// A floating point range.
+//
+// The representation is a type with a couple of endpoints, unioned
+// with the set of { -NAN, +Nan }.
class frange : public vrange
{
@@ -349,6 +292,7 @@ public:
void set (tree type, const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &,
value_range_kind = VR_RANGE);
void set_nan (tree type);
+ void set_nan (tree type, bool sign);
virtual void set_varying (tree type) override;
virtual void set_undefined () override;
virtual bool union_ (const vrange &) override;
@@ -367,42 +311,41 @@ public:
bool operator!= (const frange &r) const { return !(*this == r); }
const REAL_VALUE_TYPE &lower_bound () const;
const REAL_VALUE_TYPE &upper_bound () const;
+ void update_nan ();
+ void clear_nan ();
// fpclassify like API
- bool known_finite () const;
- bool maybe_inf () const;
- bool known_inf () const;
- bool maybe_nan () const;
- bool known_nan () const;
- bool known_signbit (bool &signbit) const;
-
- // Accessors for FP properties.
- void update_nan (fp_prop::kind f);
- void clear_nan () { update_nan (fp_prop::NO); }
- void set_signbit (fp_prop::kind);
+ bool known_isfinite () const;
+ bool known_isnan () const;
+ bool known_isinf () const;
+ bool maybe_isnan () const;
+ bool maybe_isinf () const;
+ bool signbit_p (bool &signbit) const;
private:
- fp_prop get_nan () const { return m_props.get_nan (); }
- fp_prop get_signbit () const { return m_props.get_signbit (); }
void verify_range ();
bool normalize_kind ();
+ bool union_nans (const frange &);
+ bool intersect_nans (const frange &);
+ bool combine_zeros (const frange &, bool union_p);
- frange_props m_props;
tree m_type;
REAL_VALUE_TYPE m_min;
REAL_VALUE_TYPE m_max;
+ bool m_pos_nan;
+ bool m_neg_nan;
};
inline const REAL_VALUE_TYPE &
frange::lower_bound () const
{
- gcc_checking_assert (!undefined_p ());
+ gcc_checking_assert (!undefined_p () && !known_isnan ());
return m_min;
}
inline const REAL_VALUE_TYPE &
frange::upper_bound () const
{
- gcc_checking_assert (!undefined_p ());
+ gcc_checking_assert (!undefined_p () && !known_isnan ());
return m_max;
}
@@ -1082,30 +1025,6 @@ vrp_val_min (const_tree type)
return NULL_TREE;
}
-// Supporting methods for frange.
-
-inline bool
-frange_props::operator== (const frange_props &other) const
-{
- return u.bytes == other.u.bytes;
-}
-
-inline bool
-frange_props::union_ (const frange_props &other)
-{
- unsigned char saved = u.bytes;
- u.bytes |= other.u.bytes;
- return u.bytes != saved;
-}
-
-inline bool
-frange_props::intersect (const frange_props &other)
-{
- unsigned char saved = u.bytes;
- u.bytes &= other.u.bytes;
- return u.bytes != saved;
-}
-
inline
frange::frange ()
{
@@ -1154,15 +1073,42 @@ frange::set_varying (tree type)
m_type = type;
m_min = dconstninf;
m_max = dconstinf;
- m_props.set_varying ();
+ m_pos_nan = true;
+ m_neg_nan = true;
}
inline void
frange::set_undefined ()
{
m_kind = VR_UNDEFINED;
- m_type = NULL;
- m_props.set_undefined ();
+ if (flag_checking)
+ verify_range ();
+}
+
+// Set the NAN bit and adjust the range.
+
+inline void
+frange::update_nan ()
+{
+ gcc_checking_assert (!undefined_p ());
+ m_pos_nan = true;
+ m_neg_nan = true;
+ normalize_kind ();
+ if (flag_checking)
+ verify_range ();
+}
+
+// Clear the NAN bit and adjust the range.
+
+inline void
+frange::clear_nan ()
+{
+ gcc_checking_assert (!undefined_p ());
+ m_pos_nan = false;
+ m_neg_nan = false;
+ normalize_kind ();
+ if (flag_checking)
+ verify_range ();
}
// Set R to maximum representable value for TYPE.
@@ -1186,19 +1132,28 @@ real_min_representable (REAL_VALUE_TYPE *r, tree type)
*r = real_value_negate (r);
}
-// Build a NAN of type TYPE.
+// Build a signless NAN of type TYPE.
inline void
frange::set_nan (tree type)
{
- REAL_VALUE_TYPE r;
- gcc_assert (real_nan (&r, "", 1, TYPE_MODE (type)));
- m_kind = VR_RANGE;
+ m_kind = VR_NAN;
m_type = type;
- m_min = r;
- m_max = r;
- m_props.set_varying ();
- m_props.nan_set_yes ();
+ m_pos_nan = true;
+ m_neg_nan = true;
+ if (flag_checking)
+ verify_range ();
+}
+
+// Build a NAN of type TYPE with SIGN.
+
+inline void
+frange::set_nan (tree type, bool sign)
+{
+ m_kind = VR_NAN;
+ m_type = type;
+ m_neg_nan = sign;
+ m_pos_nan = !sign;
if (flag_checking)
verify_range ();
}
@@ -1206,21 +1161,19 @@ frange::set_nan (tree type)
// Return TRUE if range is known to be finite.
inline bool
-frange::known_finite () const
+frange::known_isfinite () const
{
if (undefined_p () || varying_p () || m_kind == VR_ANTI_RANGE)
return false;
- return (!real_isnan (&m_min)
- && !real_isinf (&m_min)
- && !real_isinf (&m_max));
+ return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max));
}
// Return TRUE if range may be infinite.
inline bool
-frange::maybe_inf () const
+frange::maybe_isinf () const
{
- if (undefined_p () || m_kind == VR_ANTI_RANGE)
+ if (undefined_p () || m_kind == VR_ANTI_RANGE || m_kind == VR_NAN)
return false;
if (varying_p ())
return true;
@@ -1230,7 +1183,7 @@ frange::maybe_inf () const
// Return TRUE if range is known to be the [-INF,-INF] or [+INF,+INF].
inline bool
-frange::known_inf () const
+frange::known_isinf () const
{
return (m_kind == VR_RANGE
&& real_identical (&m_min, &m_max)
@@ -1240,32 +1193,50 @@ frange::known_inf () const
// Return TRUE if range is possibly a NAN.
inline bool
-frange::maybe_nan () const
+frange::maybe_isnan () const
{
- return !get_nan ().no_p ();
+ return m_pos_nan || m_neg_nan;
}
// Return TRUE if range is a +NAN or -NAN.
inline bool
-frange::known_nan () const
+frange::known_isnan () const
{
- return get_nan ().yes_p ();
+ return m_kind == VR_NAN;
}
// If the signbit for the range is known, set it in SIGNBIT and return
// TRUE.
inline bool
-frange::known_signbit (bool &signbit) const
+frange::signbit_p (bool &signbit) const
{
- // FIXME: Signed NANs are not supported yet.
- if (maybe_nan ())
+ if (undefined_p ())
return false;
- if (get_signbit ().varying_p ())
+
+ // NAN with unknown sign.
+ if (m_pos_nan && m_neg_nan)
return false;
- signbit = get_signbit ().yes_p ();
- return true;
+ // No NAN.
+ if (!m_pos_nan && !m_neg_nan)
+ {
+ if (m_min.sign == m_max.sign)
+ {
+ signbit = m_min.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))
+ {
+ signbit = nan_sign;
+ return true;
+ }
+ return false;
}
#endif // GCC_VALUE_RANGE_H