From: Richard Biener <richard.guenther@gmail.com>
To: Aldy Hernandez <aldyh@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>,
GCC patches <gcc-patches@gcc.gnu.org>,
Andrew MacLeod <amacleod@redhat.com>
Subject: Re: [PATCH] Implement known/maybe fpclassify like API for frange.
Date: Thu, 8 Sep 2022 09:27:33 +0200 [thread overview]
Message-ID: <7BAA2838-822A-4DF0-B712-00C265DFECEC@gmail.com> (raw)
In-Reply-To: <20220908062759.3610257-1-aldyh@redhat.com>
> Am 08.09.2022 um 08:28 schrieb Aldy Hernandez <aldyh@redhat.com>:
>
> This is what I have in mind for the fpclassify-like methods on the
> current implementation. I'll get to the removal of the tristates after
> Cauldron.
>
> As you mentioned, isnormal is kinda tricky, and likely to be confusing
> for the user. We can revisit it if it's important.
Yeah.
> ?? I assume maybe_inf() does not return true for NAN ??
Only maybe_nan and known_nan return true for NaN.
>
> Also, what are your thoughts on signbit? Perhaps a method returning
> true if we're sure, and the actual signbit result as a reference?
>
> bool known_signbit (const frange &r, int &signbit);
That works for me. You could look at
Tree_expr_nonnegative_p to see if that’s good enough to be used there. Not sure if -0. is negative or if only x for which x < 0. counts as such.. But yes, access to the sign bit is useful.
> How does this look? I must say, the uses look much cleaner.
Yes, I like it.
Richard
> Aldy
>
> 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.
> ---
> gcc/gimple-range-fold.cc | 2 +-
> gcc/range-op-float.cc | 26 ++++++++-----------
> gcc/value-range.cc | 37 ++++++++++++++-------------
> gcc/value-range.h | 54 +++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 83 insertions(+), 36 deletions(-)
>
> diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
> index c9c7a2ccc70..47a1f49eb36 100644
> --- a/gcc/gimple-range-fold.cc
> +++ b/gcc/gimple-range-fold.cc
> @@ -1031,7 +1031,7 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
> {
> if (tmp.get_signbit ().varying_p ()
> // FIXME: We don't support signed NANs yet.
> - || !tmp.get_nan ().no_p ())
> + || tmp.maybe_nan ())
> return false;
> if (tmp.get_signbit ().yes_p ())
> r.set_nonzero (type);
> 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..364919ca5c6 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,7 +308,7 @@ 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;
> @@ -467,7 +467,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 +478,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 +525,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 +534,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 +590,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)
> @@ -644,7 +643,7 @@ 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.
> @@ -701,7 +700,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 +709,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));
> @@ -3637,7 +3636,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 +3645,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 +3653,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 +3665,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 ()));
> }
> @@ -3795,7 +3794,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..e426225eabf 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,19 @@ 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;
> +
> // 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 (); }
> void verify_range ();
> bool normalize_kind ();
>
> @@ -1187,4 +1195,48 @@ 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);
> +}
> +
> +inline bool
> +frange::known_inf () const
> +{
> + return (m_kind == VR_RANGE
> + && real_identical (&m_min, &m_max)
> + && real_isinf (&m_min));
> +}
> +
> +inline bool
> +frange::maybe_nan () const
> +{
> + return !get_nan ().no_p ();
> +}
> +
> +inline bool
> +frange::known_nan () const
> +{
> + return get_nan ().yes_p ();
> +}
> +
> #endif // GCC_VALUE_RANGE_H
> --
> 2.37.1
>
next prev parent reply other threads:[~2022-09-08 7:27 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-08 6:27 Aldy Hernandez
2022-09-08 7:27 ` Richard Biener [this message]
2022-09-08 10:56 ` Aldy Hernandez
2022-09-12 8:41 ` Jan-Benedict Glaw
2022-09-12 13:12 ` Aldy Hernandez
2022-09-12 18:38 ` Jan-Benedict Glaw
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7BAA2838-822A-4DF0-B712-00C265DFECEC@gmail.com \
--to=richard.guenther@gmail.com \
--cc=aldyh@redhat.com \
--cc=amacleod@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).