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.
This commit is contained in:
Aldy Hernandez 2022-08-30 15:46:43 +02:00
parent b73c49f6f8
commit 75f59441cd

View file

@ -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.
r0 = frange_nan (float_type_node);
ASSERT_TRUE (r0.get_nan ().yes_p ());
r1 = frange_float ("+Inf", "+Inf");
// [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);
// [INF, INF] U NAN = VARYING
ASSERT_TRUE (r0.varying_p ());
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);
r1 = frange_nan (float_type_node);
r0.union_ (r1);
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);