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