diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2022-08-30 08:23:33 +0200 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2022-08-30 11:26:24 +0200 |
commit | 8bb1df032cc080b751e00c0d7d86c31a630105f9 (patch) | |
tree | 109c86b64c96335dbdc87a78fa15028ba97eccd6 /gcc/value-range-storage.cc | |
parent | df8fe4adb0721ab0e4486bc58482b501fe06287d (diff) | |
download | gcc-8bb1df032cc080b751e00c0d7d86c31a630105f9.zip gcc-8bb1df032cc080b751e00c0d7d86c31a630105f9.tar.gz gcc-8bb1df032cc080b751e00c0d7d86c31a630105f9.tar.bz2 |
Add support for floating point endpoints to frange.
The current implementation of frange is just a type with some bits to
represent NAN and INF. We can do better and represent endpoints to
ultimately solve longstanding PRs such as PR24021. This patch adds
these endpoints. In follow-up patches I will add support for a bare
bones PLUS_EXPR range-op-float entry to solve the PR.
I have chosen to use REAL_VALUE_TYPEs for the endpoints, since that's
what we use underneath the trees. This will be somewhat analogous to
our eventual use of wide-ints in the irange. No sense going through
added levels of indirection if we can avoid it. That, plus real.*
already has a nice API for dealing with floats.
With this patch, ranges will be closed float point intervals, which
make the implementation simpler, since we don't have to keep track of
open/closed intervals. This is conservative enough for use in the
ranger world, as we'd rather err on the side of more elements in a
range, than less.
For example, even though we cannot precisely represent the open
interval (3.0, 5.0) with this approach, it is perfectably reasonable
to represent it as [3.0, 5.0] since the closed interval is a super set
of the open one. In the VRP/ranger world, it is always better to
err on the side of more information in a range, than not. After all,
when we don't know anything about a range, we just use VARYING which
is a fancy term for a range spanning the entire domain.
Since REAL_VALUE_TYPEs have properly defined infinity and NAN
semantics, all the math can be made to work:
[-INF, 3.0] !NAN => Numbers <= 3.0 (NAN cannot happen)
[3.0, 3.0] => 3.0 or NAN.
[3.0, +INF] => Numbers >= 3.0 (NAN is possible)
[-INF, +INF] => VARYING (NAN is possible)
[-INF, +INF] !NAN => Entire domain. NAN cannot happen.
Also, since REAL_VALUE_TYPEs can represent the minimum and maximum
representable values of a TYPE_MODE, we can disambiguate between them
and negative and positive infinity (see get_max_float in real.cc).
This also makes the math all work. For example, suppose we know
nothing about x and y (VARYING). On the TRUE side of x > y, we can
deduce that:
(a) x cannot be NAN
(b) y cannot be NAN
(c) y cannot be +INF.
(c) means that we can drop the upper bound of "y" from +INF to the
maximum representable value for its type.
Having endpoints with different representation for infinity and the
maximum representable values, means we can drop the +-INF properties
we currently have in the frange.
gcc/ChangeLog:
* range-op-float.cc (frange_set_nan): New.
(frange_drop_inf): New.
(frange_drop_ninf): New.
(foperator_equal::op1_range): Adjust for endpoints.
(foperator_lt::op1_range): Same.
(foperator_lt::op2_range): Same.
(foperator_gt::op1_range): Same.
(foperator_gt::op2_range): Same.
(foperator_unordered::op1_range): Same.
* value-query.cc (range_query::get_tree_range): Same.
* value-range-pretty-print.cc (vrange_printer::visit): Same.
* value-range-storage.cc (frange_storage_slot::get_frange): Same.
* value-range.cc (frange::set): Same.
(frange::normalize_kind): Same.
(frange::union_): Same.
(frange::intersect): Same.
(frange::operator=): Same.
(early_nan_resolve): New.
(frange::contains_p): New.
(frange::singleton_p): New.
(frange::set_nonzero): New.
(frange::nonzero_p): New.
(frange::set_zero): New.
(frange::zero_p): New.
(frange::set_nonnegative): New.
(frange_float): New.
(frange_nan): New.
(range_tests_nan): New.
(range_tests_signed_zeros): New.
(range_tests_floats): New.
(range_tests): New.
* value-range.h (frange::lower_bound): New.
(frange::upper_bound): New.
(vrp_val_min): Use real_inf with a sign instead of negating inf.
(frange::frange): New.
(frange::set_varying): Adjust for endpoints.
(real_max_representable): New.
(real_min_representable): New.
Diffstat (limited to 'gcc/value-range-storage.cc')
-rw-r--r-- | gcc/value-range-storage.cc | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index ea3b83c..adf23c3 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -261,6 +261,18 @@ frange_storage_slot::get_frange (frange &r, tree type) const { gcc_checking_assert (r.supports_type_p (type)); + // FIXME: NANs get special treatment, because we need [NAN, NAN] in + // the range to properly represent it, not just the NAN flag in the + // property bits. This will go away when we stream out the + // endpoints. + if (m_props.get_nan ().yes_p ()) + { + REAL_VALUE_TYPE rv; + real_nan (&rv, "", 1, TYPE_MODE (type)); + r.set (type, rv, rv); + return; + } + r.set_varying (type); r.m_props = m_props; r.normalize_kind (); |