This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: forcing tail/sibling call optimization
On 03-Jan-2001, Richard Henderson <rth@redhat.com> wrote:
> On Thu, Jan 04, 2001 at 10:53:15AM +1100, Fergus Henderson wrote:
> > On 03-Jan-2001, Richard Henderson <rth@redhat.com> wrote:
> > > if the front end didn't really care if the tail
> > > call didn't happen, it could query the target before setting the bit.
> >
> > How can it query the target? The query needed is not just "does this
> > target support tail calls", it is "does this target support *this*
> > tail call", and the answer can depend on lots of stuff that the front
> > end doesn't want to know about.
>
> See FUNCTION_OK_FOR_SIBCALL; cfun->decl must be valid during the
> query so that the target can compare return types (see the x86
> version for why this matters).
But that's just one of the many ways in which sibling call optimization
can fail. There's lots of other ways it can fail in expand_call()
[see below]. Note that quite a few of these ways are just limitations
of the current implementation, not inherent requirements. It seems
like a bad idea to duplicate that logic in the language front-end.
P.S.
For completeness here a list of some of the other ways it can
fail in expand_call().
| || args_size.var)
...
| #ifdef HAVE_sibcall_epilogue
| !HAVE_sibcall_epilogue
| #else
| 1
| #endif
...
| /* 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
| /* If the register holding the address is a callee saved
| register, then we lose. We have no way to prevent that,
| so we only allow calls to named functions. */
| /* ??? This could be done by having the insn constraints
| use a register class that is all call-clobbered. Any
| reload insns generated to fix things up would appear
| before the sibcall_epilogue. */
| || fndecl == NULL_TREE
| || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP))
| || TREE_THIS_VOLATILE (fndecl)
| || !FUNCTION_OK_FOR_SIBCALL (fndecl)
| /* If this function requires more stack slots than the current
| function, we cannot change it into a sibling call. */
| || args_size.constant > current_function_args_size
| /* If the callee pops its own arguments, then it must pop exactly
| the same number of arguments as the current function. */
| || RETURN_POPS_ARGS (fndecl, funtype, args_size.constant)
| != RETURN_POPS_ARGS (current_function_decl,
| TREE_TYPE (current_function_decl),
| current_function_args_size))
...
| /* Handle calls that return values in multiple non-contiguous locations.
| The Irix 6 ABI has examples of this. */
| else if (GET_CODE (valreg) == PARALLEL)
| {
...
| /* We can not support sibling calls for this case. */
| sibcall_failure = 1;
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
| of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.