On Wed, 3 Dec 2014, Richard Biener wrote: > > This refactors fold_builtin_call_array to not build a CALL_EXPR if > no simplification was possible (we have fold_build_call_array_loc > for that). This requires to fix the single case where that was > deemed necessary (fold_builtin_varargs calling fold_builtin_fpclassify) > which is easily fixed to simply work with the call argument array. > > This also fixes missing fpclassify folding from fold_stmt which > dispatches to fold_call_stmt which only calls fold_builtin_n. > > Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. > > I'll consider the cp/ part as obvious and will commit this after > testing succeeded.
Which that part didn't (the rest did). I'll replace it with the even more obvious Index: gcc/cp/constexpr.c =================================================================== --- gcc/cp/constexpr.c (revision 218308) +++ gcc/cp/constexpr.c (working copy) @@ -1008,8 +1008,8 @@ cxx_eval_builtin_function_call (const co } if (*non_constant_p) return t; - new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), - CALL_EXPR_FN (t), nargs, args); + new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t), + CALL_EXPR_FN (t), nargs, args); VERIFY_CONSTANT (new_call); return new_call; } re-testing that. Thanks, Richard. > Thanks, > Richard. > > 2014-12-03 Richard Biener <rguent...@suse.de> > > * builtins.c (fold_builtin_fpclassify): Change to take > array of arguments instead of CALL_EXPR tree. > (MAX_ARGS_TO_FOLD_BUILTIN): Remove. > (fold_builtin_n): Dispatch to fold_builtin_varargs. > (fold_call_expr): Always use fold_builtin_n. > (fold_builtin_call_array): Change to not build the unfolded call, > always use fold_builtin_n. > (fold_builtin_varargs): Change to take array of arguments instead > of CALL_EXPR tree. > (fold_call_stmt): Always use fold_builtin_n. > * tree.c (build_call_expr_loc_array): Use fold_build_call_array_loc. > * fold-const.c (fold_build_call_array_loc): Build the call > if fold_builtin_call_array returned NULL_TREE. > * gimple-fold.c (gimple_fold_stmt_to_constant_1): Do not build > a CALL_EXPR and use fold_builtin_call_array instead of > fold_call_expr. > > cp/ > * constexpr.c (cxx_eval_builtin_function_call): Deal with > fold_builtin_call_array only returning non-NULL if it simplified > something. > > Index: gcc/builtins.c > =================================================================== > --- gcc/builtins.c (revision 218271) > +++ gcc/builtins.c (working copy) > @@ -196,7 +196,7 @@ static tree fold_builtin_1 (location_t, > static tree fold_builtin_2 (location_t, tree, tree, tree, bool); > static tree fold_builtin_3 (location_t, tree, tree, tree, tree, bool); > static tree fold_builtin_4 (location_t, tree, tree, tree, tree, tree, bool); > -static tree fold_builtin_varargs (location_t, tree, tree, bool); > +static tree fold_builtin_varargs (location_t, tree, tree*, int, bool); > > static tree fold_builtin_strpbrk (location_t, tree, tree, tree); > static tree fold_builtin_strstr (location_t, tree, tree, tree); > @@ -9785,7 +9785,7 @@ fold_builtin_classify (location_t loc, t > one floating point argument which is "type generic". */ > > static tree > -fold_builtin_fpclassify (location_t loc, tree exp) > +fold_builtin_fpclassify (location_t loc, tree *args, int nargs) > { > tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero, > arg, type, res, tmp; > @@ -9794,17 +9794,21 @@ fold_builtin_fpclassify (location_t loc, > char buf[128]; > > /* Verify the required arguments in the original call. */ > - if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, > - INTEGER_TYPE, INTEGER_TYPE, > - INTEGER_TYPE, REAL_TYPE, VOID_TYPE)) > + if (nargs != 6 > + || !validate_arg (args[0], INTEGER_TYPE) > + || !validate_arg (args[1], INTEGER_TYPE) > + || !validate_arg (args[2], INTEGER_TYPE) > + || !validate_arg (args[3], INTEGER_TYPE) > + || !validate_arg (args[4], INTEGER_TYPE) > + || !validate_arg (args[5], REAL_TYPE)) > return NULL_TREE; > > - fp_nan = CALL_EXPR_ARG (exp, 0); > - fp_infinite = CALL_EXPR_ARG (exp, 1); > - fp_normal = CALL_EXPR_ARG (exp, 2); > - fp_subnormal = CALL_EXPR_ARG (exp, 3); > - fp_zero = CALL_EXPR_ARG (exp, 4); > - arg = CALL_EXPR_ARG (exp, 5); > + fp_nan = args[0]; > + fp_infinite = args[1]; > + fp_normal = args[2]; > + fp_subnormal = args[3]; > + fp_zero = args[4]; > + arg = args[5]; > type = TREE_TYPE (arg); > mode = TYPE_MODE (type); > arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg)); > @@ -10708,14 +10712,9 @@ fold_builtin_4 (location_t loc, tree fnd > } > > /* Fold a call to built-in function FNDECL. ARGS is an array of NARGS > - arguments, where NARGS <= 4. IGNORE is true if the result of the > - function call is ignored. This function returns NULL_TREE if no > - simplification was possible. Note that this only folds builtins with > - fixed argument patterns. Foldings that do varargs-to-varargs > - transformations, or that match calls with more than 4 arguments, > - need to be handled with fold_builtin_varargs instead. */ > - > -#define MAX_ARGS_TO_FOLD_BUILTIN 4 > + arguments. IGNORE is true if the result of the > + function call is ignored. This function returns NULL_TREE if no > + simplification was possible. */ > > tree > fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool > ignore) > @@ -10741,6 +10740,7 @@ fold_builtin_n (location_t loc, tree fnd > ignore); > break; > default: > + ret = fold_builtin_varargs (loc, fndecl, args, nargs, ignore); > break; > } > if (ret) > @@ -10837,13 +10837,8 @@ fold_call_expr (location_t loc, tree exp > CALL_EXPR_ARGP (exp), ignore); > else > { > - if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN) > - { > - tree *args = CALL_EXPR_ARGP (exp); > - ret = fold_builtin_n (loc, fndecl, args, nargs, ignore); > - } > - if (!ret) > - ret = fold_builtin_varargs (loc, fndecl, exp, ignore); > + tree *args = CALL_EXPR_ARGP (exp); > + ret = fold_builtin_n (loc, fndecl, args, nargs, ignore); > if (ret) > return ret; > } > @@ -10851,62 +10846,43 @@ fold_call_expr (location_t loc, tree exp > return NULL_TREE; > } > > -/* Construct a CALL_EXPR with type TYPE with FN as the function expression. > - N arguments are passed in the array ARGARRAY. */ > +/* Fold a CALL_EXPR with type TYPE with FN as the function expression. > + N arguments are passed in the array ARGARRAY. Return a folded > + expression or NULL_TREE if no simplification was possible. */ > > tree > -fold_builtin_call_array (location_t loc, tree type, > +fold_builtin_call_array (location_t loc, tree, > tree fn, > int n, > tree *argarray) > { > - tree ret = NULL_TREE; > - tree exp; > + if (TREE_CODE (fn) != ADDR_EXPR) > + return NULL_TREE; > > - if (TREE_CODE (fn) == ADDR_EXPR) > - { > - tree fndecl = TREE_OPERAND (fn, 0); > - if (TREE_CODE (fndecl) == FUNCTION_DECL > - && DECL_BUILT_IN (fndecl)) > - { > - /* If last argument is __builtin_va_arg_pack (), arguments to this > - function are not finalized yet. Defer folding until they are. */ > - if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR) > - { > - tree fndecl2 = get_callee_fndecl (argarray[n - 1]); > - if (fndecl2 > - && TREE_CODE (fndecl2) == FUNCTION_DECL > - && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL > - && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK) > - return build_call_array_loc (loc, type, fn, n, argarray); > - } > - if (avoid_folding_inline_builtin (fndecl)) > - return build_call_array_loc (loc, type, fn, n, argarray); > - if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) > - { > - ret = targetm.fold_builtin (fndecl, n, argarray, false); > - if (ret) > - return ret; > - > - return build_call_array_loc (loc, type, fn, n, argarray); > - } > - else if (n <= MAX_ARGS_TO_FOLD_BUILTIN) > - { > - /* First try the transformations that don't require consing up > - an exp. */ > - ret = fold_builtin_n (loc, fndecl, argarray, n, false); > - if (ret) > - return ret; > - } > - > - /* If we got this far, we need to build an exp. */ > - exp = build_call_array_loc (loc, type, fn, n, argarray); > - ret = fold_builtin_varargs (loc, fndecl, exp, false); > - return ret ? ret : exp; > - } > - } > + tree fndecl = TREE_OPERAND (fn, 0); > + if (TREE_CODE (fndecl) == FUNCTION_DECL > + && DECL_BUILT_IN (fndecl)) > + { > + /* If last argument is __builtin_va_arg_pack (), arguments to this > + function are not finalized yet. Defer folding until they are. */ > + if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR) > + { > + tree fndecl2 = get_callee_fndecl (argarray[n - 1]); > + if (fndecl2 > + && TREE_CODE (fndecl2) == FUNCTION_DECL > + && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL > + && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK) > + return NULL_TREE; > + } > + if (avoid_folding_inline_builtin (fndecl)) > + return NULL_TREE; > + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) > + return targetm.fold_builtin (fndecl, n, argarray, false); > + else > + return fold_builtin_n (loc, fndecl, argarray, n, false); > + } > > - return build_call_array_loc (loc, type, fn, n, argarray); > + return NULL_TREE; > } > > /* Construct a new CALL_EXPR using the tail of the argument list of EXP > @@ -11914,7 +11890,7 @@ fold_builtin_object_size (tree ptr, tree > result of the function call is ignored. */ > > static tree > -fold_builtin_varargs (location_t loc, tree fndecl, tree exp, > +fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs, > bool ignore ATTRIBUTE_UNUSED) > { > enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); > @@ -11923,7 +11899,7 @@ fold_builtin_varargs (location_t loc, tr > switch (fcode) > { > case BUILT_IN_FPCLASSIFY: > - ret = fold_builtin_fpclassify (loc, exp); > + ret = fold_builtin_fpclassify (loc, args, nargs); > break; > > default: > @@ -12834,8 +12810,7 @@ fold_call_stmt (gcall *stmt, bool ignore > } > else > { > - if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN) > - ret = fold_builtin_n (loc, fndecl, args, nargs, ignore); > + ret = fold_builtin_n (loc, fndecl, args, nargs, ignore); > if (ret) > { > /* Propagate location information from original call to > Index: gcc/tree.c > =================================================================== > --- gcc/tree.c (revision 218271) > +++ gcc/tree.c (working copy) > @@ -10591,7 +10591,7 @@ build_call_expr_loc_array (location_t lo > tree fntype = TREE_TYPE (fndecl); > tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl); > > - return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray); > + return fold_build_call_array_loc (loc, TREE_TYPE (fntype), fn, n, > argarray); > } > > /* Conveniently construct a function call expression. FNDECL names the > Index: gcc/fold-const.c > =================================================================== > --- gcc/fold-const.c (revision 218271) > +++ gcc/fold-const.c (working copy) > @@ -14405,6 +14422,8 @@ fold_build_call_array_loc (location_t lo > #endif > > tem = fold_builtin_call_array (loc, type, fn, nargs, argarray); > + if (!tem) > + tem = build_call_array_loc (loc, type, fn, nargs, argarray); > > #ifdef ENABLE_FOLD_CHECKING > md5_init_ctx (&ctx); > Index: gcc/gimple-fold.c > =================================================================== > --- gcc/gimple-fold.c (revision 218271) > +++ gcc/gimple-fold.c (working copy) > @@ -4744,14 +4744,13 @@ gimple_fold_stmt_to_constant_1 (gimple s > TREE_OPERAND (fn, 0))) > { > tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt)); > - tree call, retval; > + tree retval; > unsigned i; > for (i = 0; i < gimple_call_num_args (stmt); ++i) > args[i] = (*valueize) (gimple_call_arg (stmt, i)); > - call = build_call_array_loc (loc, > + retval = fold_builtin_call_array (loc, > gimple_call_return_type (call_stmt), > fn, gimple_call_num_args (stmt), args); > - retval = fold_call_expr (EXPR_LOCATION (call), call, false); > if (retval) > { > /* fold_call_expr wraps the result inside a NOP_EXPR. */ > Index: gcc/cp/constexpr.c > =================================================================== > --- gcc/cp/constexpr.c (revision 218271) > +++ gcc/cp/constexpr.c (working copy) > @@ -1010,8 +1010,9 @@ cxx_eval_builtin_function_call (const co > return t; > new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), > CALL_EXPR_FN (t), nargs, args); > - VERIFY_CONSTANT (new_call); > - return new_call; > + if (new_call) > + VERIFY_CONSTANT (new_call); > + return t; > } > > /* TEMP is the constant value of a temporary object of type TYPE. Adjust > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendoerffer, HRB 21284 (AG Nuernberg) Maxfeldstrasse 5, 90409 Nuernberg, Germany