On Thu, Jul 12, 2018 at 10:12 AM Aldy Hernandez <al...@redhat.com> wrote: > > On 07/11/2018 01:33 PM, Richard Sandiford wrote: > > 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. > > > > Hmmm, I kinda like them. It just takes some getting used to, but > generally yields cleaner code as you don't have to keep using '*' > everywhere. Plus, the callee can assume the pointer is non-zero. > > >> -/* 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". > > Agreed. Fixed. > > > > >> +/* 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. > > Fixed. > > > > >> { > >> - 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. > > I would prefer cleaner rather than saving a few microseconds or bytes, > unless it's in the critical path. This particular code doesn't seem to > be ??.
So besides the general discussion about references/pointers for out parameters let's stay consistet within related APIs. This means wide_int_binop should have a wide_int wide_int_binop (enum tree_code, const wide_int &, const wide_int &, signop, wi::overflow_type *) signature. Notice how I elided the out wide_int parameter to be the return value which means the function isn't supposed to fail which means gcc_unreachable () for "unhandled" tree codes. It's more like an exceptional state anyway. The same goes for the poly_int_binop signature. The already existing wi::accumulate_overflow should probably be re-done as wi::overflow_type wi::accumulate_overflow (wi::overflow_type, wi::overflow_type); Richard. > Thanks for the review! > Aldy