Age | Commit message (Collapse) | Author | Files | Lines |
|
This patch adds the ability to resize ranges as needed, defaulting to no
resizing. int_range_max now defaults to 3 sub-ranges (instead of 255)
and grows to 255 when the range being calculated does not fit.
PR tree-optimization/110315
* value-range-storage.h (vrange_allocator::alloc_irange): Adjust
new params.
* value-range.cc (irange::operator=): Resize range.
(irange::irange_union): Same.
(irange::irange_intersect): Same.
(irange::invert): Same.
* value-range.h (irange::maybe_resize): New.
(~int_range): New.
(int_range_max): Default to 3 sub-ranges and resize as needed.
(int_range::int_range): Adjust for resizing.
(int_range::operator=): Same.
|
|
As discussed in the PR, flushing denormals to zero on every frange::set
might be harmful for e.g. x < 0.0 comparisons, because we then on both
sides use ranges that include zero [-Inf, -0.0] on the true side, and
[-0.0, +Inf] NAN on the false side, rather than [-Inf, nextafter (-0.0, -Inf)]
on the true side.
The following patch does it only in range_operator_float::fold_range
which is right now used for +-*/ (both normal and reverse ops of those).
Though, I don't see any difference on the testcase in the PR, but not sure
what I should be looking at and the reduced testcase there has undefined
behavior.
2023-03-28 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/109154
* value-range.h (frange::flush_denormals_to_zero): Make it public
rather than private.
* value-range.cc (frange::set): Don't call flush_denormals_to_zero
here.
* range-op-float.cc (range_operator_float::fold_range): Call
flush_denormals_to_zero.
|
|
I've noticed a comment typo in tree-vrp.cc and decided to quickly
skim aspell -c on the ranger sources (with quick I on everything that
looked ok or roughly ok).
But not being a native English speaker, I could get stuff wrong.
2023-03-23 Jakub Jelinek <jakub@redhat.com>
* value-range.cc (irange::irange_union, irange::intersect): Fix
comment spelling bugs.
* gimple-range-trace.cc (range_tracer::do_header): Likewise.
* gimple-range-trace.h: Likewise.
* gimple-range-edge.cc: Likewise.
(gimple_outgoing_range_stmt_p,
gimple_outgoing_range::switch_edge_range,
gimple_outgoing_range::edge_range_p): Likewise.
* gimple-range.cc (gimple_ranger::prefill_stmt_dependencies,
gimple_ranger::fold_stmt, gimple_ranger::register_transitive_infer,
assume_query::assume_query, assume_query::calculate_phi): Likewise.
* gimple-range-edge.h: Likewise.
* value-range.h (Value_Range::set, Value_Range::lower_bound,
Value_Range::upper_bound, frange::set_undefined): Likewise.
* gimple-range-gori.h (range_def_chain::depend, gori_map::m_outgoing,
gori_compute): Likewise.
* gimple-range-fold.h (fold_using_range): Likewise.
* gimple-range-path.cc (path_range_query::compute_ranges_in_phis):
Likewise.
* gimple-range-gori.cc (range_def_chain::in_chain_p,
range_def_chain::dump, gori_map::calculate_gori,
gori_compute::compute_operand_range_switch,
gori_compute::logical_combine, gori_compute::refine_using_relation,
gori_compute::compute_operand1_range, gori_compute::may_recompute_p):
Likewise.
* gimple-range.h: Likewise.
(enable_ranger): Likewise.
* range-op.h (empty_range_varying): Likewise.
* value-query.h (value_query): Likewise.
* gimple-range-cache.cc (block_range_cache::set_bb_range,
block_range_cache::dump, ssa_global_cache::clear_global_range,
temporal_cache::temporal_value, temporal_cache::current_p,
ranger_cache::range_of_def, ranger_cache::propagate_updated_value,
ranger_cache::range_from_dom, ranger_cache::register_inferred_value):
Likewise.
* gimple-range-fold.cc (fur_edge::get_phi_operand,
fur_stmt::get_operand, gimple_range_adjustment,
fold_using_range::range_of_phi,
fold_using_range::relation_fold_and_or): Likewise.
* value-range-storage.h (irange_storage_slot::MAX_INTS): Likewise.
* value-query.cc (range_query::value_of_expr,
range_query::value_on_edge, range_query::query_relation): Likewise.
* tree-vrp.cc (remove_unreachable::remove_and_update_globals,
intersect_range_with_nonzero_bits): Likewise.
* gimple-range-infer.cc (gimple_infer_range::check_assume_func,
exit_range): Likewise.
* value-relation.h: Likewise.
(equiv_oracle, relation_trio::relation_trio, value_relation,
value_relation::value_relation, pe_min): Likewise.
* range-op-float.cc (range_operator_float::rv_fold,
frange_arithmetic, foperator_unordered_equal::op1_range,
foperator_div::rv_fold): Likewise.
* gimple-range-op.cc (cfn_clz::fold_range): Likewise.
* value-relation.cc (equiv_oracle::query_relation,
equiv_oracle::register_equiv, equiv_oracle::add_equiv_to_block,
value_relation::apply_transitive, relation_chain_head::find_relation,
dom_oracle::query_relation, dom_oracle::find_relation_block,
dom_oracle::find_relation_dom, path_oracle::register_equiv): Likewise.
* range-op.cc (range_operator::wi_fold_in_parts_equiv,
create_possibly_reversed_range, adjust_op1_for_overflow,
operator_mult::wi_fold, operator_exact_divide::op1_range,
operator_cast::lhs_op1_relation, operator_cast::fold_pair,
operator_cast::fold_range, operator_abs::wi_fold, range_op_cast_tests,
range_op_lshift_tests): Likewise.
|
|
This patch implements a nan_state class, that allows us to query or
pass around the NANness of an frange. We can store +NAN, -NAN, +-NAN,
or not-a-NAN with it.
I tried to touch as little as possible, leaving other cleanups to the
next release. For example, we should replace the m_*_nan fields in
frange with nan_state, and provide relevant accessors to nan_state
(isnan, etc).
PR tree-optimization/109008
gcc/ChangeLog:
* value-range.cc (frange::set): Add nan_state argument.
* value-range.h (class nan_state): New.
(frange::get_nan_state): New.
|
|
As discussed in the PR, for trapping math, do not fold overflowing
operations into +-INF as doing so could elide a trap.
There is a minor adjustment to known_isinf() where it was mistakenly
returning true for an [infinity U NAN], whereas it should only return
true when the range is exclusively +INF or -INF. This is benign, as
there were no users of known_isinf up to now.
Tested on x86-64 Linux.
I also ran the glibc testsuite (git sources) on x86-64 and this patch
fixes:
-FAIL: math/test-double-lgamma
-FAIL: math/test-double-log1p
-FAIL: math/test-float-lgamma
-FAIL: math/test-float-log1p
-FAIL: math/test-float128-catan
-FAIL: math/test-float128-catanh
-FAIL: math/test-float128-lgamma
-FAIL: math/test-float128-log
-FAIL: math/test-float128-log1p
-FAIL: math/test-float128-y0
-FAIL: math/test-float128-y1
-FAIL: math/test-float32-lgamma
-FAIL: math/test-float32-log1p
-FAIL: math/test-float32x-lgamma
-FAIL: math/test-float32x-log1p
-FAIL: math/test-float64-lgamma
-FAIL: math/test-float64-log1p
-FAIL: math/test-float64x-lgamma
-FAIL: math/test-ldouble-lgamma
PR tree-optimization/107608
gcc/ChangeLog:
* range-op-float.cc (range_operator_float::fold_range): Avoid
folding into INF when flag_trapping_math.
* value-range.h (frange::known_isinf): Return false for possible NANs.
|
|
|
|
As mentioned earlier, we should be using HONOR_* on types rather than
flag_finite_math_only.
gcc/ChangeLog:
* value-range.cc (frange::set): Use HONOR_*.
(frange::verify_range): Same.
* value-range.h (frange_val_min): Same.
(frange_val_max): Same.
|
|
Since NANs can't appear in ranges for !HONOR_NANS, there's no reason
to set them in a VARYING range.
gcc/ChangeLog:
* value-range.h (frange::set_varying): Do not set NAN flags for
!HONOR_NANS.
* value-range.cc (frange::normalize_kind): Adjust for no NAN when
!HONOR_NANS.
(frange::verify_range): Same.
* range-op-float.cc (maybe_isnan): Remove flag_finite_math_only check.
|
|
In writing some range-op entries I noticed we don't have a way to
query the sign of the NAN in a range, unless the range only contains
NAN, in which case you can just use frange::signbit_p. This patch
adds a method that returns TRUE if there exists the possiblity of a
NAN and we know its sign.
gcc/ChangeLog:
* value-range.h (frange::nan_signbit_p): New.
|
|
We have a set_nan(type) method which can be confused with
update_nan(bool) because of the silent conversion of pointers to bool.
Currently, if you call update_nan(tree), you'll set the possibility of
NAN with a sign of true if tree is non-null. This is prone to error
and this patch disallows this behavior.
gcc/ChangeLog:
* value-range.cc (frange::set_nonnegative): Pass bool to
update_nan.
* value-range.h: Disallow conversion to bool in update_nan().
|
|
gcc/ChangeLog:
* value-range.h (frange::frange): Add constructor taking type.
|
|
It is useful to know if there's the possiblity of a NAN with a given
sign. This is to complement maybe_isnan(void) which returns TRUE for a
NAN of any sign.
A follow-up patch implementing ABS will make use of this.
gcc/ChangeLog:
* value-range.h (frange::maybe_isnan): New.
|
|
Having nonzero masks always set had a performance penalty of 10% in
VRP, so mask==NULL is a shortcut to all bits set.
gcc/ChangeLog:
* value-range.cc (irange::irange_set): Convert nonzero mask to
tree.
(irange::irange_set_anti_range): Same.
(irange::set): Same.
(irange::verify_range): Same.
(irange::contains_p): Same.
(irange::invert): Same.
(irange::set_range_from_nonzero_bits): Same.
(irange::set_nonzero_bits): Same.
(mask_to_wi): Same.
(irange::intersect_nonzero_bits): Same.
(irange::union_nonzero_bits): Same.
* value-range.h (irange::varying_compatible_p): Same.
(gt_ggc_mx): Same.
(gt_pch_nx): Same.
(irange::set_undefined): Same.
(irange::set_varying): Same.
|
|
We recently agreed that setting a range of NAN should instead set
UNDEFINED for -ffinite-math-only. This patch makes that change to
frange::set_nan() directly. Also, calling frange::update_nan() will now
be a nop for !HONOR_NANS.
Doing this in the setters simplifies everywhere we set NANs, as it keeps
us from introducing NANs by mistake.
gcc/ChangeLog:
* value-range.cc (frange::set): Call set_nan unconditionally.
(range_tests_nan): Adjust tests.
(range_tests_signed_zeros): Same.
(range_tests_floats): Same.
* value-range.h (frange::update_nan): Guard with HONOR_NANS.
(frange::set_nan): Set undefined if !HONOR_NANS.
|
|
The reason the nonzero mask was kept in a tree was basically inertia,
as everything in irange is a tree. However, there's no need to keep
it in a tree, as the conversions to and from wide ints are very
annoying. That, plus special casing NULL masks to be -1 is prone
to error.
I have not only rewritten all the uses to assume a wide int, but
have corrected a few places where we weren't propagating the masks, or
rather pessimizing them to -1. This will become more important in
upcoming patches where we make better use of the masks.
Performance testing shows a trivial improvement in VRP, as things like
irange::contains_p() are tied to a tree. Ughh, can't wait for trees in
iranges to go away.
gcc/ChangeLog:
* value-range-storage.cc (irange_storage_slot::set_irange): Remove
special case.
* value-range.cc (irange::irange_set): Adjust for nonzero mask
being a wide int.
(irange::irange_set_anti_range): Same.
(irange::set): Same.
(irange::verify_range): Same.
(irange::legacy_equal_p): Same.
(irange::operator==): Same.
(irange::contains_p): Same.
(irange::legacy_intersect): Same.
(irange::legacy_union): Same.
(irange::irange_single_pair_union): Call union_nonzero_bits.
(irange::irange_union): Same.
(irange::irange_intersect): Call intersect_nonzero_bits.
(irange::intersect): Adjust for nonzero mask being a wide int.
(irange::invert): Same.
(irange::set_nonzero_bits): Same.
(irange::get_nonzero_bits_from_range): New.
(irange::set_range_from_nonzero_bits): New.
(irange::get_nonzero_bits): Adjust for nonzero mask being a wide
int.
(irange::intersect_nonzero_bits): Same.
(irange::union_nonzero_bits): Same.
(range_tests_nonzero_bits): Remove test.
* value-range.h (irange::varying_compatible_p): Adjust for nonzero
mask being a wide int.
(gt_ggc_mx): Same.
(gt_pch_nx): Same.
(irange::set_undefined): Same.
(irange::set_varying): Same.
(irange::normalize_kind): Same.
|
|
Just the same way as we have real_value setters for franges, we should
have a wide_int version for irange. This matches the irange
constructor for wide_ints, and paves the way for the eventual
conversion of irange to wide ints.
gcc/ChangeLog:
* value-range.h (irange::set): New version taking wide_int_ref.
|
|
Similarly to how we drop NANs to UNDEFINED when -ffinite-math-only, I
think we can drop the numbers outside of the min/max representable
numbers to the representable number.
This means the endpoings to VR_VARYING for -ffinite-math-only can now
be the min/max representable, instead of -INF and +INF.
Saturating in the setter means that the upcoming implementation for
binary operators no longer have to worry about doing the right
thing for -ffinite-math-only. If the range goes outside the limits,
it'll get chopped down.
Tested on x86-64 Linux.
gcc/ChangeLog:
* range-op-float.cc (build_le): Use vrp_val_*.
(build_lt): Same.
(build_ge): Same.
(build_gt): Same.
* value-range.cc (frange::set): Chop ranges outside of the
representable numbers for -ffinite-math-only.
(frange::normalize_kind): Use vrp_val*.
(frange::verify_range): Same.
(frange::set_nonnegative): Same.
(range_tests_floats): Remove tests that depend on -INF and +INF.
* value-range.h (real_max_representable): Add prototype.
(real_min_representable): Same.
(vrp_val_max): Set max representable number for
-ffinite-math-only.
(vrp_val_min): Same but for min.
(frange::set_varying): Use vrp_val*.
|
|
gcc/ChangeLog:
* value-range.cc (frange::combine_zeros): Call set_undefined.
(frange::intersect_nans): Same.
(frange::intersect): Same.
(frange::verify_range): Undefined ranges do not have a type.
* value-range.h (frange::set_undefined): Clear NAN flags and type.
|
|
Undefined ranges have undefined NAN bits. We can't depend on them,
as they may contain garbage. This patch returns false from
maybe_isnan() for undefined ranges (the empty set).
gcc/ChangeLog:
* value-range.h (frange::maybe_isnan): Return false for
undefined ranges.
|
|
A specifically nonnegative range should not contain -NAN, otherwise
signbit_p() would return false, because we'd be unsure of the sign.
PR 68097/tree-optimization
gcc/ChangeLog:
* value-range.cc (frange::set_nonnegative): Set +NAN.
(range_tests_signed_zeros): New test.
* value-range.h (frange::update_nan): New overload to set NAN sign.
|
|
For some architectures (or for -funsafe-math-optimizations) we may
flush denormals to zero, in which case we need to be careful to
extend the ranges to the appropriate zero. This patch does exactly that.
For a range of [x, -DENORMAL] we flush to [x, -0.0] and for [+DENORMAL, x]
we flush to [+0.0, x].
gcc/ChangeLog:
* value-range.cc (frange::flush_denormals_to_zero): New.
(frange::set): Call flush_denormals_to_zero.
* value-range.h (class frange): Add flush_denormals_to_zero.
|
|
The attatched patch rewrites the NAN and sign handling, dropping both
tristates in favor of a pair of boolean flags for NANs, and nothing at
all for signs. The signs are tracked in the range itself, so now it's
possible to describe things like [-0.0, +0.0] +NAN, [+0, +0], [-5, +0],
[+0, 3] -NAN, etc.
Here is an example of the various ranges and how they are displayed:
[frange] float VARYING NAN ;; Varying includes NAN
[frange] UNDEFINED ;; Empty set as always
[frange] float [] +-NAN ;; Unknown sign NAN
[frange] float [] -NAN ;; -NAN
[frange] float [] +NAN ;; +NAN
[frange] float [-0.0, 0.0] ;; All zeros.
[frange] float [-0.0, -0.0] +-NAN ;; -0 or NAN.
[frange] float [-5.0e+0, -1.0e+0] +NAN ;; [-5, -1] or +NAN
[frange] float [-5.0e+0, -0.0] +-NAN ;; [-5, -0] or NAN
[frange] float [-5.0e+0, -0.0] ;; [-5, -0]
[frange] float [5.0e+0, 1.0e+1] ;; [5, 10]
Notice the NAN signs are decoupled from the range, so we can represent
a negative range with a positive NAN. For this range,
frange::signbit_p() would return false, as only when the signs of the
NANs and range agree can we be certain.
There is no longer any pessimization of ranges for intersects
involving NANs. Also, union and intersect work with signed zeros:
// [-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]
The special casing for signed zeros in the singleton code is gone in
favor of just making sure the signs in the range agree, that is
[-0, -0] for example.
I have removed the idea that a known NAN is a "range", so a NAN is no
longer in the endpoints itself. Requesting the bound of a known NAN
is a hard fail. For that matter, we don't store the actual NAN in the
range. The only information we have are the set of boolean flags.
This way we make sure nothing seeps into the frange. This also means
it's explicit that we don't track anything but the sign in NANs. We
can revisit this if we desire to track signalling or whatever
concoction y'all can imagine.
Regstrapped with mpfr tests on x86-64 and ppc64le Linux. Selftests
were also run with -ffinite-math-only on x86-64.
At Jakub's suggestion, I built lapack with associated tests. They
pass on x86-64 and ppc64le Linux with no regressions from mainline.
As a sanity check, I also ran them for -ffinite-math-only on x86 which
(as expected) returned:
NaN arithmetic did not perform per the ieee spec
Otherwise, all tests pass for -ffinite-math-only.
gcc/ChangeLog:
* range-op-float.cc (frange_add_zeros): Replace set_signbit with
union of zero.
* value-query.cc (range_query::get_tree_range): Remove set_signbit
use.
* value-range-pretty-print.cc (vrange_printer::print_frange_prop):
Remove.
(vrange_printer::print_frange_nan): New.
* value-range-pretty-print.h (print_frange_prop): Remove.
(print_frange_nan): New.
* value-range-storage.cc (frange_storage_slot::set_frange): Set
kind and NAN fields.
(frange_storage_slot::get_frange): Restore kind and NAN fields.
* value-range-storage.h (class frange_storage_slot): Add kind and
NAN fields.
* value-range.cc (frange::update_nan): Remove.
(frange::set_signbit): Remove.
(frange::set): Adjust for NAN fields.
(frange::normalize_kind): Remove m_props.
(frange::combine_zeros): New.
(frange::union_nans): New.
(frange::union_): Handle new NAN fields.
(frange::intersect_nans): New.
(frange::intersect): Handle new NAN fields.
(frange::operator=): Same.
(frange::operator==): Same.
(frange::contains_p): Same.
(frange::singleton_p): Remove special case for signed zeros.
(frange::verify_range): Adjust for new NAN fields.
(frange::set_zero): Handle signed zeros.
(frange::set_nonnegative): Same.
(range_tests_nan): Adjust tests.
(range_tests_signed_zeros): Same.
(range_tests_signbit): Same.
(range_tests_floats): Same.
* value-range.h (class fp_prop): Remove.
(FP_PROP_ACCESSOR): Remove.
(class frange_props): Remove
(frange::lower_bound): NANs don't have endpoints.
(frange::upper_bound): Same.
(frange_props::operator==): Remove.
(frange_props::union_): Remove.
(frange_props::intersect): Remove.
(frange::update_nan): New.
(frange::clear_nan): New.
(frange::undefined_p): New.
(frange::set_nan): New.
(frange::known_finite): Adjust for new NAN representation.
(frange::maybe_isnan): Same.
(frange::known_isnan): Same.
(frange::signbit_p): Same.
* gimple-range-fold.cc (range_of_builtin_int_call): Rename
known_signbit_p into signbit_p.
|
|
This patch cleans up the frange::set() code by passing all things NAN
to frange::set_nan().
No functional changes.
Regstrapped on x86-64 Linux, plus I ran selftests for
-ffinite-math-only.
gcc/ChangeLog:
* value-range.cc (frange::set): Use set_nan.
* value-range.h (frange::set_nan): Inline code originally in
set().
|
|
set_* has a very specific meaning for irange's and friends. Methods
prefixed with set_* are setters clobbering the existing range. As
such, the current set_nan() method is confusing in that it's not
actually setting a range to a NAN, but twiddling the NAN flags for an
existing frange.
This patch replaces set_nan() with an update_nan() to set the flag,
and clear_nan() to clear it. This makes the code clearer, and though
the confusing tristate is still there, it will be removed in upcoming
patches.
Also, there is now an actual set_nan() method to set the range to a
NAN. This replaces two out of class functions doing the same thing.
In future patches I will also add the ability to create a NAN with a
specific sign, but doing so now would be confusing because we're not
tracking NAN signs.
We should also submit set_signbit to the same fate, but it's about to
get removed.
No functional changes.
Regstrapped on x86-64 Linux, plus I ran selftests for
-ffinite-math-only.
gcc/ChangeLog:
* range-op-float.cc (frange_set_nan): Remove.
(build_lt): Use set_nan, update_nan, clear_nan.
(build_gt): Same.
(foperator_equal::op1_range): Same.
(foperator_not_equal::op1_range): Same.
(foperator_lt::op1_range): Same.
(foperator_lt::op2_range): Same.
(foperator_le::op1_range): Same.
(foperator_le::op2_range): Same.
(foperator_gt::op1_range): Same.
(foperator_gt::op2_range): Same.
(foperator_ge::op1_range): Same.
(foperator_ge::op2_range): Same.
(foperator_unordered::op1_range): Same.
(foperator_ordered::op1_range): Same.
* value-query.cc (range_query::get_tree_range): Same.
* value-range.cc (frange::set_nan): Same.
(frange::update_nan): Same.
(frange::union_): Same.
(frange::intersect): Same.
(range_tests_nan): Same.
(range_tests_signed_zeros): Same.
(range_tests_signbit): Same.
(range_tests_floats): Same.
* value-range.h (class frange): Add update_nan and clear_nan.
(frange::set_nan): New.
|
|
Following are a series of cleanups to the frange code in preparation
for a much more invasive patch rewriting the NAN and sign tracking
bits. Please be patient, as I'm trying to break everything up into
small chunks instead of dropping a mondo patch removing the NAN and
sign tristate handling.
No functional changes.
Regstrapped on x86-64 Linux, plus I ran selftests for
-ffinite-math-only.
gcc/ChangeLog:
* value-query.cc (range_query::get_tree_range): Remove check for overflow.
* value-range-pretty-print.cc (vrange_printer::visit): Move read
of type until after undefined_p is checked.
* value-range.cc (frange::set): Remove asserts for REAL_CST.
(frange::contains_p): Tidy up.
(range_tests_nan): Add comment.
* value-range.h (frange::type): Check for undefined_p.
(frange::set_undefined): Remove set of endpoints.
|
|
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.
|
|
As Jakub mentioned in the PR, because many numbers have multiple
possible representations, we can't reliably return true for singleton_p.
For that matter, we may not be capable of modeling them just yet.
Disabling them until someone with DFP knowledge can opine or extend
frange.
PR middle-end/106831
gcc/ChangeLog:
* value-range.h (frange::supports_p): Disable decimal floats.
* range-op-float.cc (frange_drop_inf): Remove DECIMAL_FLOAT_MODE_P
check.
(frange_drop_ninf): Same.
|
|
gcc/ChangeLog:
* range-op-float.cc (build_le): Convert to dconst*inf.
(build_ge): Same.
* value-range.cc (frange::set_signbit): Same.
(frange::normalize_kind): Same.
(range_tests_floats): Same.
* value-range.h (vrp_val_max): Same.
(vrp_val_min): Same.
(frange::set_varying): Same.
|
|
As discussed here:
https://gcc.gnu.org/pipermail/gcc-patches/2022-August/600656.html
This adds an frange property to keep track of the sign bit. We keep
it updated at all times, but we don't use it make any decisions when
!HONOR_SIGNED_ZEROS.
With this property we can now query the range for the appropriate sign
with frange::get_signbit (). Possible values are yes, no, and unknown.
gcc/ChangeLog:
* range-op-float.cc (foperator_equal::op1_range): Do not copy sign
bit.
(foperator_not_equal::op1_range): Same.
* value-query.cc (range_query::get_tree_range): Set sign bit.
* value-range-pretty-print.cc (vrange_printer::visit): Dump sign bit.
* value-range.cc (frange::set_signbit): New.
(frange::set): Adjust for sign bit.
(frange::normalize_kind): Same.
(frange::union_): Remove useless comment.
(frange::intersect): Same.
(frange::contains_p): Adjust for sign bit.
(frange::singleton_p): Same.
(frange::verify_range): Same.
(range_tests_signbit): New tests.
(range_tests_floats): Call range_tests_signbit.
* value-range.h (class frange_props): Add signbit
(class frange): Same.
|
|
gcc/ChangeLog:
* value-range.h: Add more override keywords.
|
|
Fixes:
gcc/value-range.h:357:16: warning: 'set_nonnegative' overrides
a member function but is not marked 'override' [-Winconsistent-missing-override]
gcc/ChangeLog:
* value-range.h: Add override.
|
|
Setting the definite NAN property should also force a [NAN, NAN]
range, otherwise we'd have two ways of representing a NAN: with the
endpoints or with the property. In the ranger world we avoid at all
costs having more than one representation for a range.
In doing this, I removed the FRANGE_PROP_ACCESSOR macro, since it
looks like setting a property may have repercurssions in the range
itself, so it's best for the client to definte its own setter.
gcc/ChangeLog:
* value-range-storage.cc (frange_storage_slot::get_frange): Use
frange_nan.
* value-range.cc (frange::set_nan): New.
(frange_nan): Move to header file.
(range_tests_nan): Adjust frange_nan callers to pass type.
New test.
* value-range.h (FRANGE_PROP_ACCESSOR): Remove.
(frange_nan): New.
|
|
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.
|
|
Add 2 virtual destructors in order to address:
gcc/alloc-pool.h:522:5: warning: destructor called on non-final 'value_range_equiv' that has virtual functions but non-virtual destructor [-Wdelete-non-abstract-non-virtual-dtor]
gcc/ggc.h:166:3: warning: destructor called on non-final 'int_range<1>' that has virtual functions but non-virtual destructor [-Wdelete-non-abstract-non-virtual-dtor]
gcc/ChangeLog:
* value-range-equiv.h (class value_range_equiv): Add virtual
destructor.
* value-range.h: Likewise.
|
|
An unsupported_range temporary is instantiated in every Value_Range
for completeness sake and should be mostly a NOP. However, it's
showing up in the callgrind stats, because it's not inline. This
fixes the oversight.
PR tree-optimization/106514
gcc/ChangeLog:
* value-range.cc (unsupported_range::unsupported_range): Move...
* value-range.h (unsupported_range::unsupported_range): ...here.
(unsupported_range::set_undefined): New.
|
|
Without further ado, here is the implementation for floating point
range operators, plus the switch to enable all ranger clients to
handle floats.
These are bare bone implementations good enough for relation operators
to work, while keeping the NAN bits up to date in the frange. There
is also minimal support for keeping track of +-INF when it is obvious.
Tested on x86-64 Linux.
gcc/ChangeLog:
* range-op-float.cc (finite_operands_p): New.
(frelop_early_resolve): New.
(default_frelop_fold_range): New.
(class foperator_equal): New.
(class foperator_not_equal): New.
(class foperator_lt): New.
(class foperator_le): New.
(class foperator_gt): New.
(class foperator_ge): New.
(class foperator_unordered): New.
(class foperator_ordered): New.
(class foperator_relop_unknown): New.
(floating_op_table::floating_op_table): Add above classes to
floating op table.
* value-range.h (frange::supports_p): Enable.
gcc/testsuite/ChangeLog:
* g++.dg/opt/pr94589-2.C: XFAIL.
* gcc.dg/tree-ssa/vrp-float-1.c: New test.
* gcc.dg/tree-ssa/vrp-float-11.c: New test.
* gcc.dg/tree-ssa/vrp-float-3.c: New test.
* gcc.dg/tree-ssa/vrp-float-4.c: New test.
* gcc.dg/tree-ssa/vrp-float-6.c: New test.
* gcc.dg/tree-ssa/vrp-float-7.c: New test.
* gcc.dg/tree-ssa/vrp-float-8.c: New test.
|
|
These are some assorted cleanups to the frange class to make it easier
to drop in an implementation with FP endpoints:
* frange::set() had some asserts limiting the type of arguments
passed. There's no reason why we can't handle all the variants.
Worse comes to worse, we can always return a VARYING which is
conservative and correct.
* frange::normalize_kind() now returns a boolean that can be used in
union and intersection to indicate that the range changed.
* Implement vrp_val_max and vrp_val_min for floats. Also, move them
earlier in the header file so frange can use them.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.cc (tree_compare): New.
(frange::set): Make more general.
(frange::normalize_kind): Cleanup and return bool.
(frange::union_): Use normalize_kind return value.
(frange::intersect): Same.
(frange::verify_range): Remove unnecessary else.
* value-range.h (vrp_val_max): Move before frange class.
(vrp_val_min): Same.
(frange::frange): Remove set to m_type.
|
|
Make all vrange::supports_*_p methods const_tree as they can end up
being called from functions that are const_tree.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.cc (vrange::supports_type_p): Use const_tree.
(irange::supports_type_p): Same.
(frange::supports_type_p): Same.
* value-range.h (Value_Range::supports_type_p): Same.
(irange::supports_p): Same.
|
|
This implements a basic frange class to represent floating point
ranges. Although it is meant to be a base for further development, it
is enough to handle relations and propagate NAN and other properties.
For ranger clients to become floating point aware, we still need the
range-op entries, which I will submit later this week. Since those
entries require specialized FP knowledge, I will ask for a review from
the FP experts before committing.
Once range-op entries come live, all ranger clients that have been
converted to the type agnostic vrange API will become FP aware: evrp,
DOM, the threaders, loop-ch, etc. (Still missing is loop unswitching,
as a lot of the int_range* temporaries should be Value_Range. I don't
have enough cycles to convert loop unswitching, but could gladly give
guidance. It should be straightforward for those familiar with the
code ;-)).
Samples things we handle:
* We can set the FP properties (!NAN, !INF, etc) at assignment from
constants (and propagate them throughout the CFG):
float z = 0.0;
if (__builtin_isnan (z))
link_error ();
* The relation oracle works in tandem with the FP ranges:
if (x > y)
;
else if (!__builtin_isnan (x) && !__builtin_isnan (y))
{
// If x and y are not NAN, the x <= y relationship holds, and the
// following conditional can be folded away.
if (x <= y)
bar ();
}
* We know the true side of all ordered conditionals (except !=)
implies !NAN:
if (x > y)
{
if (__builtin_isnan (x) || __builtin_isnan (y))
link_error ();
}
Range-ops also works correctly with -ffinite-math-only, and avoids
checking for NANs, etc.
I believe this is enough to get a fully fleshed out floating point
support for evrp and friends, but doing so is beyond my limited FP
knowledge. For example, frange could be enhanced to track constant
endpoints, and we could track other FP properties aside from NAN.
Further discussion is gladly welcome.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range-pretty-print.cc (vrange_printer::visit): New.
(vrange_printer::print_frange_prop): New.
* value-range-pretty-print.h (class vrange_printer): Add visit and
print_frange_prop.
* value-range-storage.h (vrange_allocator::alloc_vrange): Handle frange.
(vrange_allocator::alloc_frange): New.
* value-range.cc (vrange::operator=): Handle frange.
(vrange::operator==): Same.
(frange::accept): New.
(frange::set): New.
(frange::normalize_kind): New.
(frange::union_): New.
(frange::intersect): New.
(frange::operator=): New.
(frange::operator==): New.
(frange::supports_type_p): New.
(frange::verify_range): New.
* value-range.h (enum value_range_discriminator): Handle frange.
(class fp_prop): New.
(FP_PROP_ACCESSOR): New.
(class frange_props): New.
(FRANGE_PROP_ACCESSOR): New.
(class frange): New.
(Value_Range::init): Handle frange.
(Value_Range::operator=): Same.
(Value_Range::supports_type_p): Same.
(frange_props::operator==): New.
(frange_props::union_): New.
(frange_props::intersect): New
(frange::frange): New.
(frange::type): New.
(frange::set_varying): New.
(frange::set_undefined): New.
|
|
We need to dump global ranges from the gimple pretty printer code, but
all the vrange dumping facilities work with FILE handles. This patch
converts all the dumping methods to work with pretty printers, and
provides a wrapper so the FILE * methods continue to work for
debugging. I also cleaned up the code a bit.
Tested on x86-64 Linux.
gcc/ChangeLog:
* Makefile.in (OBJS): Add value-range-pretty-print.o.
* pretty-print.h (pp_vrange): New.
* value-range.cc (vrange::dump): Call pp version.
(unsupported_range::dump): Move to its own file.
(dump_bound_with_infinite_markers): Same.
(irange::dump): Same.
(irange::dump_bitmasks): Same.
(vrange::debug): Remove.
* value-range.h: Remove virtual designation for dump methods.
Remove dump_bitmasks method.
* value-range-pretty-print.cc: New file.
* value-range-pretty-print.h: New file.
|
|
We frequently do operations on the various (upcoming) range types.
The cascading if/switch statements of is_a<> are getting annoying and
repetitive.
The classic visitor pattern provides a clean way to implement classes
handling various range types without the need for endless
conditionals. It also helps us keep polluting the vrange API with
functionality that should frankly live elsewhere.
In a follow-up patch I will add pretty printing facilities for vrange
and unify them with the dumping code. This is a prime candidate for
the pattern, as the code isn't performance sensitive. Other instances
(?? the dispatch code in range-ops ??) may still benefit from the hand
coded conditionals, since they elide vtables in favor of the
discriminator bit in vrange.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.cc (irange::accept): New.
(unsupported_range::accept): New.
* value-range.h (class vrange_visitor): New.
(class vrange): Add accept method.
(class unsupported_range): Same.
(class Value_Range): Same.
|
|
In discussions with Andrew we realized varying_p() was returning true
for a range of the entire domain with a non-empty nonzero mask. This
is confusing as varying_p() should only return true when absolutely no
information is available. A nonzero mask that has any cleared bits is
extra information and must return false for varying_p(). This patch
fixes this oversight. Now a range of the entire domain with nonzero
bits, is internally set to VR_RANGE (with the appropriate end points
set). VR_VARYING ranges must have a null nonzero mask.
Also, the union and intersect code were not quite right in the presence of
nonzero masks. Sometimes we would drop masks to -1 unnecessarily. I
was trying to be too smart in avoiding extra work when the mask was
NULL, but there's also an implicit mask in the range that must be
taken into account. For example, [0,0] may have no nonzero bits set
explicitly, but the mask is really 0x0. This will all be simpler when
we drop trees, because the nonzero bits will always be set, even if
-1.
Finally, I've added unit tests to the nonzero mask code. This should
help us maintain sanity going forward.
There should be no visible changes, as the main consumer of this code
is the SSA_NAME_RANGE_INFO patchset which has yet to be committed.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.cc (irange::operator=): Call verify_range.
(irange::irange_set): Normalize kind after everything else has
been set.
(irange::irange_set_anti_range): Same.
(irange::set): Same.
(irange::verify_range): Disallow nonzero masks for VARYING.
(irange::irange_union): Call verify_range.
Handle nonzero masks better.
(irange::irange_intersect): Same.
(irange::set_nonzero_bits): Calculate mask if either range has an
explicit mask.
(irange::intersect_nonzero_bits): Same.
(irange::union_nonzero_bits): Same.
(range_tests_nonzero_bits): New.
(range_tests): Call range_tests_nonzero_bits.
* value-range.h (class irange): Remove set_nonzero_bits method
with trees.
(irange::varying_compatible_p): Set nonzero mask.
|
|
The nonzero bits and integer ranges compliment each other quite well,
and it only makes sense to make the mask a first class citizen in the
irange. We do a half assed job of keeping ranges and nonzero bits
somewhat in sync in SSA_NAME_RANGE_INFO, and the goal has always
been to integrate them properly. This patch does that, in preparation
for streaming out full-resolution iranges between passes (think
SSA_NAME_RANGE_INFO).
Having nonzero bits in the irange allows us to get better results from
things like irange::contains_p() and keeping them in the irange allows
us to propagate the bits throughout with the ranger. This patch
provides the bare infrastructure, without any optimizations to
range-ops, etc. Those will come as follow-ups.
A few notes:
Legacy SSA_NAME_RANGE_INFO updates the nonzero bits every time a range
is set. Here instead, we don't update the nonzero bits on a new
range, but calculate it on the fly when irange::get_nonzero_bits() is
called. The goal is to only store nonzero bits that provide
meaningful information that can't be gleaned from the range itself.
But you can always call get_nonzero_bits() and get the full
information.
Nonzero bits are not supported in legacy mode. The mask may be set
as a consequence of propagation or reading global ranges, but no
one from legacy land should be querying irange::get_nonzero_bits. There
is an assert enforcing this. However, legacy/global set_nonzero_bits()
continue to work as before. There is no change to legacy behavior.
There is virtually no performance change with this patch, as there are
no consumers. The next patch I post will be the SSA_NAME_RANGE_INFO
conversion to the new world, in which I will discuss performance
proper. Hint: I'll be chewing up the time budget we gained with the
vrange conversion.
Tested and benchmarked on x86-64 Linux.
gcc/ChangeLog:
* value-range-storage.cc (irange_storage_slot::set_irange): Set
nonzero bits in irange.
(irange_storage_slot::get_irange): Get nonzero bits from irange.
* value-range.cc (irange::operator=): Set nonzero bits.
(irange::irange_set): Same.
(irange::irange_set_anti_range): Same.
(irange::set): Same.
(irange::verify_range): Same.
(irange::legacy_equal_p): Check nonzero bits.
(irange::equal_p): Same.
(irange::contains_p): Handle nonzero bits.
(irange::irange_union): Same.
(irange::irange_intersect): Same.
(irange::dump): Same.
(irange::set_nonzero_bits): New.
(irange::get_nonzero_bits): New.
(irange::intersect_nonzero_bits): New.
(irange::union_nonzero_bits): New.
(irange::dump_bitmasks): New.
* value-range.h (class irange): Add m_nonzero_mask.
(gt_ggc_mx): Handle nonzero bits.
(gt_pch_nx): Same.
(irange::set_undefined): Set nonzero bits.
(irange::set_varying): Same.
(irange::normalize_kind): Call set_undefined.
|
|
Tested on x86-64 Linux.
gcc/ChangeLog:
* ipa-cp.cc (ipcp_vr_lattice::meet_with_1): Use operator!=.
* ipa-prop.cc (struct ipa_vr_ggc_hash_traits): Same.
* tree-ssa-loop-unswitch.cc (struct unswitch_predicate): Use set
with two arguments.
(find_unswitching_predicates_for_bb): Same.
* tree-vrp.cc (range_fold_unary_symbolics_p): Same.
* value-range-equiv.cc (value_range_equiv::equal_p): Use operator==.
* value-range.cc (irange::equal_p): Rename to...
(irange::operator==): ...this.
* value-range.h (irange::set): Remove.
(irange::operator==): Remove.
(irange::set_zero): Use set with two arguments.
* vr-values.cc (vr_values::extract_range_from_binary_expr): Same.
(vr_values::extract_range_from_unary_expr): Same.
(check_for_binary_op_overflow): Same.
(bounds_of_var_in_loop): Same.
|
|
Now that vrange_storage is in its own file, I think it's prudent to
move all the vrange allocator code there since it's all related.
The users of value-range.h do not need to know the implementation
details of the storage facilities.
Tested and benchmarked on x86-64 Linux.
gcc/ChangeLog:
* gimple-range-cache.cc: Include value-range-storage.h.
* gimple-range-cache.h (class block_range_cache): Add "class" to
m_range_allocator.
* gimple-range-edge.cc
(gimple_outgoing_range::gimple_outgoing_range): Allocate allocator.
(gimple_outgoing_range::~gimple_outgoing_range): Free allocator.
(gimple_outgoing_range::calc_switch_ranges): Dereference allocator.
* gimple-range-edge.h: Add "class" to m_range_allocator.
* gimple-range-infer.cc
(infer_range_manager::infer_range_manager): Allocate allocator.
(infer_range_manager::~infer_range_manager): Free allocator.
(infer_range_manager::get_nonzero): Dereference allocator.
(infer_range_manager::add_range): Same.
* gimple-range-infer.h (class vrange_allocator): Add "class" to
m_range_allocator.
* value-range-storage.h (class vrange_allocator): Move from
value-range.h.
(class obstack_vrange_allocator): Same.
(class ggc_vrange_allocator): Same.
(vrange_allocator::alloc_vrange): Same.
(vrange_allocator::alloc_irange): Same.
* value-range.h (class vrange_allocator): Move to value-range-storage.h.
(class obstack_vrange_allocator): Same.
(class ggc_vrange_allocator): Same.
|
|
This patch makes the vrange_allocator an abstract class, and uses it
to implement the obstack allocator as well as a new GC allocator.
The GC bits will be used to implement the vrange storage class for
global ranges, which will be contributed in the next week or so.
Tested and benchmarked on x86-64 Linux.
gcc/ChangeLog:
* gimple-range-cache.cc (block_range_cache::block_range_cache):
Rename vrange_allocator to obstack_vrange_allocator.
(ssa_global_cache::ssa_global_cache): Same.
* gimple-range-edge.h (class gimple_outgoing_range): Same.
* gimple-range-infer.h (class infer_range_manager): Same.
* value-range.h (class vrange_allocator): Make abstract.
(class obstack_vrange_allocator): Inherit from vrange_allocator.
(class ggc_vrange_allocator): New.
|
|
This fixes a couples places that were using int_range_max, but needed
a generic temporary. Found while merging the frange work.
Also, copying between range temporaries is actually useful :).
Tested on x86-64 Linux.
gcc/ChangeLog:
* gimple-range-cache.cc (ranger_cache::range_from_dom): Use
Value_Range.
* gimple-range.cc (gimple_ranger::register_inferred_ranges): Same.
* value-range.h (Value_Range::Value_Range): Implement copy
constructor for Value_Range.
|
|
The traits struct is no longer needed.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.h (struct vrange_traits): Remove.
(is_a): Rewrite without vrange_traits.
(as_a): Same.
|
|
It's cleaner to have the unsupported_range fully fleshed out, instead
of trapping on every operation. It can also serve as the basis for
the default vrange methods that frange and prange will inherit.
This patch implements most methods, including union and intersect, to
handle an UNDEFINED and a VARYING range.
Since this can serve as the basis for other classes, I have moved
everything into the vrange class, making the unsupported_range
trivial.
Note that vrange is still an abstract class, as I have purposely left
the dump() method abstract.
Also, I have made the unsupported range in the temporary class
(Value_Range) a method field, instead of a static member. This way
the temporary can set UNDEFINED and VARYING as needed.
Tested on x86-64 Linux.
gcc/ChangeLog:
* value-range.cc (vrange::contains_p): Implement.
(vrange::type): Return void.
(vrange::supports_type_p): Implement.
(irange::fits_p): Same.
(vrange::set_undefined): Same.
(irange::set_nonnegative): Same.
(vrange::set_varying): Same.
(vrange::union_): Same.
(unsupported_range::set): Move to vrange.
(unsupported_range::type): Move to vrange.
(vrange::intersect): Implement for varying and undefined.
(vrange::zero_p): Implement.
(unsupported_range::supports_type_p): Move to vrange.
(vrange::nonzero_p): Implement.
(unsupported_range::set_undefined): Move to vrange.
(unsupported_range::set_varying): Same.
(unsupported_range::dump): Same.
(unsupported_range::union_): Same. Implement for varying and
undefined.
(unsupported_range::intersect): Move to vrange.
(unsupported_range::zero_p): Same.
(unsupported_range::nonzero_p): Same.
(unsupported_range::set_nonzero): Same.
(unsupported_range::set_zero): Same.
(unsupported_range::set_nonnegative): Same.
(unsupported_range::fits_p): Same.
* value-range.h (class vrange): Remove abstract markers for most
methods.
(class unsupported_range): Remove most methods as they will now be
inherited from vrange.
|
|
[I have conservatively assumed that both the loop-ch and loop-unswitch
passes, which also use the ranger, only support integers and pointers.
If the goal is to handle other types as well, irange::supports_p()
should be Value_Range::supports_type_p(), and any uses of
int_range_max should be converted to Value_Range. I can help in the
conversion if you'd like.]
As discussed, this patch disambiguates the use of supports_type_p
throughout, as what ranger supports is a totally different question
than what a given range variant (irange, frange, etc) supports.
Unfortunately we need both a static method and a virtual method, and
they can't be named the same. The uses are documented in the vrange
class:
+// To query what types ranger and the entire ecosystem can support,
+// use Value_Range::supports_type_p(tree type). This is a static
+// method available independently of any vrange object.
+//
+// To query what a given vrange variant can support, use:
+// irange::supports_p ()
+// frange::supports_p ()
+// etc
+//
+// To query what a range object can support, use:
+// void foo (vrange &v, irange &i, frange &f)
+// {
+// if (v.supports_type_p (type)) ...
+// if (i.supports_type_p (type)) ...
+// if (f.supports_type_p (type)) ...
+// }
The value_range_equiv::supports_p() method can be use to determine
what legacy VRP supports, as irange::supports_p() will no longer be
applicable in the evrp analyzer code base once irange and prange are
split.
Tested on x86-64 Linux.
gcc/ChangeLog:
* gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for
an object level supports_type_p for irange and a static
Value_Range::supports_type_p.
* gimple-range-fold.cc (fold_using_range::range_of_range_op): Same.
(fold_using_range::range_of_address): Same.
(fold_using_range::range_of_builtin_call): Same.
* gimple-range-fold.h (gimple_range_type): Same.
(gimple_range_ssa_p): Same.
* gimple-range-path.cc (path_range_query::internal_range_of_expr):
Same.
(path_range_query::range_of_stmt): Same.
(path_range_query::add_to_imports): Same.
* gimple-range.cc (gimple_ranger::range_on_edge): Same.
(gimple_ranger::export_global_ranges): Same.
* gimple-ssa-evrp-analyze.cc
(evrp_range_analyzer::record_ranges_from_phis): Same.
* range-op.cc (range_operator::wi_fold): Same.
(range_operator::fold_range): Same.
* tree-ssa-loop-ch.cc (entry_loop_condition_is_static): Same.
* tree-ssa-loop-unswitch.cc (struct unswitch_predicate): Same.
(evaluate_control_stmt_using_entry_checks): Same.
* tree-ssa-threadedge.cc
(hybrid_jt_simplifier::compute_ranges_from_state): Same.
* tree-vrp.cc (supported_types_p): Same.
* value-query.cc (range_query::value_of_expr): Same.
(range_query::value_on_edge): Same.
(range_query::value_of_stmt): Same.
(range_query::get_tree_range): Same.
(get_range_global): Same.
(global_range_query::range_of_expr): Same.
* value-range-equiv.h (class value_range_equiv): Same.
* value-range.cc (irange::supports_type_p): Same.
(unsupported_range::supports_type_p): Same.
* value-range.h (enum value_range_discriminator): Same.
(Value_Range::init): Same.
(Value_Range::supports_type_p): Same.
(irange::supports_type_p): Same.
(irange::supports_p): Same.
(vrange::supports_type_p): Same.
(vrange_allocator::alloc_vrange): Same.
|