On Mon, 27 Feb 2023, Aldy Hernandez wrote: > > > On 2/27/23 14:58, Richard Biener wrote: > > After fixing PR107561 the following avoids looking at VR_ANTI_RANGE > > ranges where it doesn't seem obvious the code does the correct > > thing here (lower_bound and upper_bound do not work as expected). > > I do realize there's some confusion here, and some of it is my fault. This has > become obvious in my upcoming work removing all of legacy. > > What's going on is that ultimately min/max are broken with (non-legacy) > iranges. Or at the very least inconsistent between legacy and non-legacy. > These are left over from the legacy world, and have been marked DEPRECATED for > a few releases, but the middle end warnings continued to use them and even > added new uses after they were obsoleted. > > min/max have different meanings depending on kind(), which is also deprecated, > btw. They are the underlying min/max fields from the legacy implementation, > and thus somewhat leak the implementation details. Unfortunately, they are > being called from non-legacy code which is ignoring the kind() field. > > In retrospect I should've converted everything away from min/max/kind years > ago, or at the very least converted min/max to work with non-legacy more > consistently. > > For the record: > > enum value_range_kind kind () const; // DEPRECATED > tree min () const; // DEPRECATED > tree max () const; // DEPRECATED > bool symbolic_p () const; // DEPRECATED > bool constant_p () const; // DEPRECATED > void normalize_symbolics (); // DEPRECATED > void normalize_addresses (); // DEPRECATED > bool may_contain_p (tree) const; // DEPRECATED > bool legacy_verbose_union_ (const class irange *); // DEPRECATED > bool legacy_verbose_intersect (const irange *); // DEPRECATED > > In my local branch I tried converting all the middle-end legacy API uses to > the new API, but a bunch of tests started failing, and lots more false > positives started showing up in correct code. I suspect that's part of the > reason legacy continued to be used in these passes :-/. As you point out in > the PR, the tests seem designed to test the current (at times broken) > implementation. > > That being said, the 5 fixes in your patch are not wrong to begin with, > because all uses guard lower_bound() and upper_bound() which work correctly. > They return the lowest and uppermost possible bound for the range (ignoring > the underlying implementation). So, the lower bound of a signed non-zero is > -INF because ~[0,0] is really [-INF,-1][1,+INF]. In the min/max legacy code, > min() of signed non-zero (~[0,0]) is 0. The new implementation has no concept > of anti-ranges, and we don't leak any of that out. > > Any uses of min/max without looking at kind() are definitely broken. OTOH uses > of lower/upper_bound are fine and should work with both legacy and non-legacy. > > Unrelated, but one place where I haven't been able to convince myself that the > use is correct is bounds_of_var_in_loop: > > > /* Check if init + nit * step overflows. Though we checked > > scev {init, step}_loop doesn't wrap, it is not enough > > because the loop may exit immediately. Overflow could > > happen in the plus expression in this case. */ > > if ((dir == EV_DIR_DECREASES > > && compare_values (maxvr.min (), initvr.min ()) != -1) > > || (dir == EV_DIR_GROWS > > && compare_values (maxvr.max (), initvr.max ()) != 1)) > > Ughh...this is all slated to go away, and I have patches removing all of > legacy and the old API. > > Does this help? Do you still think lower and upper bound are not working as > expected?
lower_bound/upper_bound work as expected, tree_lower_bound/tree_upper_bound do not. I've checked and all uses I "fixed" use lower_bound/upper_boud. tree_lower_bound & friends are 'protected', but in the above light the comment // potential promotion to public? looks dangerous (I was considering using them ...). I'm dropping the patch, it's probably time to work on getting rid of 'value_range' uses (aka legacy_mode_p ()) and/or replace raw accesses to the min/max for that mode with m_base accesses? At least that there's tree_{upper,lower}_bound for pair != 0 suggests this function is used with differing semantics internally which is a source of confusion (to me at least). tree_{lower,upper}_bound should be able to assert it's not a legacy mode range and min/max should be able to assert that it is. Btw, legacy_upper_bound looks wrong: if (m_kind == VR_ANTI_RANGE) { tree typ = type (), t; if (pair == 1 || vrp_val_is_min (min ())) t = vrp_val_max (typ); else t = wide_int_to_tree (typ, wi::to_wide (min ()) - 1); not sure what the pair == 1 case is about, but the upper bound of an anti-range is only special when max() is vrp_val_is_max, aka ~[low, +INF] where it then is low - 1, but the above checks for ~[-INF, high] and returns +INF in that case. That's correct unless high == +INF at least, but the else case is wrong for all high != +INF? I think it should be if (pair == 1 || !vrp_val_is_max (max ())) t = vrp_val_max (typ); else t = wide_int_to_tree (typ, wi::to_wide (min ()) - 1); no? The pair == 1 case is a mystery to me - I suppose we consider the non-existing range to be empty? Richard. > Aldy > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu. > > > > OK? > > > > Thanks, > > Richard. > > > > * gimple-ssa-sprintf.cc (get_int_range): Avoid VR_ANTI_RANGE > > by using range_int_cst_p. > > (format_integer): Likewise. > > (handle_printf_call): Guard against VR_ANTI_RANGE. > > * graphite-sese-to-poly.cc (add_param_constraints): Likewise. > > * tree-ssa-strlen.cc (set_strlen_range): Likewise. > > --- > > gcc/gimple-ssa-sprintf.cc | 6 +++--- > > gcc/graphite-sese-to-poly.cc | 2 +- > > gcc/tree-ssa-strlen.cc | 2 +- > > 3 files changed, 5 insertions(+), 5 deletions(-) > > > > diff --git a/gcc/gimple-ssa-sprintf.cc b/gcc/gimple-ssa-sprintf.cc > > index 18975708d2c..61974072f62 100644 > > --- a/gcc/gimple-ssa-sprintf.cc > > +++ b/gcc/gimple-ssa-sprintf.cc > > @@ -1082,7 +1082,7 @@ get_int_range (tree arg, gimple *stmt, > > value_range vr; > > query->range_of_expr (vr, arg, stmt); > > - if (!vr.undefined_p () && !vr.varying_p ()) > > + if (range_int_cst_p (&vr)) > > { > > HOST_WIDE_INT type_min > > = (TYPE_UNSIGNED (argtype) > > @@ -1391,7 +1391,7 @@ format_integer (const directive &dir, tree arg, > > pointer_query &ptr_qry) > > value_range vr; > > ptr_qry.rvals->range_of_expr (vr, arg, dir.info->callstmt); > > - if (!vr.varying_p () && !vr.undefined_p ()) > > + if (range_int_cst_p (&vr)) > > { > > argmin = wide_int_to_tree (TREE_TYPE (arg), vr.lower_bound ()); > > argmax = wide_int_to_tree (TREE_TYPE (arg), vr.upper_bound ()); > > @@ -4623,7 +4623,7 @@ handle_printf_call (gimple_stmt_iterator *gsi, > > pointer_query &ptr_qry) > > value_range vr; > > ptr_qry.rvals->range_of_expr (vr, size, info.callstmt); > > - if (!vr.undefined_p ()) > > + if (!vr.undefined_p () && vr.kind () != VR_ANTI_RANGE) > > { > > tree type = TREE_TYPE (size); > > tree tmin = wide_int_to_tree (type, vr.lower_bound ()); > > diff --git a/gcc/graphite-sese-to-poly.cc b/gcc/graphite-sese-to-poly.cc > > index fbe7667380a..b89262640ac 100644 > > --- a/gcc/graphite-sese-to-poly.cc > > +++ b/gcc/graphite-sese-to-poly.cc > > @@ -426,7 +426,7 @@ add_param_constraints (scop_p scop, graphite_dim_t p, > > tree parameter) > > > > if (INTEGRAL_TYPE_P (type) > > && get_range_query (cfun)->range_of_expr (r, parameter) > > - && !r.undefined_p ()) > > + && range_int_cst_p (&r)) > > { > > min = r.lower_bound (); > > max = r.upper_bound (); > > diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc > > index 7508c1768a5..e1230522564 100644 > > --- a/gcc/tree-ssa-strlen.cc > > +++ b/gcc/tree-ssa-strlen.cc > > @@ -1936,7 +1936,7 @@ set_strlen_range (tree lhs, wide_int min, wide_int > > max, > > { > > value_range r; > > get_range_query (cfun)->range_of_expr (r, bound); > > - if (!r.undefined_p ()) > > + if (range_int_cst_p (&r)) > > { > > /* For a bound in a known range, adjust the range determined > > above as necessary. For a bound in some anti-range or > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman; HRB 36809 (AG Nuernberg)