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 :-)

Reply via email to