On Mon, Sep 3, 2018 at 8:58 AM Aldy Hernandez <al...@redhat.com> wrote: > >
Can you re-base and re-post please? Sorry for being late here. Richard. > > -------- Forwarded Message -------- > Subject: Re: lightweight class to wide int ranges in VRP and friends > Date: Fri, 24 Aug 2018 13:40:29 -0400 > From: Aldy Hernandez <al...@redhat.com> > To: Richard Biener <richard.guent...@gmail.com> > CC: GCC Patches <gcc-patches@gcc.gnu.org> > > On 08/24/2018 06:32 AM, Richard Biener wrote: > > On Wed, Aug 15, 2018 at 7:31 PM Aldy Hernandez <al...@redhat.com> wrote: > >> > >> I kept seeing the same patterns over and over in all this re-factoring: > >> > >> 1. extract value_range constants into pairs of wide ints > >> > >> 2. mimic symbolics as [-MIN, +MAX] (most of the time :)) > >> > >> 3. perform some wide int operation on the wide int range > >> > >> 4. convert back to a value range > >> > >> So I've decided to clean this up even more. Instead of passing a pair > >> of wide ints plus sign, precision, and god knows what to every > >> wide_int_range_* function, I've implemented a lighweight class > >> (wi_range) for a pair of wide ints. It is not meant for long term > >> storage, but even so its footprint is minimal. > >> > >> The only extra bits are another 64-bit word per pair for keeping > >> attributes such as precision, sign, overflow_wraps, and a few other > >> things we'll need shortly. In reality we only need one set of > >> attributes for both sets of pairs, so we waste one 64-bit word. I don't > >> care. They're short lived, and the resulting code looks an awful lot > >> nicer. For example, the shift code gets rewritten from this: > >> > >> if (range_int_cst_p (&vr1) > >> && !vrp_shift_undefined_p (vr1, prec)) > >> { > >> if (code == RSHIFT_EXPR) > >> { > >> if (vr0.type != VR_RANGE || symbolic_range_p (&vr0)) > >> { > >> vr0.type = type = VR_RANGE; > >> vr0.min = vrp_val_min (expr_type); > >> vr0.max = vrp_val_max (expr_type); > >> } > >> extract_range_from_multiplicative_op (vr, code, &vr0, &vr1); > >> return; > >> } > >> else if (code == LSHIFT_EXPR > >> && range_int_cst_p (&vr0)) > >> { > >> wide_int res_lb, res_ub; > >> if (wide_int_range_lshift (res_lb, res_ub, sign, prec, > >> wi::to_wide (vr0.min), > >> wi::to_wide (vr0.max), > >> wi::to_wide (vr1.min), > >> wi::to_wide (vr1.max), > >> TYPE_OVERFLOW_UNDEFINED > >> (expr_type), > >> TYPE_OVERFLOW_WRAPS (expr_type))) > >> { > >> min = wide_int_to_tree (expr_type, res_lb); > >> max = wide_int_to_tree (expr_type, res_ub); > >> set_and_canonicalize_value_range (vr, VR_RANGE, > >> min, max, NULL); > >> return; > >> } > >> } > >> } > >> set_value_range_to_varying (vr); > >> > >> into this: > >> > >> wi_range w0 (&vr0, expr_type); > >> wi_range w1 (&vr1, expr_type); > >> if (!range_int_cst_p (&vr1) > >> || wi_range_shift_undefined_p (w1) > >> || (code == LSHIFT_EXPR > >> && !range_int_cst_p (&vr0))) > >> { > >> vr->set_varying (); > >> return; > >> } > >> bool success; > >> if (code == RSHIFT_EXPR) > >> success = wi_range_multiplicative_op (res, code, w0, w1); > >> else > >> success = wi_range_lshift (res, w0, w1); > >> > >> if (success) > >> vr->set_and_canonicalize (res, expr_type); > >> else > >> vr->set_varying (); > >> return; > > > > not sure whether I like the munging of lshift and right shift (what exactly > > gets > > done is less clear in your version ...). Having a light-weigth class for > > the wi_range_ parameters is nice though. > > No worries. I'm not emotionally attached to munging them :). > > > > >> I also munged together the maybe/mustbe nonzero_bits into one structure. > >> > >> Finally, I've pontificated that wide_int_range_blah is too much typing. > >> Everyone's RSI will thank me for rewriting the methods as wi_range_blah. > >> > >> I've tried to keep the functionality changes to a minimum. However, > >> there are some slight changes where I treat symbolics and VR_VARYING as > >> [MIN, MAX] and let the constant code do its thing. It is considerably > >> easier to read. > >> > >> I am finally happy with the overall direction of this. If this and the > >> last one are acceptable, I think I only need to clean MIN/MAX_EXPR and > >> ABS_EXPR and I'm basically done with what I need going forward. > >> > >> Phew... > >> > >> How does this look? > > > > +struct wi_range > > +{ > > + wide_int min; > > + wide_int max; > > + /* This structure takes one additional 64-bit word apart from the > > + min/max bounds above. It is laid out so that PRECISION and SIGN > > + can be accessed without any bit twiddling, since they're the most > > + commonly accessed fields. */ > > + unsigned short precision; > > + bool empty_p:1; > > + bool pointer_type_p:1; > > + bool overflow_wraps:1; > > + bool overflow_undefined:1; > > + signop sign; > > > > isn't precision already available in min.get_precision () which is > > required to be equal to max.get_precision ()? > > Indeed. Good point. > > > > > + wi_range () { empty_p = false; } > > > > true I suppose? Better not allow default construction? > > OK. > > > > > empty_p doesn't seem to be documented, nor is pointer_type_p > > or why that is necessary - maybe simply store a tree type > > instead all of the bits? > > I was trying to avoid dereferencing another pointer by perhaps > flattening out the needed bits, but again-- not emotionally attached. > Easier for me... > > > > > +/* A structure to pass maybe and mustbe nonzero bitmasks. This is for > > + use in wi_range_set_zero_nonzero_bits and friends. */ > > + > > +struct maybe_nonzero_bits > > +{ > > + /* If some bit is unset, it means that for all numbers in the range > > + the bit is 0, otherwise it might be 0 or 1. */ > > + wide_int may_be; > > + > > + /* If some bit is set, it means that for all numbers in the range > > + the bit is 1, otherwise it might be 0 or 1. */ > > + wide_int must_be; > > }; > > > > eh - multiple changes in one patch ... > > Well, is it? I'm trying to avoid passing tons of things to the > wide_int_range_* functions, and that includes wide ints and the nonzero > bit pairs. Could I please leave these in the patch? > > > > > @@ -52,6 +54,58 @@ struct GTY((for_user)) value_range > > > > /* Dump value range to stderr. */ > > void dump (); > > + > > + void set (const wi_range &r, tree type); > > + void set_and_canonicalize (const wi_range &r, tree type); > > + void set_undefined (); > > + void set_varying (); > > +}; > > > > likewise ... you introduce those methods but not use them consistently. > > Please leave out this change (I would object to this kind of change > > if carried out through). > > I was really avoiding having to convert every caller. But really, why > would you object even if carried out through? > > > > > +/* Construct a new range from the contents of a value_range. Varying > > + or symbolic ranges are normalized to the entire possible range. */ > > + > > +inline > > +wi_range::wi_range (value_range *vr, tree type) > > +{ > > + precision = TYPE_PRECISION (type); > > + pointer_type_p = POINTER_TYPE_P (type); > > + overflow_wraps = TYPE_OVERFLOW_WRAPS (type); > > + overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type); > > + sign = TYPE_SIGN (type); > > + empty_p = false; > > + if (vr->type == VR_VARYING || symbolic_range_p (vr)) > > + { > > + min = wi::min_value (precision, sign); > > + max = wi::max_value (precision, sign); > > + } > > + else if (vr->type == VR_RANGE) > > + { > > + min = wi::to_wide (vr->min); > > + max = wi::to_wide (vr->max); > > + } > > + else > > + gcc_unreachable (); > > +} > > > > What about VR_ANTI_RANGE? Note the above doesn't exactly look > > "light-weight". > > Yes, I should handle anti range, or ICE or something, considering the > pain it was to find the anti range problem with the POINTER_PLUS_EXPR > code recently. > > Is "not exactly light-weight" an objection, or just a btw type of > comment :)? Would it make it less painful if we stored the entire type > in the wi_range as mentioned earlier? > > > > > -/* Calculate TRUNC_MOD_EXPR on two ranges and store the result in > > - [WMIN,WMAX]. */ > > +/* Calculate TRUNC_MOD_EXPR on two ranges and store the result in RES. > > + Return TRUE if operation succeeded. */ > > > > did I say multiple changes...? I think this isn't a good one given > > "succeed" > > doesn't imply that if not the result is UNDEFINED ... > > Point taken, but hey I can't read your responses as you're typing them ;-). > > > > > As said above the shift handlign structrue is now unreadable :/ Given we do > > different things for lshift vs. rshift it makes sense to simply split > > Unreadable? Surely you jest! As opposed to the super-readable stuff in > VRP before? Come on! But I can split the shifts. That's not a problem :). > > > > > else if (code == RSHIFT_EXPR > > || code == LSHIFT_EXPR) > > { > > > > even if that means duplicating a few lines. > > > > Just to remind you review (and approval) isn't easier if you put unrelated > > stuff > > into a patch ;) > > If you mention it three times in a review and I apologize three times, > are we at peace now? :-P > > Aldy