Commit b40d90e6 by David Malcolm Committed by David Malcolm

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
parent 97c53806
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> 2016-05-20 Jan Hubicka <hubicka@ucw.cz>
* cfgloop.h (expected_loop_iterations_unbounded, * cfgloop.h (expected_loop_iterations_unbounded,
......
...@@ -2344,6 +2344,78 @@ avoid_likely_spilled_reg (rtx x) ...@@ -2344,6 +2344,78 @@ avoid_likely_spilled_reg (rtx x)
return 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 /* Generate all the code for a CALL_EXPR exp
and return an rtx for its value. and return an rtx for its value.
Store the value in TARGET (specified as an rtx) if convenient. Store the value in TARGET (specified as an rtx) if convenient.
...@@ -2740,44 +2812,10 @@ expand_call (tree exp, rtx target, int ignore) ...@@ -2740,44 +2812,10 @@ expand_call (tree exp, rtx target, int ignore)
try_tail_call = 0; try_tail_call = 0;
/* Rest of purposes for tail call optimizations to fail. */ /* Rest of purposes for tail call optimizations to fail. */
if (!try_tail_call if (try_tail_call)
|| !targetm.have_sibcall_epilogue () try_tail_call = can_implement_as_sibling_call_p (exp, structure_value_addr, funtype,
/* Doing sibling call optimization needs some work, since reg_parm_stack_space, fndecl,
structure_value_addr can be allocated on the stack. flags, addr, args_size);
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;
/* Check if caller and callee disagree in promotion of function /* Check if caller and callee disagree in promotion of function
return value. */ return value. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment