From b40d90e6c569c434002f968a197d58eed0d2aaa3 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 20 May 2016 14:07:56 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 7 ++++ gcc/calls.c | 114 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 83 insertions(+), 38 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7f5f87f293f..1b5959dce8b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2016-05-20 David Malcolm + + * 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 * cfgloop.h (expected_loop_iterations_unbounded, diff --git a/gcc/calls.c b/gcc/calls.c index 6cc1fc721e4..ac8092c696e 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 + + /* 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. */ -- 2.30.2