forcing tail/sibling call optimization

Fergus Henderson fjh@cs.mu.oz.au
Sat Sep 14 23:30:00 GMT 2002


I've finally gotten around to having another go at my patches which
allow the front-end to indicate to the back-end when it is safe to do
a tail call.

Firstly, I have a question about coding style.
Which of the following two alternative code samples attached is preferred?
The first one is more concise, but the code checking the list of reasons
for sibcall failure is duplicated.  The second is longer, but the
code dealing with each reason for sibcall failure is in a single place.

Secondly, I have some comments and a question in response to Richard's review
comments.  The semantics I would like for the flag are these:

	If CALL_EXPR_TAILCALL flag is set, this indicates that the
	call is in a tail position, and the caller's stack frame is
	no longer live.  The back-end shall report an error if the
	call is not in a tail position.  The back-end should trust
	the front-end about the liveness of the caller's stack
	frame; any use of the caller's stack frame after such a
	call is undefined behaviour.  The back-end will report a
	diagnostic if the call cannot be optimized as a tail call.

These semantics require the back-end to report an error if the front-end
marks a call as a tail call but the call is not in a tail position, which
requires keeping the CALL_PLACEHOLDER.  I think the error check is useful.
So I'd rather keep the CALL_PLACEHOLDER.  Is that OK?

> On 03-Jan-2001, Richard Henderson <rth@redhat.com> wrote:
> > I'm a bit confused by your intended usage here.  Are you
> > intending CALL_EXPR_FORCE_TAILCALL to indicate that it is
> > _possible_ to perform a tail call despite otherwise 
> > potential problems with the local stack frame?  Or are you
> > intending to indicate that this _will_ be a tail call.
> > In which case the change to CALL_PLACEHOLDER is 
> > not needed.  That is used to choose between alternate
> > code sequences at some later date.  If we _know_ that 
> > we are going to tail call, then we can simply generate
> > either the tail recursion or sibling call sequence 
> > directly and be done with it.

-- 
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
-------------- next part --------------
  /* Tail calls can make things harder to debug, and we're traditionally
     pushed these optimizations into -O2.  Don't try if we're already
     expanding a call, as that means we're an argument.  Don't try if
     there's cleanups, as we know there's code to follow the call.

     If rtx_equal_function_value_matters is false, that means we've
     finished with regular parsing.  Which means that some of the
     machinery we use to generate tail-calls is no longer in place.
     This is most often true of sjlj-exceptions, which we couldn't
     tail-call to anyway.  */

  if (currently_expanding_call++ != 0
      || !flag_optimize_sibling_calls
      || !rtx_equal_function_value_matters
      || any_pending_cleanups (1)
      || args_size.var)
    {
      try_tail_call = try_tail_recursion = 0;
      if (marked_as_tail_call)
        {
          if (currently_expanding_call != 1)
            error("call marked as tail call is not in tail position (it is an argument to another call)");
          else if (!flag_optimize_sibling_calls)
	    warning("can't optimize tail call: -foptimize-sibling-calls not set");
          else if (any_pending_cleanups)
            error("call marked as tail call is not in tail position (there are pending cleanups)");
          else if (!rtx_equal_function_value_matters)
            /* Should this be an internal_error rather than a warning? */
	    warning("can't optimize tail call emitted after regular parsing");
          else if (args_size.var)
	    warning("can't optimize tail call for variable-argument function");
	  else
	    abort();
	  warned_about_tail_call = true;
        }
    }

-------------- next part --------------
  /* Don't try tail calling if we're already expanding a call, as that means
     we're an argument. */

  if (currently_expanding_call++ != 0)
    {
      if (marked_as_tail_call)
        {
          error("call marked as tail call is not in tail position (it is an argument to another call)");
	  warned_about_tail_call = true;
	}
      try_tail_call = try_tail_recursion = 0;
    }

  /* Tail calls can make things harder to debug, and we've traditionally
     pushed these optimizations into -O2.  */

  if (!flag_optimize_sibling_calls != 0)
    {
      if (marked_as_tail_call)
        {
	  inform("can't optimize tail call: -foptimize-sibling-calls not set");
	  warned_about_tail_call = true;
	}
      try_tail_call = try_tail_recursion = 0;
    }

  /* Don't try tail calling if there's cleanups, as we know there's code to
     follow the call. */

  if (any_pending_cleanups != 0)
    {
      if (marked_as_tail_call)
        {
          error("call marked as tail call is not in tail position (there are pending cleanups)");
	  warned_about_tail_call = true;
	}
      try_tail_call = try_tail_recursion = 0;
    }

  /* If rtx_equal_function_value_matters is false, that means we've
     finished with regular parsing.  Which means that some of the
     machinery we use to generate tail-calls is no longer in place.
     This is most often true of sjlj-exceptions, which we couldn't
     tail-call to anyway.  */

  if (!rtx_equal_function_value_matters)
    {
      if (marked_as_tail_call)
        {
          /* Should this be an internal_error rather than a warning? */
	  warning("can't optimize tail call emitted after regular parsing");
	  warned_about_tail_call = true;
	}
      try_tail_call = try_tail_recursion = 0;
    }

  /* Don't try tail calling for variable-argument functions.
     The current implementation won't handle those.  */

  if (args_size.var)
    {
      if (marked_as_tail_call)
        {
	  warning("can't optimize tail call for variable-argument function");
	  warned_about_tail_call = true;
	}
      try_tail_call = try_tail_recursion = 0;
    }



More information about the Gcc-patches mailing list