On Wed, Jun 12, 2019 at 11:33 PM Aldy Hernandez <al...@redhat.com> wrote: > > On 6/12/19 5:33 AM, Richard Biener wrote: > > On Wed, Jun 12, 2019 at 1:57 AM Martin Sebor <mse...@gmail.com> wrote: > >> > >> On 6/11/19 3:02 PM, Aldy Hernandez wrote: > >>> > >>> > >>> On 6/11/19 12:52 PM, Martin Sebor wrote: > >>>> On 6/11/19 10:26 AM, Aldy Hernandez wrote: > >>>>> > >>>>> > >>>>> On 6/11/19 12:17 PM, Martin Sebor wrote: > >>>>>> On 6/11/19 9:05 AM, Aldy Hernandez wrote: > >>>>>>> > >>>>>>> > >>>>>>> On 6/11/19 9:45 AM, Richard Biener wrote: > >>>>>>>> On Tue, Jun 11, 2019 at 12:40 PM Aldy Hernandez <al...@redhat.com> > >>>>>>>> wrote: > >>>>>>>>> > >>>>>>>>> This patch cleans up the various contains, may_contain, and > >>>>>>>>> value_inside_range variants we have throughout, in favor of one-- > >>>>>>>>> contains_p. There should be no changes in functionality. > >>>>>>>>> > >>>>>>>>> I have added a note to range_includes_zero_p, perhaps as a personal > >>>>>>>>> question than anything else. This function was/is returning true > >>>>>>>>> for > >>>>>>>>> UNDEFINED. From a semantic sense, that doesn't make sense. > >>>>>>>>> UNDEFINED > >>>>>>>>> is really the empty set. Is the functionality wrong, or should > >>>>>>>>> we call > >>>>>>>>> this function something else? Either way, I'm fine removing the > >>>>>>>>> comment > >>>>>>>>> but I'm genuinely curious. > >>>>>>>> > >>>>>>>> So this affects for example this hunk: > >>>>>>>> > >>>>>>>> - if (vr && !range_includes_p (vr, 1)) > >>>>>>>> + if (vr && (!vr->contains_p (build_one_cst (TREE_TYPE (name))) > >>>>>>>> + && !vr->undefined_p ())) > >>>>>>>> { > >>>>>>>> > >>>>>>>> I think it's arbitrary how we compute X in UNDEFINED and I'm fine > >>>>>>>> with changing the affected predicates to return false. This means > >>>>>>>> not testing for !vr->undefined_p here. > >>>>>>> > >>>>>>> Excellent. > >>>>>>> > >>>>>>>> > >>>>>>>> Note I very much dislike the build_one_cst () call here so please > >>>>>>>> provide an overload hiding this. > >>>>>>> > >>>>>>> Good idea. I love it. > >>>>>>> > >>>>>>>> > >>>>>>>> Not sure why you keep range_includes_zero_p. > >>>>>>> > >>>>>>> I wasn't sure if there was some subtle reason why we were including > >>>>>>> undefined. > >>>>>>> > >>>>>>> OK pending tests? > >>>>>> > >>>>>> Should the second overload: > >>>>>> > >>>>>> + bool contains_p (tree) const; > >>>>>> + bool contains_p (int) const; > >>>>>> > >>>>>> take something like HOST_WIDE_INT or even one of those poly_ints > >>>>>> like build_int_cst does? (With the former, contains_p (0) will > >>>>>> likely be ambiguous since 0 is int and HOST_WIDE_INT is long). > >>>>> > >>>>> We have a type, so there should be no confusion: > >>>>> > >>>>> + return contains_p (build_int_cst (type (), val)); > >>>>> > >>>>> (UNDEFINED and VARYING don't have a type, so they are special cased > >>>>> prior). > >>>> > >>>> I didn't mean the overloads are confusing, just that there the one > >>>> that takes an int doesn't make it possible to test whether a value > >>>> outside the range of an int is in the range. For example, in > >>>> the call > >>>> > >>>> contains_p (SIZE_MAX) > >>>> > >>>> the argument will get sliced (and trigger a -Woverflow). One will > >>>> need to go back to the more verbose way of calling it. > >>> > >>> The int version is not really meant to pass anything but simple > >>> constants. For anything fancy, one should really be using the tree > >>> version. But I can certainly change the argument to HOST_WIDE_INT if > >>> preferred. > >>> > >>>> > >>>> Changing the argument type to HOST_WIDE_INT would avoid the slicing > >>>> and warning but then make contains_p (0) ambiguous because 0 isn't > >>>> a perfect match for either void* or long (so it requires a conversion). > >>> > >>> Just a plain 0 will match the int version, instead of the tree version, > >>> right? Nobody should be passing NULL to the tree version, so that seems > >>> like a non-issue. > >> > >> Right, NULL isn't a problem, but I would expect any integer to work > >> (I thought that's what Richard was asking for) So my suggestion was > >> to have contains_p() a poly_int64 and provide just as robust an API > >> as build_int_cst. The argument ends up converted to the poly_int64 > >> anyway when it's passed to the latter. I.e., why not define > >> contains_p simply like this: > >> > >> bool > >> value_range_base::contains_p (poly_int64 val) const > >> { > >> if (varying_p ()) > >> return true; > >> if (undefined_p ()) > >> return false; > >> > >> return contains_p (build_int_cst (type (), val)); > >> } > > > > I agree that plain 'int' is bad. Given we currently store > > INTEGER_CSTs only (and not POLY_INT_CSTs) a > > widest_int argument should be fine. Note widest > > because when interpreted signed all unsigned values > > fit. > > > > The existing contains_p check is also a bit fishy > > for the cases TREE_TYPE of the value has a > > value-range not covered in the value-ranges type... > > I guess it could do > > > > if (!int_fits_type_p (val, this->type ()) > > return false; > > > > but that changes existing behavior which happily > > throws different sign constants into tree_int_cst_lt > > for example... Do we want to allow non-INTEGER_CST > > val arguments at all? That is, you make contains_p > > return a bool and say "yes" when we couldn't really > > decide. This is why previously it was named > > may_contain_p (and we didn't have must_contain_p). > > I think making the result explicitely clear is a must > > since contains_p reads like !contains_p means > > it does _not_ contain. So, either change back the > > name (and provide the must variant) > > or make it return the tri-state from value_inside_range. > > The only reason I added the int overload was because you didn't like the > build_one_cst call. However, if we make it HOST_WIDE_INT or even > widest_int, it will cause a conflict resolution with the tree version. > I think it's best we only provide a tree version, and make due with the > one call to build_one_cst. There is still the range_includes_zero_p() > convenience function that takes care of the common case. > > I see what you mean with the may/must problem. We don't have that > problem in the ranger because we only deal with constants, and there is > never ambiguity. Since we don't have any consumers of must_contain_p > yet, let's leave this bit for later discussion when it's actually needed. > > What I propose then is a general clean up of may_contain_p, making > value_inside_range a member function that deals with the range in THIS. > We can remove value_inside_range, as it's only used from the one > build_on-cst place, and range_includes_zero_p (which I've adjusted > accordingly). > > Note. I've changed existing functionality to so that may_contains_p > (and range_includes_zero_p accordingly) returns FALSE for VR_UNDEFINED. > AFAIU, VR_UNDEFINED is the empty set, so we absolutely know it's not > inside the range. I've tested my patch both with and without this > VR_UNDEFINED changelet, and there are no regressions. > > With this cleanup, particularly with rewriting may_contain_p in terms of > the now value_inside_range method, we can later provide must_contain_p > when needed with just: > > bool > value_range_base::must_contain_p (tree val) const > { > return value_inside_range (val) == 1; > } > > OK?
OK. This is definitely an obvious improvement. As you say we can do more adjustments later. Richard.