This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Avoid building CALL_EXPRs in gimple_fold_stmt_to_constant_1
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 3 Dec 2014 12:51:56 +0100 (CET)
- Subject: Re: [PATCH] Avoid building CALL_EXPRs in gimple_fold_stmt_to_constant_1
- Authentication-results: sourceware.org; auth=none
- References: <alpine dot LSU dot 2 dot 11 dot 1412031119290 dot 5894 at zhemvz dot fhfr dot qr>
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 <rguenther@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 <rguenther@suse.de>
SUSE LINUX GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendoerffer, HRB 21284
(AG Nuernberg)
Maxfeldstrasse 5, 90409 Nuernberg, Germany