Aldy Hernandez <al...@redhat.com> writes: > On 07/11/2018 08:52 AM, Richard Biener wrote: >> On Wed, Jul 11, 2018 at 8:48 AM Aldy Hernandez <al...@redhat.com> wrote: >>> >>> Hmmm, I think we can do better, and since this hasn't been reviewed yet, >>> I don't think anyone will mind the adjustment to the patch ;-). >>> >>> I really hate int_const_binop_SOME_RANDOM_NUMBER. We should abstract >>> them into properly named poly_int_binop, wide_int_binop, and tree_binop, >>> and then use a default argument for int_const_binop() to get things going. >>> >>> Sorry for more changes in flight, but I thought we could benefit from >>> more cleanups :). >>> >>> OK for trunk pending tests? >> >> Much of GCC pre-dates function overloading / default args ;) > > Heh...and ANSI C. > >> >> Looks OK but can you please rename your tree_binop to int_cst_binop? >> Or maybe inline it into int_const_binop, also sharing the force_fit_type () >> tail with poly_int_binop? > > I tried both, but inlining looked cleaner :). Done. > >> >> What about mixed INTEGER_CST / poly_int constants? Shouldn't it >> be >> >> if (neither-poly-nor-integer-cst (arg1 || arg2)) >> return NULL_TREE; >> if (poly_int_tree (arg1) || poly_int_tree (arg2)) >> poly-int-stuff >> else if (INTEGER_CST && INTEGER_CST) >> wide-int-stuff >> >> ? I see that is a pre-existing issue but if you are at refactoring... >> wi::to_poly_wide should handle INTEGER_CST operands just fine >> I hope. > > This aborted: > gcc_assert (NUM_POLY_INT_COEFFS != 1); > > but even taking it out made the bootstrap die somewhere else. > > If it's ok, I'd rather not tackle this now, as I have some more cleanups > that are pending on this. If you feel strongly, I could do it at a > later time. > > OK pending tests?
LGTM FWIW, just some nits: > -/* Subroutine of int_const_binop_1 that handles two INTEGER_CSTs. */ > +/* Combine two wide ints ARG1 and ARG2 under operation CODE to produce > + a new constant in RES. Return FALSE if we don't know how to > + evaluate CODE at compile-time. */ > > -static tree > -int_const_binop_2 (enum tree_code code, const_tree parg1, const_tree parg2, > - int overflowable) > +bool > +wide_int_binop (enum tree_code code, > + wide_int &res, const wide_int &arg1, const wide_int &arg2, > + signop sign, wi::overflow_type &overflow) > { IMO we should avoid pass-back by reference like the plague. :-) It's especially confusing when the code does things like: case FLOOR_DIV_EXPR: if (arg2 == 0) return false; res = wi::div_floor (arg1, arg2, sign, &overflow); break; It looked at first like it was taking the address of a local variable and failing to propagate the information back up. I think we should stick to using pointers for this kind of thing. > -/* Combine two integer constants PARG1 and PARG2 under operation CODE > - to produce a new constant. Return NULL_TREE if we don't know how > +/* Combine two poly int's ARG1 and ARG2 under operation CODE to > + produce a new constant in RES. Return FALSE if we don't know how > to evaluate CODE at compile-time. */ > > -static tree > -int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree arg2, > - int overflowable) > +static bool > +poly_int_binop (poly_wide_int &res, enum tree_code code, > + const_tree arg1, const_tree arg2, > + signop sign, wi::overflow_type &overflow) > { Would be good to be consistent about the order of the result and code arguments. Here it's "result, code" (which seems better IMO), but in wide_int_binop it's "code, result". > +/* Combine two integer constants PARG1 and PARG2 under operation CODE > + to produce a new constant. Return NULL_TREE if we don't know how > + to evaluate CODE at compile-time. */ > + > tree > -int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2) > +int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2, > + int overflowable) s/PARG/ARG/g in comment. > { > - return int_const_binop_1 (code, arg1, arg2, 1); > + bool success = false; > + poly_wide_int poly_res; > + tree type = TREE_TYPE (arg1); > + signop sign = TYPE_SIGN (type); > + wi::overflow_type overflow = wi::OVF_NONE; > + > + if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST) > + { > + wide_int warg1 = wi::to_wide (arg1), res; > + wide_int warg2 = wi::to_wide (arg2, TYPE_PRECISION (type)); > + success = wide_int_binop (code, res, warg1, warg2, sign, overflow); > + poly_res = res; > + } > + else if (poly_int_tree_p (arg1) && poly_int_tree_p (arg2)) > + success = poly_int_binop (poly_res, code, arg1, arg2, sign, overflow); > + if (success) > + return force_fit_type (type, poly_res, overflowable, > + (((sign == SIGNED || overflowable == -1) > + && overflow) > + | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))); > + return NULL_TREE; > } > > /* Return true if binary operation OP distributes over addition in operand > @@ -1925,7 +1930,7 @@ size_binop_loc (location_t loc, enum tree_code code, > tree arg0, tree arg1) > /* Handle general case of two integer constants. For sizetype > constant calculations we always want to know about overflow, > even in the unsigned case. */ > - tree res = int_const_binop_1 (code, arg0, arg1, -1); > + tree res = int_const_binop (code, arg0, arg1, -1); > if (res != NULL_TREE) > return res; > } > diff --git a/gcc/fold-const.h b/gcc/fold-const.h > index 4613a62e1f6..b921ba86854 100644 > --- a/gcc/fold-const.h > +++ b/gcc/fold-const.h > @@ -100,7 +100,10 @@ extern tree fold_bit_and_mask (tree, tree, enum > tree_code, > tree, enum tree_code, tree, tree, > tree, enum tree_code, tree, tree, tree *); > extern tree fold_read_from_constant_string (tree); > -extern tree int_const_binop (enum tree_code, const_tree, const_tree); > +extern bool wide_int_binop (enum tree_code, wide_int &res, > + const wide_int &arg1, const wide_int &arg2, > + signop, wi::overflow_type &); > +extern tree int_const_binop (enum tree_code, const_tree, const_tree, int = > 1); > #define build_fold_addr_expr(T)\ > build_fold_addr_expr_loc (UNKNOWN_LOCATION, (T)) > extern tree build_fold_addr_expr_loc (location_t, tree); > diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c > index a7453abba7f..7764f7b30b6 100644 > --- a/gcc/tree-vrp.c > +++ b/gcc/tree-vrp.c > @@ -956,11 +956,13 @@ value_range_constant_singleton (value_range *vr) > return NULL_TREE; > } > > -/* Wrapper around int_const_binop. Return true if we can compute the > - result; i.e. if the operation doesn't overflow or if the overflow is > - undefined. In the latter case (if the operation overflows and > - overflow is undefined), then adjust the result to be -INF or +INF > - depending on CODE, VAL1 and VAL2. Return the value in *RES. > +/* Wrapper around wide_int_binop that adjusts for overflow. > + > + Return true if we can compute the result; i.e. if the operation > + doesn't overflow or if the overflow is undefined. In the latter > + case (if the operation overflows and overflow is undefined), then > + adjust the result to be -INF or +INF depending on CODE, VAL1 and > + VAL2. Return the value in *RES. > > Return false for division by zero, for which the result is > indeterminate. */ > @@ -970,78 +972,36 @@ vrp_int_const_binop (enum tree_code code, tree val1, > tree val2, wide_int *res) > { > wi::overflow_type overflow = wi::OVF_NONE; > signop sign = TYPE_SIGN (TREE_TYPE (val1)); > + wide_int w1 = wi::to_wide (val1); > + wide_int w2 = wi::to_wide (val2); > This doesn't come for free. Until we can use "auto", it might be better to keep the wi::to_wide calls at the point they're used. That probably maans having a separate call to wide_int_binop for shifts. Thanks, Richard