[PATCH 1/3] Introduce can_implement_as_sibling_call_p
Kyrill Tkachov
kyrylo.tkachov@foss.arm.com
Fri Jan 1 00:00:00 GMT 2016
Hi David,
On 17/05/16 23:01, David Malcolm wrote:
> This patch moves part of the logic for determining if tail
> call optimizations are possible to a new helper function.
>
> There are no functional changes.
>
> expand_call is 1300 lines long, so there's arguably a
> case for doing this on its own, but this change also
> enables the followup patch.
>
> The patch changes the logic from a big "if" with joined
> || clauses:
>
> if (first_problem ()
> ||second_problem ()
> /* ...etc... */
> ||final_problem ())
> try_tail_call = 0;
>
> to a series of separate tests:
>
> if (first_problem ())
> return false;
> if (second_problem ())
> return false;
> /* ...etc... */
> if (final_problem ())
> return false;
>
> I think the latter form has several advantages over the former:
> - IMHO it's easier to read
> - it makes it easy to put breakpoints on individual causes of failure
> - it makes it easy to put specific error messages on individual causes
> of failure (as done in the followup patch).
>
> Successfully bootstrapped®rtested on x86_64-pc-linux-gnu.
>
> OK for trunk?
>
> gcc/ChangeLog:
> * calls.c (expand_call): Move "Rest of purposes for tail call
> optimizations to fail" to...
> (can_implement_as_sibling_call_p): ...this new function, and
> split into multiple "if" statements.
> ---
> gcc/calls.c | 114 ++++++++++++++++++++++++++++++++++++++++--------------------
> 1 file changed, 76 insertions(+), 38 deletions(-)
>
> diff --git a/gcc/calls.c b/gcc/calls.c
> index 6cc1fc7..ac8092c 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -2344,6 +2344,78 @@ avoid_likely_spilled_reg (rtx x)
> return x;
> }
>
> +/* Helper function for expand_call.
> + Return false is EXP is not implementable as a sibling call. */
> +
> +static bool
> +can_implement_as_sibling_call_p (tree exp,
> + rtx structure_value_addr,
> + tree funtype,
> + int reg_parm_stack_space,
> + tree fndecl,
> + int flags,
> + tree addr,
> + const args_size &args_size)
> +{
> + if (!targetm.have_sibcall_epilogue ())
> + return false;
> +
> + /* Doing sibling call optimization needs some work, since
> + structure_value_addr can be allocated on the stack.
> + It does not seem worth the effort since few optimizable
> + sibling calls will return a structure. */
> + if (structure_value_addr != NULL_RTX)
> + return false;
> +
> +#ifdef REG_PARM_STACK_SPACE
> + /* If outgoing reg parm stack space changes, we can not do sibcall. */
> + if (OUTGOING_REG_PARM_STACK_SPACE (funtype)
> + != OUTGOING_REG_PARM_STACK_SPACE (TREE_TYPE (current_function_decl))
> + || (reg_parm_stack_space != REG_PARM_STACK_SPACE (current_function_decl)))
> + return false;
> +#endif
> +
REG_PARM_STACK_SPACE is not defined on arm, which makes reg_parm_stack_space
unused in this function and so breaks bootstrap on arm.
Can you please add an ATTRIBUTE_UNUSED to reg_parm_stack_space?
Thanks,
Kyrill
> + /* Check whether the target is able to optimize the call
> + into a sibcall. */
> + if (!targetm.function_ok_for_sibcall (fndecl, exp))
> + return false;
> +
> + /* Functions that do not return exactly once may not be sibcall
> + optimized. */
> + if (flags & (ECF_RETURNS_TWICE | ECF_NORETURN))
> + return false;
> +
> + if (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr))))
> + return false;
> +
> + /* If the called function is nested in the current one, it might access
> + some of the caller's arguments, but could clobber them beforehand if
> + the argument areas are shared. */
> + if (fndecl && decl_function_context (fndecl) == current_function_decl)
> + return false;
> +
> + /* If this function requires more stack slots than the current
> + function, we cannot change it into a sibling call.
> + crtl->args.pretend_args_size is not part of the
> + stack allocated by our caller. */
> + if (args_size.constant > (crtl->args.size - crtl->args.pretend_args_size))
> + return false;
> +
> + /* If the callee pops its own arguments, then it must pop exactly
> + the same number of arguments as the current function. */
> + if (targetm.calls.return_pops_args (fndecl, funtype, args_size.constant)
> + != targetm.calls.return_pops_args (current_function_decl,
> + TREE_TYPE (current_function_decl),
> + crtl->args.size))
> + return false;
> +
> + if (!lang_hooks.decls.ok_for_sibcall (fndecl))
> + return false;
> +
> + /* All checks passed. */
> + return true;
> +}
> +
> /* Generate all the code for a CALL_EXPR exp
> and return an rtx for its value.
> Store the value in TARGET (specified as an rtx) if convenient.
> @@ -2740,44 +2812,10 @@ expand_call (tree exp, rtx target, int ignore)
> try_tail_call = 0;
>
> /* Rest of purposes for tail call optimizations to fail. */
> - if (!try_tail_call
> - || !targetm.have_sibcall_epilogue ()
> - /* Doing sibling call optimization needs some work, since
> - structure_value_addr can be allocated on the stack.
> - It does not seem worth the effort since few optimizable
> - sibling calls will return a structure. */
> - || structure_value_addr != NULL_RTX
> -#ifdef REG_PARM_STACK_SPACE
> - /* If outgoing reg parm stack space changes, we can not do sibcall. */
> - || (OUTGOING_REG_PARM_STACK_SPACE (funtype)
> - != OUTGOING_REG_PARM_STACK_SPACE (TREE_TYPE (current_function_decl)))
> - || (reg_parm_stack_space != REG_PARM_STACK_SPACE (current_function_decl))
> -#endif
> - /* Check whether the target is able to optimize the call
> - into a sibcall. */
> - || !targetm.function_ok_for_sibcall (fndecl, exp)
> - /* Functions that do not return exactly once may not be sibcall
> - optimized. */
> - || (flags & (ECF_RETURNS_TWICE | ECF_NORETURN))
> - || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr)))
> - /* If the called function is nested in the current one, it might access
> - some of the caller's arguments, but could clobber them beforehand if
> - the argument areas are shared. */
> - || (fndecl && decl_function_context (fndecl) == current_function_decl)
> - /* If this function requires more stack slots than the current
> - function, we cannot change it into a sibling call.
> - crtl->args.pretend_args_size is not part of the
> - stack allocated by our caller. */
> - || args_size.constant > (crtl->args.size
> - - crtl->args.pretend_args_size)
> - /* If the callee pops its own arguments, then it must pop exactly
> - the same number of arguments as the current function. */
> - || (targetm.calls.return_pops_args (fndecl, funtype, args_size.constant)
> - != targetm.calls.return_pops_args (current_function_decl,
> - TREE_TYPE (current_function_decl),
> - crtl->args.size))
> - || !lang_hooks.decls.ok_for_sibcall (fndecl))
> - try_tail_call = 0;
> + if (try_tail_call)
> + try_tail_call = can_implement_as_sibling_call_p (exp, structure_value_addr, funtype,
> + reg_parm_stack_space, fndecl,
> + flags, addr, args_size);
>
> /* Check if caller and callee disagree in promotion of function
> return value. */
More information about the Jit
mailing list