On Tue, Oct 1, 2019 at 8:07 PM Jeff Law <l...@redhat.com> wrote: > > On 10/1/19 11:11 AM, Aldy Hernandez wrote: > > Hi folks. > > > > Here is my official submission of the range-ops part of the ranger to > > mainline. > > > > I realize that I could have split this patch up into 2-3 separate ones, > > but I don't want to run into the chicken-and-egg scenario of last time, > > where I had 4 inter-connected patches that were hard to review > > independently. > It might have helped a bit, but it was pretty easy to find the mapping > from bits in wide-int-range.cc into range-op.cc -- the comments were > copied :-) > > > > > A few notes that may help in reviewing. > > > > The range-ops proper is in range-op.*. > > > > The range.* files are separate files containing some simple auxiliary > > functions that will have irange and value_range_base counterparts. Our > > development branch will have #define value_range_base irange, and some > > auxiliary glue, but none of that will be in trunk. As promised, trunk > > is all value_range_base. > > > > * The changes to tree-vrp.* are: > > > > 1. New constructors to align the irange and value_range_base APIs. We > > discussed this a few months ago, and these were the agreed upon changes > > to the API. > Right. > > > > > 2. Extracting the symbolic handling of PLUS/MINUS and POINTER_PLUS_EXPR > > into separate functions (extract_range_from_plus_minus_expr and > > extract_range_from_pointer_plus_expr). > In retrospect we should have broken down that function in the old vrp > code. I suspect that function started out relatively small and just > kept expanding over time into the horrid mess that became. > > THere were a number of places where you ended up pulling code from two > existing locations into a single point in range-ops. But again, it was > just a matter of finding the multiple original source points and mapping > then into their new location in range-ops.cc, using the copied comments > as a guide. > > > > > 3. New range_fold_unary_expr and range_fold_binary_expr functions. These > > are the VRP entry point into range-ops. They normalize symbolics and do > > some minor pre-shuffling before calling range-ops to do the actual range > > operation. > Right. I see these as primarily an adapter between existing code and > the new range ops. > > > > > (I have some minor shuffling of these two functions that I'd like to > > post as separate clean-ups, but I didn't want to pollute this patchset > > with them: Fedora taking forever to test and all.) > Works for me. > > > > 5. Removing the wide-int-range.* files. Most of the code is now > > in-lined into range-op.cc with the exception of > > wide_int_range_set_zero_nonzero_bits which has been moved into tree-vrp.c. > Right. Largely follows from #2 above. > > > > > I think that's all! > > > > For testing this patchset, I left the old extract_*ary_expr_code in, and > > added comparison code that trapped if there were any differences between > > what VRP was getting and what range-ops calculated. I found no > > regressions in either a full bootstrap/tests (all languages), or with a > > full Fedora build. As a bonus, we found quite a few cases where > > range-ops was getting better results. > So to provide a bit more info here. We ran tests back in the spring > which resulted in various bugfixes/improvements. Aldy asked me to > re-run with their more recent branch. That run exposed one very clear > ranger bug which Aldy fixed prior to submitting this patch as well as > several cases where the results differed. We verified each and every > one of them was a case where Ranger was getting better results. > > > (Note: At the last minute, Jeff found one regression in the multi-day > > Fedora build. I will fix this as a follow-up. BTW, it does not cause > > any regressions in a bootstrap or GCC test-run, just a discrepancy on > > one specific corner case between VRP and range-ops.) > Right. WHat happened was there was a package that failed to build due > to the Fortran front-end getting tighter in its handling of argument > checking. Once that (and various other issues related to using a gcc-10 > snapshot) was worked around I rebuilt the failing packages. That in > turn exposed another case where ranger and vrp differed in their results > (it's a MULT+overflow case IIRC) ANyway, I'm leaving it to you to > analyze :-) > > > [ ... ] > > > > > The attached patch is based off of trunk from a few weeks ago. If > > approved, I will merge and re-test again with latest trunk. I won't > > however, test all of Fedora :-P. > Agreed, I don't think that's necessary. FWIW, using a month-old branch > for testing was amazingly helpful in other respects. We found ~100 > packages that need updating for gcc-10 as well as a few bugs unrelated > to Ranger. I've actually got Sunday's snapshot spinning now and fully > expect to be spinning Fedora builds with snapshots for the next several > months. So I don't expect a Fedora build just to test after ranger > integration, but instead that it'll "just happen" on a subsequent snapshot. > > > > > May I be so bold as to suggest that if there are minor suggestions that > > arise from this review, that they be done as follow-ups? I'd like to > > get as much testing as possible in this stage1. > There's a variety of small, obvious things that should be fixed. > Comment typos and the like. There's one question on inversion that may > require some discussion. > > See inline comments... > > > > > > Thanks. > > Aldy > > > > > > range-ops.patch > > > > diff --git a/gcc/ChangeLog b/gcc/ChangeLog > > index 65f9db966d0..9aa46c087b8 100644 > > --- a/gcc/ChangeLog > > +++ b/gcc/ChangeLog > > @@ -1,3 +1,68 @@ > > +2019-09-25 Aldy Hernandez <al...@redhat.com> > > + > > + * Makefile.in (OBJS): Add range.o and range-op.o. > > + Remove wide-int-range.o. > > + (GTFILES): Add range.h. > > + * function-tests.c (test_ranges): New. > > + (function_tests_c_tests): Call test_ranges. > > + * ipa-cp.c (ipa_vr_operation_and_type_effects): Call > > + range_fold_unary_expr instead of extract_range_from_unary_expr. > > + * ipa-prop.c (ipa_compute_jump_functions_for_edge): Same. > > + * range-op.cc: New file. > > + * range-op.h: New file. > > + * range.cc: New file. > > + * range.h: New file. > > + * selftest.h (range_tests): New prototype. > > + * ssa.h: Include range.h. > > + * tree-vrp.c (value_range_base::value_range_base): New > > + constructors. > > + (value_range_base::singleton_p): Do not call > > + ranges_from_anti_range until sure we will need to. > > + (value_range_base::type): Rename gcc_assert to > > + gcc_checking_assert. > > + (vrp_val_is_max): New argument. > > + (vrp_val_is_min): Same. > > + (wide_int_range_set_zero_nonzero_bits): Move from > > + wide-int-range.cc. > > + (extract_range_into_wide_ints): Remove. > > + (extract_range_from_multiplicative_op): Remove. > > + (extract_range_from_pointer_plus_expr): Abstract POINTER_PLUS code > > + from extract_range_from_binary_expr. > > + (extract_range_from_plus_minus_expr): Abstract PLUS/MINUS code > > + from extract_range_from_binary_expr. > > + (extract_range_from_binary_expr): Remove. > > + (normalize_for_range_ops): New. > > + (range_fold_binary_expr): New. > > + (range_fold_unary_expr): New. > > + (value_range_base::num_pairs): New. > > + (value_range_base::lower_bound): New. > > + (value_range_base::upper_bound): New. > > + (value_range_base::upper_bound): New. > > + (value_range_base::contains_p): New. > > + (value_range_base::invert): New. > > + (value_range_base::union_): New. > > + (value_range_base::intersect): New. > > + (range_compatible_p): New. > > + (value_range_base::operator==): New. > > + (determine_value_range_1): Call range_fold_*expr instead of > > + extract_range_from_*expr. > > + * tree-vrp.h (class value_range_base): Add new constructors. > > + Add methods for union_, intersect, operator==, contains_p, > > + num_pairs, lower_bound, upper_bound, invert. > > + (vrp_val_is_min): Add handle_pointers argument. > > + (vrp_val_is_max): Same. > > + (extract_range_from_unary_expr): Remove. > > + (extract_range_from_binary_expr): Remove. > > + (range_fold_unary_expr): New. > > + (range_fold_binary_expr): New. > > + * vr-values.c (vr_values::extract_range_from_binary_expr): Call > > + range_fold_binary_expr instead of extract_range_from_binary_expr. > > + (vr_values::extract_range_basic): Same. > > + (vr_values::extract_range_from_unary_expr): Call > > + range_fold_unary_expr instead of extract_range_from_unary_expr. > > + * wide-int-range.cc: Remove. > > + * wide-int-range.h: Remove. > > + > > 2019-08-27 Richard Biener <rguent...@suse.de> > > > > * config/i386/i386-features.h > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > > index 597dc01328b..d9549710d8e 100644 > > --- a/gcc/Makefile.in > > +++ b/gcc/Makefile.in > [ ... ] > > @@ -2548,6 +2549,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h > > $(srcdir)/coretypes.h \ > > $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \ > > $(srcdir)/gimple.h \ > > $(srcdir)/gimple-ssa.h \ > > + $(srcdir)/range.h $(srcdir)/range.cc \ > > $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c > > $(srcdir)/tree-ssa-address.c \ > > $(srcdir)/tree-cfg.c $(srcdir)/tree-ssa-loop-ivopts.c \ > > $(srcdir)/tree-dfa.c \ > I didn't see any GTY thingies in range.h/range.cc, so I don't think this > is strictly necessary. BUt I'm not going to stress if you leave it in. > > > diff --git a/gcc/range-op.cc b/gcc/range-op.cc > > new file mode 100644 > > index 00000000000..a21520df355 > > --- /dev/null > > +++ b/gcc/range-op.cc > [ ... ] > > + > > +// Return a value_range_base instance that is a boolean FALSE. > > + > > +static inline value_range_base > > +range_true_and_false (tree type) > > +{ > > + unsigned prec = TYPE_PRECISION (type); > > + return value_range_base (type, wi::zero (prec), wi::one (prec)); > > +} > I think the function comment is wrong. We're creating a range with both > true and false values. Effectively a BRS_FULL range I believe. > > > +// Return the summary information about boolean range LHS. Return an > > +// "interesting" range in R. For EMPTY or FULL, return the equivilent > > +// range for TYPE, for BRS_TRUE and BRS false, return the negation of > > +// the bool range. > s/equivilent/equivalent/ > > > + > > +static bool_range_state > > +get_bool_state (value_range_base &r, > > + const value_range_base &lhs, tree val_type) > > +{ > > + // If there is no result, then this is unexectuable. > s/unexectuable/unexecutable/ > > [ ... ] > > > > +bool > > +operator_equal::op1_range (value_range_base &r, tree type, > > + const value_range_base &lhs, > > + const value_range_base &op2) const > > +{ > > + switch (get_bool_state (r, lhs, type)) > > + { > > + case BRS_FALSE: > > + // If the result is false, the only time we know anything is > > + // if OP2 is a constant. > > + if (wi::eq_p (op2.lower_bound(), op2.upper_bound())) > > + r = range_invert (op2); > > + else > > + r.set_varying (type); > > + break; > Looks like you've got spaces vs tabs wrong above. It repeats in other > BRS_FALSE cases. I suspect some global search/replace is the right > thing to do here. > > [ ... ] > + > > +value_range_base > > +operator_lt::fold_range (tree type, > > + const value_range_base &op1, > > + const value_range_base &op2) const > > +{ > > + value_range_base r; > > + if (empty_range_check (r, op1, op2)) > > + return r; > > + > > + signop sign = TYPE_SIGN (op1.type ()); > > + gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); > > + > > + if (wi::lt_p (op1.upper_bound (), op2.lower_bound (), sign)) > > + r = range_true (type); > > + else > > + if (!wi::lt_p (op1.lower_bound (), op2.upper_bound (), sign)) > > + r = range_false (type); > > + else > > + r = range_true_and_false (type); > > + return r; > > +} > So formatting goof here. It should be > > if (...) > blah > else if (...) > blah2 > else > blah3 > > This repeats in other operator_XX member functions. > > [ ... ] > > > + > > > +value_range_base > > +operator_lshift::wi_fold (tree type, > > + const wide_int &lh_lb, const wide_int &lh_ub, > > + const wide_int &rh_lb, const wide_int &rh_ub) const > > +{ > [ ... ] > > > + { > > + // For non-negative numbers, we're shifting out only zeroes, > > + // the value increases monotonically. For negative numbers, > > + // we're shifting out only ones, the value decreases > > + // monotomically. > s/monotomically/monotonically/ > > > > + > > +bool > > +operator_cast::op1_range (value_range_base &r, tree type, > > + const value_range_base &lhs, > > + const value_range_base &op2) const > > +{ > [ ... ] > > > > + // If the LHS precision is greater than the rhs precision, the LHS > > + // range is resticted to the range of the RHS by this > > + // assignment. > s/resticted/restricted/ > > > > > diff --git a/gcc/range.cc b/gcc/range.cc > > new file mode 100644 > > index 00000000000..5e4d90436f2 > > --- /dev/null > > +++ b/gcc/range.cc > [ ... ] > > + > > +value_range_base > > +range_intersect (const value_range_base &r1, const value_range_base &r2) > > +{ > > + value_range_base tmp (r1); > > + tmp.intersect (r2); > > + return tmp; > > +} > So low level question here. This code looks particularly well suited > for the NRV optimization. Can you check if NVR (named-value-return) is > triggering here, and if not why. ISTM these are likely used heavily and > NVR would be a win. > > > > diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c > > index 5ec4d17f23b..269a3cb090e 100644 > > --- a/gcc/tree-vrp.c > > +++ b/gcc/tree-vrp.c > [ ... ] > > > @@ -67,7 +67,7 @@ along with GCC; see the file COPYING3. If not see > > > + > > +/* Return the inverse of a range. */ > > + > > +void > > +value_range_base::invert () > > +{ > > + if (undefined_p ()) > > + return; > > + if (varying_p ()) > > + set_undefined (); > > + else if (m_kind == VR_RANGE) > > + m_kind = VR_ANTI_RANGE; > > + else if (m_kind == VR_ANTI_RANGE) > > + m_kind = VR_RANGE; > > + else > > + gcc_unreachable (); > > +} > I don't think this is right for varying_p. ISTM that if something is > VR_VARYING that inverting it is still VR_VARYING. VR_UNDEFINED seems > particularly bad given its optimistic treatment elsewhere.
VR_VARYING isn't a range, it's a lattice state (likewise for VR_UNDEFINED). It doesn't make sense to invert a lattice state. How you treat VR_VARYING/VR_UNDEFINED depends on context and so depends what 'invert' would do. I suggest to assert that varying/undefined is never inverted. Richard. > > So there's a handful of nits in there. The only functional concern I > have is value_range_base::invert. > > jeff