From: Aldy Hernandez <[email protected]>
IEEE calls -0.0 and +0.0 equal, but in frange they are distinct:
[+0.0, x] excludes -0.0 and [-0.0, x] includes it. We have been
fixing things on the fly at each modification site, either manually or
by calling combine_zeros to fix up the signs. This was hacky at best.
This patch removes the signed zero special casing by providing
frange_cmp(), a comparison function that orders -0.0 strictly below +0.0.
The ranges themselves are unchanged. The only difference is that we
are now more exact about whether we actually modified a range
containing a zero. Previously combine_zeros flagged a change whenever
the two ranges disagreed on the sign of a zero endpoint, even when the
canonical result was the sign we already had. This made union_ and
intersect return a changed range pessimistically. We are now more
accurate, so in theory the ranger cache should be happier.
With these cleanups we can start implementing multi-ranges for frange
without any special casing for signed zeros.
Tested on x86-64 and ppc64le Linux. No changes to assembly for a
corpus of preprocessed files from LAPACK. Also, LAPACK and GCC tests
pass as usual.
Pushed.
gcc/ChangeLog:
* value-range.cc (frange_cmp): New.
(frange::combine_zeros): Remove.
(frange::union_): Use frange_cmp to merge endpoints.
(frange::intersect): Likewise.
(frange::contains_p): Use frange_cmp.
(frange::verify_range): Use frange_cmp.
* value-range.h (class frange): Remove combine_zeros.
---
gcc/value-range.cc | 101 +++++++++++++++++----------------------------
gcc/value-range.h | 1 -
2 files changed, 38 insertions(+), 64 deletions(-)
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 9e689ffbc0e..4e1be3b0ed6 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -986,6 +986,33 @@ frange::fits_p (const vrange &) const
return true;
}
+// Compare two range endpoints.
+//
+// In IEEE -0.0 and +0.0 equal for comparison purposes, but as endpoints they
+// are distinct. Order -0.0 strictly below +0.0 and use this rather than
+// real_less/real_compare, and the signed zeros stop needing a special case.
+
+static int
+frange_cmp (const REAL_VALUE_TYPE &a, const REAL_VALUE_TYPE &b)
+{
+ gcc_checking_assert (!real_isnan (&a) && !real_isnan (&b));
+
+ if (real_less (&a, &b))
+ return -1;
+ if (real_less (&b, &a))
+ return 1;
+ if (real_iszero (&a) && real_iszero (&b))
+ {
+ bool nega = real_isneg (&a);
+ bool negb = real_isneg (&b);
+ if (nega && !negb)
+ return -1;
+ if (!nega && negb)
+ return 1;
+ }
+ return 0;
+}
+
// Flush denormal endpoints to the appropriate 0.0.
void
@@ -1161,44 +1188,6 @@ frange::normalize_kind ()
return false;
}
-// Union or intersect the zero endpoints of two ranges. For example:
-// [-0, x] U [+0, x] => [-0, x]
-// [ x, -0] U [ x, +0] => [ x, +0]
-// [-0, x] ^ [+0, x] => [+0, x]
-// [ x, -0] ^ [ x, +0] => [ x, -0]
-//
-// UNION_P is true when performing a union, or false when intersecting.
-
-bool
-frange::combine_zeros (const frange &r, bool union_p)
-{
- gcc_checking_assert (!undefined_p () && !known_isnan ());
-
- bool changed = false;
- if (real_iszero (&m_min) && real_iszero (&r.m_min)
- && real_isneg (&m_min) != real_isneg (&r.m_min))
- {
- m_min.sign = union_p;
- changed = true;
- }
- if (real_iszero (&m_max) && real_iszero (&r.m_max)
- && real_isneg (&m_max) != real_isneg (&r.m_max))
- {
- m_max.sign = !union_p;
- changed = true;
- }
- // If the signs are swapped, the resulting range is empty.
- if (m_min.sign == 0 && m_max.sign == 1)
- {
- if (maybe_isnan ())
- m_kind = VR_NAN;
- else
- set_undefined ();
- changed = true;
- }
- return changed;
-}
-
// Union two ranges when one is known to be a NAN.
bool
@@ -1253,20 +1242,17 @@ frange::union_ (const vrange &v)
}
// Combine endpoints.
- if (real_less (&r.m_min, &m_min))
+ if (frange_cmp (r.m_min, m_min) < 0)
{
m_min = r.m_min;
changed = true;
}
- if (real_less (&m_max, &r.m_max))
+ if (frange_cmp (m_max, r.m_max) < 0)
{
m_max = r.m_max;
changed = true;
}
- if (HONOR_SIGNED_ZEROS (m_type))
- changed |= combine_zeros (r, true);
-
changed |= normalize_kind ();
return changed;
}
@@ -1319,18 +1305,20 @@ frange::intersect (const vrange &v)
}
// Combine endpoints.
- if (real_less (&m_min, &r.m_min))
+ if (frange_cmp (m_min, r.m_min) < 0)
{
m_min = r.m_min;
changed = true;
}
- if (real_less (&r.m_max, &m_max))
+ if (frange_cmp (r.m_max, m_max) < 0)
{
m_max = r.m_max;
changed = true;
}
- // If the endpoints are swapped, the resulting range is empty.
- if (real_less (&m_max, &m_min))
+
+ // If the endpoints are swapped, the resulting range is empty. This also
+ // catches [+0.0, -0.0], which is also empty.
+ if (frange_cmp (m_max, m_min) < 0)
{
if (maybe_isnan ())
m_kind = VR_NAN;
@@ -1341,9 +1329,6 @@ frange::intersect (const vrange &v)
return true;
}
- if (HONOR_SIGNED_ZEROS (m_type))
- changed |= combine_zeros (r, false);
-
changed |= normalize_kind ();
return changed;
}
@@ -1419,14 +1404,7 @@ frange::contains_p (const REAL_VALUE_TYPE &r) const
if (known_isnan ())
return false;
- if (real_compare (GE_EXPR, &r, &m_min) && real_compare (LE_EXPR, &r, &m_max))
- {
- // Make sure the signs are equal for signed zeros.
- if (HONOR_SIGNED_ZEROS (m_type) && real_iszero (&r))
- return r.sign == m_min.sign || r.sign == m_max.sign;
- return true;
- }
- return false;
+ return frange_cmp (r, m_min) >= 0 && frange_cmp (r, m_max) <= 0;
}
// If range is a singleton, place it in RESULT and return TRUE. If
@@ -1522,11 +1500,8 @@ frange::verify_range () const
// NANs cannot appear in the endpoints of a range.
gcc_checking_assert (!real_isnan (&m_min) && !real_isnan (&m_max));
- // Make sure we don't have swapped ranges.
- gcc_checking_assert (!real_less (&m_max, &m_min));
-
- // [ +0.0, -0.0 ] is nonsensical.
- gcc_checking_assert (!(real_iszero (&m_min, 0) && real_iszero (&m_max, 1)));
+ // Make sure we don't have swapped ranges. This also catches [ +0.0, -0.0].
+ gcc_checking_assert (frange_cmp (m_min, m_max) <= 0);
// A zero endpoint must carry its canonical sign. Every producer runs
// canonicalize_zeros, so a zero bound can only descend from a canonical one.
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 5d547bd7727..3226e53cb71 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -666,7 +666,6 @@ private:
bool normalize_kind ();
bool union_nans (const frange &);
bool intersect_nans (const frange &);
- bool combine_zeros (const frange &, bool union_p);
void canonicalize_zeros (REAL_VALUE_TYPE &, REAL_VALUE_TYPE &);
tree m_type;
--
2.47.3