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