diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2022-08-30 15:46:43 +0200 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2022-08-30 17:43:37 +0200 |
commit | 75f59441cd63a1d07e86d70d59c518049f53904f (patch) | |
tree | 84f0d2e66b02beb667e5bdadaa0a22e5768aba82 | |
parent | b73c49f6f88dd7f7569f9a72c8ceb04598d4c15c (diff) | |
download | gcc-75f59441cd63a1d07e86d70d59c518049f53904f.zip gcc-75f59441cd63a1d07e86d70d59c518049f53904f.tar.gz gcc-75f59441cd63a1d07e86d70d59c518049f53904f.tar.bz2 |
Improve union of ranges containing NAN.
Previously [5,6] U NAN would just drop to VARYING. With this patch,
the resulting range becomes [5,6] with the NAN bit set to unknown.
[I still have yet to decide what to do with intersections. ISTM, the
intersection of a known NAN with anything else should be a NAN, but it
could also be undefined (the empty set). I'll have to run some tests
and see. Currently, we drop to VARYING cause well... it's always safe
to give up;-).]
gcc/ChangeLog:
* value-range.cc (early_nan_resolve): Change comment.
(frange::union_): Handle union when one side is a NAN.
(range_tests_nan): Add tests for NAN union.
-rw-r--r-- | gcc/value-range.cc | 44 |
1 files changed, 34 insertions, 10 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc index b6d6c62..473139c 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -403,7 +403,7 @@ early_nan_resolve (frange &r, const frange &other) // There's nothing to do for both NANs. if (r.get_nan ().yes_p () == other.get_nan ().yes_p ()) return false; - // But only one NAN complicates things. + // ?? Perhaps the intersection of a NAN and anything is a NAN ??. r.set_varying (r.type ()); return true; } @@ -420,10 +420,22 @@ frange::union_ (const vrange &v) *this = r; return true; } - // ?? We could do better here. [5,6] U NAN should be [5,6] with the - // NAN maybe bits set. For now, this is conservatively correct. - if (get_nan ().yes_p () || r.get_nan ().yes_p ()) - return early_nan_resolve (*this, r); + + // If one side has a NAN, the union is just the other side plus the + // NAN bit. + if (get_nan ().yes_p ()) + { + *this = r; + // NOP if NAN already set. + set_nan (fp_prop::VARYING); + return true; + } + if (r.get_nan ().yes_p ()) + { + // NOP if NAN already set. + set_nan (fp_prop::VARYING); + return true; + } bool changed = m_props.union_ (r.m_props); @@ -3520,6 +3532,7 @@ static void range_tests_nan () { frange r0, r1; + REAL_VALUE_TYPE q, r; // Equal ranges but with differing NAN bits are not equal. r1 = frange_float ("10", "12"); @@ -3537,13 +3550,24 @@ range_tests_nan () ASSERT_FALSE (r0 == r0); ASSERT_TRUE (r0 != r0); - // Make sure that combining NAN and INF doesn't give any crazy results. + // [5,6] U NAN is [5,6] with an unknown NAN bit. + r0 = frange_float ("5", "6"); + r0.set_nan (fp_prop::NO); + r1 = frange_nan (float_type_node); + r0.union_ (r1); + real_from_string (&q, "5"); + 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 ()); + + // NAN U NAN = NAN r0 = frange_nan (float_type_node); - ASSERT_TRUE (r0.get_nan ().yes_p ()); - r1 = frange_float ("+Inf", "+Inf"); + r1 = frange_nan (float_type_node); r0.union_ (r1); - // [INF, INF] U NAN = VARYING - ASSERT_TRUE (r0.varying_p ()); + ASSERT_TRUE (real_isnan (&r0.lower_bound ())); + ASSERT_TRUE (real_isnan (&r1.upper_bound ())); + ASSERT_TRUE (r0.get_nan ().yes_p ()); // [INF, INF] ^ NAN = VARYING r0 = frange_nan (float_type_node); |