public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Implement known/maybe fpclassify like API for frange.
@ 2022-09-08  6:27 Aldy Hernandez
  2022-09-08  7:27 ` Richard Biener
  0 siblings, 1 reply; 6+ messages in thread
From: Aldy Hernandez @ 2022-09-08  6:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, GCC patches, Andrew MacLeod, Aldy Hernandez

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.

?? I assume maybe_inf() does not 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);

How does this look?  I must say, the uses look much cleaner.
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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Implement known/maybe fpclassify like API for frange.
  2022-09-08  6:27 [PATCH] Implement known/maybe fpclassify like API for frange Aldy Hernandez
@ 2022-09-08  7:27 ` Richard Biener
  2022-09-08 10:56   ` Aldy Hernandez
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Biener @ 2022-09-08  7:27 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Jakub Jelinek, GCC patches, Andrew MacLeod



> 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
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Implement known/maybe fpclassify like API for frange.
  2022-09-08  7:27 ` Richard Biener
@ 2022-09-08 10:56   ` Aldy Hernandez
  2022-09-12  8:41     ` Jan-Benedict Glaw
  0 siblings, 1 reply; 6+ messages in thread
From: Aldy Hernandez @ 2022-09-08 10:56 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, GCC patches, Andrew MacLeod

[-- Attachment #1: Type: text/plain, Size: 16026 bytes --]

On Thu, Sep 8, 2022 at 9:27 AM Richard Biener
<richard.guenther@gmail.com> wrote:
>
>
>
> > 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

ok.  settled on:
+  bool known_signbit (bool &signbit) const;

It even cleaned up the __builtin_signbit folding kludge because now we
can just bail on NANs from known_signbit until they're properly
handled.

> 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.

We're definitely keeping track of signed zeros.  That was the whole
point of the sign bit.  I'll be removing it also, as it's a tristate.

tree_expr_nonnegative_p could definitely be made to make use of
it...especially because we have global ranges.  I'll look into it.

>
> > How does this look?  I must say, the uses look much cleaner.
>
> Yes, I like it.

Attached is the patch I'm pushing.

Tested on x86-64 Linux.

Thanks.
Aldy

>
> 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
> >
>

[-- Attachment #2: 0001-Implement-known-maybe-fpclassify-like-API-for-frange.patch --]
[-- Type: text/x-patch, Size: 19488 bytes --]

From 795baa0b044953e9f198f49e379374d633f43b47 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Thu, 8 Sep 2022 08:11:43 +0200
Subject: [PATCH] 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.
---
 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
-- 
2.37.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Implement known/maybe fpclassify like API for frange.
  2022-09-08 10:56   ` Aldy Hernandez
@ 2022-09-12  8:41     ` Jan-Benedict Glaw
  2022-09-12 13:12       ` Aldy Hernandez
  0 siblings, 1 reply; 6+ messages in thread
From: Jan-Benedict Glaw @ 2022-09-12  8:41 UTC (permalink / raw)
  To: Aldy Hernandez, Paul Koning; +Cc: Richard Biener, Jakub Jelinek, GCC patches

[-- Attachment #1: Type: text/plain, Size: 3195 bytes --]

Hi Aldy!

On Thu, 2022-09-08 12:56:24 +0200, Aldy Hernandez via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:

> From 795baa0b044953e9f198f49e379374d633f43b47 Mon Sep 17 00:00:00 2001
> From: Aldy Hernandez <aldyh@redhat.com>
> Date: Thu, 8 Sep 2022 08:11:43 +0200
> Subject: [PATCH] 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.
> ---
>  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(-)

This triggers a selftest failure for pdp11:

.../gcc/configure --prefix=... --enable-werror-always --enable-languages=all --disable-gcov --disable-shared --disable-threads --target=pdp11-aout --without-headers
[...]
make V=1 all-gcc
[...]
/var/lib/laminar/run/gcc-pdp11-aout/13/toolchain-build/./gcc/xgcc -B/var/lib/laminar/run/gcc-pdp11-aout/13/toolchain-build/./gcc/  -xc -nostdinc /dev/null -S -o /dev/null -fself-test=../../gcc/gcc/testsuite/selftests
../../gcc/gcc/value-range.cc:3801: range_tests_signbit: FAIL: ASSERT_TRUE ((r0.undefined_p ()))
In function 'test_fn':
cc1: internal compiler error: in fail, at selftest.cc:47
0x1757e97 selftest::fail(selftest::location const&, char const*)
      ../../gcc/gcc/selftest.cc:47
0x109ab62 range_tests_signbit
      ../../gcc/gcc/value-range.cc:3801
0x109ab62 range_tests_floats
      ../../gcc/gcc/value-range.cc:3810
0x10a9cf1 selftest::range_tests()
      ../../gcc/gcc/value-range.cc:3914
0x156e6d7 test_ranges
      ../../gcc/gcc/function-tests.cc:584
0x156e6d7 selftest::function_tests_cc_tests()
      ../../gcc/gcc/function-tests.cc:680
0x168d60b selftest::run_tests()
      ../../gcc/gcc/selftest-run-tests.cc:107
0xd968c9 toplev::run_self_tests()
      ../../gcc/gcc/toplev.cc:2184
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
make[1]: *** [../../gcc/gcc/c/Make-lang.in:128: s-selftest-c] Error 1

Thanks,
  Jan-Benedict

-- 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Implement known/maybe fpclassify like API for frange.
  2022-09-12  8:41     ` Jan-Benedict Glaw
@ 2022-09-12 13:12       ` Aldy Hernandez
  2022-09-12 18:38         ` Jan-Benedict Glaw
  0 siblings, 1 reply; 6+ messages in thread
From: Aldy Hernandez @ 2022-09-12 13:12 UTC (permalink / raw)
  To: Jan-Benedict Glaw; +Cc: Paul Koning, Richard Biener, Jakub Jelinek, GCC patches

On Mon, Sep 12, 2022 at 10:48 AM Jan-Benedict Glaw <jbglaw@lug-owl.de> wrote:
>
> Hi Aldy!
>
> On Thu, 2022-09-08 12:56:24 +0200, Aldy Hernandez via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>
> > From 795baa0b044953e9f198f49e379374d633f43b47 Mon Sep 17 00:00:00 2001
> > From: Aldy Hernandez <aldyh@redhat.com>
> > Date: Thu, 8 Sep 2022 08:11:43 +0200
> > Subject: [PATCH] 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.
> > ---
> >  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(-)
>
> This triggers a selftest failure for pdp11:
>
> .../gcc/configure --prefix=... --enable-werror-always --enable-languages=all --disable-gcov --disable-shared --disable-threads --target=pdp11-aout --without-headers

I have just pushed a patch to fix this.

I have also added -ffinite-math-only selftests to my list of testing
requirements for all future frange work.

Thanks for reporting this.
Aldy


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Implement known/maybe fpclassify like API for frange.
  2022-09-12 13:12       ` Aldy Hernandez
@ 2022-09-12 18:38         ` Jan-Benedict Glaw
  0 siblings, 0 replies; 6+ messages in thread
From: Jan-Benedict Glaw @ 2022-09-12 18:38 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: Paul Koning, Richard Biener, Jakub Jelinek, GCC patches

[-- Attachment #1: Type: text/plain, Size: 1382 bytes --]

Hi Aldy!

On Mon, 2022-09-12 15:12:46 +0200, Aldy Hernandez <aldyh@redhat.com> wrote:
> On Mon, Sep 12, 2022 at 10:48 AM Jan-Benedict Glaw <jbglaw@lug-owl.de> wrote:
> >
> > On Thu, 2022-09-08 12:56:24 +0200, Aldy Hernandez via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> >
> > > From 795baa0b044953e9f198f49e379374d633f43b47 Mon Sep 17 00:00:00 2001
> > > From: Aldy Hernandez <aldyh@redhat.com>
> > > Date: Thu, 8 Sep 2022 08:11:43 +0200
> > > Subject: [PATCH] Implement known/maybe fpclassify like API for frange.
> > >
> > > gcc/ChangeLog:
[...]
> > > ---
> > >  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(-)
> >
> > This triggers a selftest failure for pdp11:
> >
> > .../gcc/configure --prefix=... --enable-werror-always --enable-languages=all --disable-gcov --disable-shared --disable-threads --target=pdp11-aout --without-headers
> 
> I have just pushed a patch to fix this.
> 
> I have also added -ffinite-math-only selftests to my list of testing
> requirements for all future frange work.
> 
> Thanks for reporting this.

Thanks for the very quick fix, already confirmed here!

MfG, JBG

-- 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-09-12 18:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-08  6:27 [PATCH] Implement known/maybe fpclassify like API for frange Aldy Hernandez
2022-09-08  7:27 ` Richard Biener
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

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).