lightweight class to wide int ranges in VRP and friends

Aldy Hernandez aldyh@redhat.com
Wed Aug 15 17:32:00 GMT 2018


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;

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?

Aldy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: curr.patch
Type: text/x-patch
Size: 47218 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/gcc-patches/attachments/20180815/3f6ffe89/attachment.bin>


More information about the Gcc-patches mailing list