static inline bool
finite_operand_p (const frange &op1)
{
- return flag_finite_math_only || op1.get_nan ().no_p ();
+ return flag_finite_math_only || !op1.maybe_nan ();
}
// Return TRUE if OP1 and OP2 are known to be free of NANs.
static inline bool
finite_operands_p (const frange &op1, const frange &op2)
{
- return (flag_finite_math_only
- || (op1.get_nan ().no_p ()
- && op2.get_nan ().no_p ()));
+ return flag_finite_math_only || (!op1.maybe_nan () && !op2.maybe_nan ());
}
// Floating version of relop_early_resolve that takes into account NAN
else
r = range_true_and_false (type);
}
- else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
+ else if (op1.known_nan () || op2.known_nan ())
r = range_false (type);
else
r = range_true_and_false (type);
else
r = range_true_and_false (type);
}
- else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
+ else if (op1.known_nan () || op2.known_nan ())
r = range_false (type);
else
r = range_true_and_false (type);
else
r = range_true_and_false (type);
}
- else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
+ else if (op1.known_nan () || op2.known_nan ())
r = range_false (type);
else
r = range_true_and_false (type);
else
r = range_true_and_false (type);
}
- else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
+ else if (op1.known_nan () || op2.known_nan ())
r = range_false (type);
else
r = range_true_and_false (type);
relation_kind) const
{
// UNORDERED is TRUE if either operand is a NAN.
- if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
+ if (op1.known_nan () || op2.known_nan ())
r = range_true (type);
// UNORDERED is FALSE if neither operand is a NAN.
- else if (op1.get_nan ().no_p () && op2.get_nan ().no_p ())
+ else if (!op1.maybe_nan () && !op2.maybe_nan ())
r = range_false (type);
else
r = range_true_and_false (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.get_nan ().no_p ())
+ if (!op2.maybe_nan ())
frange_set_nan (r, type);
break;
const frange &op1, const frange &op2,
relation_kind) const
{
- // ORDERED is TRUE if neither operand is a NAN.
- if (op1.get_nan ().no_p () && op2.get_nan ().no_p ())
+ if (!op1.maybe_nan () && !op2.maybe_nan ())
r = range_true (type);
- // ORDERED is FALSE if either operand is a NAN.
- else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ())
+ else if (op1.known_nan () || op2.known_nan ())
r = range_false (type);
else
r = range_true_and_false (type);
{
if (k == fp_prop::YES)
{
- if (get_nan ().no_p ())
+ if (!maybe_nan ())
{
set_undefined ();
return;
return;
}
- if (k == fp_prop::NO && get_nan ().yes_p ())
+ if (k == fp_prop::NO && known_nan ())
{
set_undefined ();
return;
gcc_checking_assert (m_type);
// No additional adjustments are needed for a NAN.
- if (get_nan ().yes_p ())
+ if (known_nan ())
{
m_props.set_signbit (k);
return;
}
// Ignore sign changes when they're set correctly.
- if (real_less (&m_max, &dconst0))
- {
- gcc_checking_assert (get_signbit ().yes_p ());
- return;
- }
- if (real_less (&dconst0, &m_min))
+ if (!maybe_nan ())
{
- gcc_checking_assert (get_signbit ().no_p ());
- return;
+ if (real_less (&m_max, &dconst0))
+ return;
+ if (real_less (&dconst0, &m_min))
+ 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);
- m_props.set_signbit (fp_prop::YES);
+ 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);
- m_props.set_signbit (fp_prop::NO);
+ if (!undefined_p ())
+ m_props.set_signbit (fp_prop::NO);
}
else
- m_props.set_signbit (fp_prop::VARYING);
+ {
+ m_props.set_signbit (fp_prop::VARYING);
+ normalize_kind ();
+ }
if (flag_checking)
verify_range ();
// 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 (get_nan ().yes_p ())
+ if (known_nan ())
{
frange_props save = m_props;
*this = r;
verify_range ();
return true;
}
- if (r.get_nan ().yes_p ())
+ if (r.known_nan ())
{
m_props.union_ (r.m_props);
set_nan (fp_prop::VARYING);
// If two NANs are not exactly the same, drop to an unknown NAN,
// otherwise there's nothing to do.
- if (get_nan ().yes_p () && r.get_nan ().yes_p ())
+ if (known_nan () && r.known_nan ())
{
if (m_props == r.m_props)
return false;
return true;
}
// ?? Perhaps the intersection of a NAN and anything is a NAN ??.
- if (get_nan ().yes_p () || r.get_nan ().yes_p ())
+ if (known_nan () || r.known_nan ())
{
set_varying (m_type);
return true;
if (varying_p ())
return types_compatible_p (m_type, src.m_type);
- if (m_props.get_nan ().yes_p ()
- || src.m_props.get_nan ().yes_p ())
+ if (known_nan () || src.known_nan ())
return false;
return (real_identical (&m_min, &src.m_min)
{
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 ())
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) && !get_nan ().no_p ())
+ if (HONOR_NANS (m_type) && maybe_nan ())
return false;
// Return the appropriate zero if known.
if (HONOR_SIGNED_ZEROS (m_type) && zero_p ())
{
- if (get_signbit ().no_p ())
+ bool signbit;
+ if (known_signbit (signbit))
{
- if (result)
- *result = build_real (m_type, dconst0);
- return true;
- }
- if (get_signbit ().yes_p ())
- {
- if (result)
- *result = build_real (m_type, real_value_negate (&dconst0));
+ 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 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 ());
+ gcc_checking_assert (known_nan ());
}
else
// Make sure we don't have swapped ranges.
// 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 ())
+ 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.
- if (m_props.get_signbit ().yes_p ())
- gcc_checking_assert (real_compare (LE_EXPR, &m_max, &dconst0));
- else if (m_props.get_signbit ().no_p ())
- gcc_checking_assert (real_compare (GE_EXPR, &m_min, &dconst0));
+ 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));
+ }
}
// If all the properties are clear, we better not span the entire
ASSERT_FALSE (r0 == r0);
ASSERT_TRUE (r0 != r0);
- // [5,6] U NAN is [5,6] with an unknown NAN bit.
+ // [5,6] U NAN.
r0 = frange_float ("5", "6");
r0.set_nan (fp_prop::NO);
r1 = frange_nan (float_type_node);
real_from_string (&r, "6");
ASSERT_TRUE (real_identical (&q, &r0.lower_bound ()));
ASSERT_TRUE (real_identical (&r, &r0.upper_bound ()));
- ASSERT_TRUE (r0.get_nan ().varying_p ());
+ ASSERT_TRUE (r0.maybe_nan ());
// NAN U NAN = NAN
r0 = frange_nan (float_type_node);
r0.union_ (r1);
ASSERT_TRUE (real_isnan (&r0.lower_bound ()));
ASSERT_TRUE (real_isnan (&r1.upper_bound ()));
- ASSERT_TRUE (r0.get_nan ().yes_p ());
+ ASSERT_TRUE (r0.known_nan ());
// [INF, INF] ^ NAN = VARYING
r0 = frange_nan (float_type_node);
r0 = frange_nan (float_type_node);
r1 = frange_nan (float_type_node);
r0.intersect (r1);
- ASSERT_TRUE (r0.get_nan ().yes_p ());
+ ASSERT_TRUE (r0.known_nan ());
// VARYING ^ NAN = NAN.
r0 = frange_nan (float_type_node);
r1.set_varying (float_type_node);
r0.intersect (r1);
- ASSERT_TRUE (r0.get_nan ().yes_p ());
+ ASSERT_TRUE (r0.known_nan ());
// Setting the NAN bit to yes, forces to range to [NAN, NAN].
r0.set_varying (float_type_node);
r0.set_nan (fp_prop::YES);
- ASSERT_TRUE (r0.get_nan ().yes_p ());
+ ASSERT_TRUE (r0.known_nan ());
ASSERT_TRUE (real_isnan (&r0.lower_bound ()));
ASSERT_TRUE (real_isnan (&r0.upper_bound ()));
}
tree neg_zero = fold_build1 (NEGATE_EXPR, float_type_node, zero);
REAL_VALUE_TYPE q, r;
frange r0, r1;
+ bool signbit;
// Since -0.0 == +0.0, a range of [-0.0, -0.0] should contain +0.0
// and vice versa.
r1 = frange (zero, zero);
r1.set_signbit (fp_prop::YES);
r0.union_ (r1);
- ASSERT_TRUE (r0.zero_p () && r0.get_signbit ().varying_p ());
+ ASSERT_TRUE (r0.zero_p () && !r0.known_signbit (signbit));
// NAN U [5,6] should be [5,6] with no sign info.
r0 = frange_nan (float_type_node);
real_from_string (&r, "6");
ASSERT_TRUE (real_identical (&q, &r0.lower_bound ()));
ASSERT_TRUE (real_identical (&r, &r0.upper_bound ()));
- ASSERT_TRUE (r0.get_signbit ().varying_p ());
+ ASSERT_TRUE (!r0.known_signbit (signbit));
}
static void
range_tests_signbit ()
{
frange r0, r1;
+ bool signbit;
// Setting the signbit drops the range to [-INF, 0].
r0.set_varying (float_type_node);
// the signbit property set.
r0 = frange_float ("-5", "10");
r0.set_signbit (fp_prop::YES);
- ASSERT_TRUE (r0.get_signbit ().yes_p ());
+ r0.set_nan (fp_prop::NO);
+ 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");
- ASSERT_TRUE (r0.get_signbit ().yes_p ());
+ r0.set_nan (fp_prop::NO);
+ ASSERT_TRUE (r0.known_signbit (signbit) && signbit);
// Positive numbers should have the SIGNBIT clear.
r0 = frange_float ("1", "10");
- ASSERT_TRUE (r0.get_signbit ().no_p ());
+ r0.set_nan (fp_prop::NO);
+ ASSERT_TRUE (r0.known_signbit (signbit) && !signbit);
// Numbers containing zero should have an unknown SIGNBIT.
r0 = frange_float ("0", "10");
- ASSERT_TRUE (r0.get_signbit ().varying_p ());
+ r0.set_nan (fp_prop::NO);
+ ASSERT_TRUE (!r0.known_signbit (signbit));
// Numbers spanning both positive and negative should have an
// unknown SIGNBIT.
r0 = frange_float ("-10", "10");
- ASSERT_TRUE (r0.get_signbit ().varying_p ());
+ r0.set_nan (fp_prop::NO);
+ ASSERT_TRUE (!r0.known_signbit (signbit));
r0.set_varying (float_type_node);
- ASSERT_TRUE (r0.get_signbit ().varying_p ());
+ 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.set_nan (fp_prop::NO);
r0.set_signbit (fp_prop::VARYING);
- ASSERT_TRUE (r0.get_signbit ().no_p ());
+ ASSERT_TRUE (r0.known_signbit (signbit) && !signbit);
r0 = frange_float ("-5", "-1");
r0.set_signbit (fp_prop::NO);
- ASSERT_TRUE (r0.get_signbit ().yes_p ());
+ r0.set_nan (fp_prop::NO);
+ ASSERT_TRUE (r0.undefined_p ());
}
static void
// A range of [-INF,+INF] is actually VARYING if no other properties
// are set.
r0 = frange_float ("-Inf", "+Inf");
- if (r0.get_nan ().varying_p ())
+ if (r0.maybe_nan ())
ASSERT_TRUE (r0.varying_p ());
// ...unless it has some special property...
r0.set_nan (fp_prop::NO);
class frange : public vrange
{
friend class frange_storage_slot;
+ friend class vrange_printer;
public:
frange ();
frange (const frange &);
const REAL_VALUE_TYPE &lower_bound () const;
const REAL_VALUE_TYPE &upper_bound () const;
+ // 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.
- fp_prop get_nan () const { return m_props.get_nan (); }
void set_nan (fp_prop::kind f);
- fp_prop get_signbit () const { return m_props.get_signbit (); }
void set_signbit (fp_prop::kind);
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 ();
return frange (type, r, r);
}
+// Return TRUE if range is known to be finite.
+
+inline bool
+frange::known_finite () 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 TRUE if range may be infinite.
+
+inline bool
+frange::maybe_inf () const
+{
+ if (undefined_p () || m_kind == VR_ANTI_RANGE)
+ return false;
+ if (varying_p ())
+ return true;
+ return real_isinf (&m_min) || real_isinf (&m_max);
+}
+
+// Return TRUE if range is known to be the [-INF,-INF] or [+INF,+INF].
+
+inline bool
+frange::known_inf () const
+{
+ return (m_kind == VR_RANGE
+ && real_identical (&m_min, &m_max)
+ && real_isinf (&m_min));
+}
+
+// Return TRUE if range is possibly a NAN.
+
+inline bool
+frange::maybe_nan () const
+{
+ return !get_nan ().no_p ();
+}
+
+// Return TRUE if range is a +NAN or -NAN.
+
+inline bool
+frange::known_nan () const
+{
+ return get_nan ().yes_p ();
+}
+
+// If the signbit for the range is known, set it in SIGNBIT and return
+// TRUE.
+
+inline bool
+frange::known_signbit (bool &signbit) const
+{
+ // FIXME: Signed NANs are not supported yet.
+ if (maybe_nan ())
+ return false;
+ if (get_signbit ().varying_p ())
+ return false;
+ signbit = get_signbit ().yes_p ();
+ return true;
+}
+
#endif // GCC_VALUE_RANGE_H