aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2022-09-08 08:11:43 +0200
committerAldy Hernandez <aldyh@redhat.com>2022-09-08 12:56:16 +0200
commit672632317ac901f369b65b25f2147b3e7790ecca (patch)
treecaeeeee430d82a2e4122005babb4c0a96224810c /gcc
parenta7852bd30a19d29ff7986869453786d460d17877 (diff)
downloadgcc-672632317ac901f369b65b25f2147b3e7790ecca.zip
gcc-672632317ac901f369b65b25f2147b3e7790ecca.tar.gz
gcc-672632317ac901f369b65b25f2147b3e7790ecca.tar.bz2
Implement known/maybe fpclassify like API for frange.
gcc/ChangeLog: * gimple-range-fold.cc (fold_using_range::range_of_builtin_int_call): Use fpclassify like API. * range-op-float.cc (finite_operand_p): Same. (finite_operands_p): Same. (foperator_lt::fold_range): Same. (foperator_le::fold_range): Same. (foperator_gt::fold_range): Same. (foperator_ge::fold_range): Same. (foperator_unordered::fold_range): Same. (foperator_unordered::op1_range): Same. (foperator_ordered::fold_range): Same. * value-range.cc (frange::set_nan): Same. (frange::set_signbit): Same. (frange::union_): Same. (frange::intersect): Same. (frange::operator==): Same. (frange::singleton_p): Same. (frange::verify_range): Same. (range_tests_nan): Same. (range_tests_floats): Same. * value-range.h(frange::known_finite): New. (frange::maybe_inf): New. (frange::known_inf): New. (frange::maybe_nan): New. (frange::known_nan): New. (frange::known_signbit): New.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-range-fold.cc19
-rw-r--r--gcc/range-op-float.cc26
-rw-r--r--gcc/value-range.cc126
-rw-r--r--gcc/value-range.h78
4 files changed, 170 insertions, 79 deletions
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index c9c7a2c..85ed6f9 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -1029,15 +1029,16 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
frange tmp;
if (src.get_operand (tmp, arg))
{
- if (tmp.get_signbit ().varying_p ()
- // FIXME: We don't support signed NANs yet.
- || !tmp.get_nan ().no_p ())
- return false;
- if (tmp.get_signbit ().yes_p ())
- r.set_nonzero (type);
- else
- r.set_zero (type);
- return true;
+ bool signbit;
+ if (tmp.known_signbit (signbit))
+ {
+ if (signbit)
+ r.set_nonzero (type);
+ else
+ r.set_zero (type);
+ return true;
+ }
+ return false;
}
break;
}
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 5fbbaa1..0f928b6 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -167,7 +167,7 @@ frange_set_nan (frange &r, tree type)
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.
@@ -175,9 +175,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.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
@@ -546,7 +544,7 @@ foperator_lt::fold_range (irange &r, tree 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);
@@ -648,7 +646,7 @@ foperator_le::fold_range (irange &r, tree 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);
@@ -742,7 +740,7 @@ foperator_gt::fold_range (irange &r, tree 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);
@@ -844,7 +842,7 @@ foperator_ge::fold_range (irange &r, tree 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);
@@ -927,10 +925,10 @@ foperator_unordered::fold_range (irange &r, tree 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);
@@ -949,7 +947,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.get_nan ().no_p ())
+ if (!op2.maybe_nan ())
frange_set_nan (r, type);
break;
@@ -993,11 +991,9 @@ foperator_ordered::fold_range (irange &r, tree type,
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);
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index c3f668a..adcaaa2 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -274,7 +274,7 @@ frange::set_nan (fp_prop::kind k)
{
if (k == fp_prop::YES)
{
- if (get_nan ().no_p ())
+ if (!maybe_nan ())
{
set_undefined ();
return;
@@ -284,7 +284,7 @@ frange::set_nan (fp_prop::kind k)
return;
}
- if (k == fp_prop::NO && get_nan ().yes_p ())
+ if (k == fp_prop::NO && known_nan ())
{
set_undefined ();
return;
@@ -308,21 +308,18 @@ frange::set_signbit (fp_prop::kind k)
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)
@@ -330,17 +327,22 @@ frange::set_signbit (fp_prop::kind k)
// 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 ();
@@ -467,7 +469,7 @@ frange::union_ (const vrange &v)
// 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;
@@ -478,7 +480,7 @@ frange::union_ (const vrange &v)
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);
@@ -525,7 +527,7 @@ frange::intersect (const vrange &v)
// 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;
@@ -534,7 +536,7 @@ frange::intersect (const vrange &v)
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;
@@ -590,8 +592,7 @@ frange::operator== (const frange &src) const
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)
@@ -621,6 +622,9 @@ frange::contains_p (tree cst) const
{
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 ())
@@ -644,22 +648,25 @@ 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) && !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;
@@ -701,7 +708,7 @@ frange::verify_range ()
{
// 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.
@@ -710,7 +717,7 @@ frange::verify_range ()
// 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));
@@ -718,10 +725,14 @@ frange::verify_range ()
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
@@ -3637,7 +3648,7 @@ range_tests_nan ()
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);
@@ -3646,7 +3657,7 @@ 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.get_nan ().varying_p ());
+ ASSERT_TRUE (r0.maybe_nan ());
// NAN U NAN = NAN
r0 = frange_nan (float_type_node);
@@ -3654,7 +3665,7 @@ range_tests_nan ()
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);
@@ -3666,18 +3677,18 @@ range_tests_nan ()
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 ()));
}
@@ -3689,6 +3700,7 @@ range_tests_signed_zeros ()
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.
@@ -3722,7 +3734,7 @@ range_tests_signed_zeros ()
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);
@@ -3732,13 +3744,14 @@ range_tests_signed_zeros ()
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);
@@ -3750,35 +3763,42 @@ range_tests_signbit ()
// 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
@@ -3795,7 +3815,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.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);
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 645dc76..f9a01ee 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -330,6 +330,7 @@ private:
class frange : public vrange
{
friend class frange_storage_slot;
+ friend class vrange_printer;
public:
frange ();
frange (const frange &);
@@ -366,12 +367,20 @@ public:
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 ();
@@ -1187,4 +1196,69 @@ frange_nan (tree type)
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