From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2136) id 095ED3858D1E; Thu, 8 Sep 2022 10:56:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 095ED3858D1E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1662634583; bh=QDihccUbP99dUHkizg24WxRFpGQtFUgHoQ8bu06/rmc=; h=From:To:Subject:Date:From; b=b2vPblcBbiBIHRNtfDVTeZZqoM+tHuUe5HIO3RShiTeHXqw8mGPyUa1jSGd5zQCTy 8ejbw6EYhdAEK25M4xFhHDHpvceyP4zOqtHavKkK/y9QKbJXoYEEOhDQ5vhrpmqfQj 4i42IZ1yJrqWu9SpZZbbBhYSVL++uPQ9v1iPKRec= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Aldy Hernandez To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-2535] Implement known/maybe fpclassify like API for frange. X-Act-Checkin: gcc X-Git-Author: Aldy Hernandez X-Git-Refname: refs/heads/master X-Git-Oldrev: a7852bd30a19d29ff7986869453786d460d17877 X-Git-Newrev: 672632317ac901f369b65b25f2147b3e7790ecca Message-Id: <20220908105623.095ED3858D1E@sourceware.org> Date: Thu, 8 Sep 2022 10:56:23 +0000 (GMT) List-Id: https://gcc.gnu.org/g:672632317ac901f369b65b25f2147b3e7790ecca commit r13-2535-g672632317ac901f369b65b25f2147b3e7790ecca Author: Aldy Hernandez Date: Thu Sep 8 08:11:43 2022 +0200 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. Diff: --- gcc/gimple-range-fold.cc | 19 +++---- gcc/range-op-float.cc | 26 +++++----- gcc/value-range.cc | 126 +++++++++++++++++++++++++++-------------------- gcc/value-range.h | 78 ++++++++++++++++++++++++++++- 4 files changed, 170 insertions(+), 79 deletions(-) diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index c9c7a2ccc70..85ed6f9d47e 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 5fbbaa1fb36..0f928b6c098 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 c3f668a811a..adcaaa2a69a 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 645dc76c33a..f9a01ee7a05 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