Introduce can_implement_as_sibling_call_p

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.

From-SVN: r236513
This commit is contained in:
David Malcolm 2016-05-20 14:07:56 +00:00 committed by David Malcolm
parent 97c53806a2
commit b40d90e6c5
2 changed files with 83 additions and 38 deletions

View File

@ -1,3 +1,10 @@
2016-05-20 David Malcolm <dmalcolm@redhat.com>
* 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.
2016-05-20 Jan Hubicka <hubicka@ucw.cz>
* cfgloop.h (expected_loop_iterations_unbounded,

View File

@ -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
/* 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. */