Hi Andrew,
>
> all the range-op integer code is in gcc/range-op.cc. As this is a basic
> binary operation, you should be able to get away with implementing a
> single routine, wi_fold () which adds 2 wide int bounds together and
> returns a result. THis si the implelemntaion for operator_plus.
>
> void
> operator_plus::wi_fold (irange &r, tree type,
> const wide_int &lh_lb, const wide_int &lh_ub,
> const wide_int &rh_lb, const wide_int &rh_ub) const
> {
> wi::overflow_type ov_lb, ov_ub;
> signop s = TYPE_SIGN (type);
> wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb);
> wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub);
> value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub);
> }
>
>
> you shouldn't have to do any of the overflow stuff at the end, just take
> the 2 sets of wide int, double their precision to start, add them
> together (it cant possible overflow right) and then return an
> int_range<2> with those bounds...
> ie
>
> void
> operator_plus::wi_fold (irange &r, tree type,
> const wide_int &lh_lb, const wide_int &lh_ub,
> const wide_int &rh_lb, const wide_int &rh_ub) const
> {
> wi::overflow_type ov_lb, ov_ub;
> signop s = TYPE_SIGN (type);
>
> // Do whatever wideint magic is required to do this adds in higher
> precision
> wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb);
> wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub);
>
> r = int_range<2> (type, new_lb, new_ub);
> }
>
So I've been working on adding support for widening plus and widening
multiplication,
and my examples all work now.. but during bootstrap I hit a problem.
Say you have a mixed sign widening multiplication, such as in:
int decMultiplyOp_zacc, decMultiplyOp_iacc;
int *decMultiplyOp_lp;
void decMultiplyOp() {
decMultiplyOp_lp = &decMultiplyOp_zacc;
for (; decMultiplyOp_lp < &decMultiplyOp_zacc + decMultiplyOp_iacc;
decMultiplyOp_lp++)
*decMultiplyOp_lp = 0;
}
Eventually the pointer arithmetic will generate:
intD.7 decMultiplyOp_iacc.2_13;
long unsigned intD.11 _15;
_15 = decMultiplyOp_iacc.2_13 w* 4;
and it'll try to get the range from this.
My implementation is just:
void
operator_widen_mult::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const
{
signop s = TYPE_SIGN (type);
wide_int lh_wlb = wide_int::from (lh_lb, wi::get_precision (lh_lb) * 2, s);
wide_int rh_wlb = wide_int::from (rh_lb, wi::get_precision (rh_lb) * 2, s);
wide_int lh_wub = wide_int::from (lh_ub, wi::get_precision (lh_ub) * 2, s);
wide_int rh_wub = wide_int::from (rh_ub, wi::get_precision (rh_ub) * 2, s);
/* We don't expect a widening multiplication to be able to overflow but range
calculations for multiplications are complicated. After widening the
operands lets call the base class. */
return operator_mult::wi_fold (r, type, lh_wlb, lh_wub, rh_wlb, rh_wub);
}
But in this case the operands are different types and the wi_fold only gets the
type of the operation. The issue is that when increasing the precision for lh_*
I need to sign extend the value and not zero extend, but I don't seem to have
enough context here to know that I do. I'm missing the type of the operands.
For non-widening operations this doesn't matter as the precision stays the same.
Is there a way to get the information I need?
Thanks,
Tamar
>
> The operator needs to be registered, I've attached the skeleton for it.
> you should just have to finish implementing wi_fold().
>
> in theory :-)