David Malcolm via Gcc <gcc@gcc.gnu.org> wrote:

On Fri, 2021-04-23 at 12:44 -0700, Josh Haberman via Gcc wrote:
Would it be feasible to implement a "musttail" statement attribute in
GCC to get a guarantee that tail call optimization will be performed?

Such an attribute has just landed in the trunk of Clang
(https://reviews.llvm.org/D99517). It makes it possible to write
algorithms that use arbitrarily long chains of tail calls without risk
of blowing the stack. I would love to see something like this land in
GCC also (ultimately I'd love to see it standardized).


FWIW I implemented something like this in GCC's middle-end here:
 
https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=9a385c2d3d74ffed78f2ed9ad47b844d2f294105
exposing it in API form for libgccjit:
 
https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=15c671a79ca66df5b1de70dd1a0b78414fe003ef
https://gcc.gnu.org/onlinedocs/jit/topics/expressions.html#c.gcc_jit_rvalue_set_bool_require_tail_call
but IIRC it's not yet exposed to the regular GCC frontends.

I did try to use it this ^ for GCC coroutines (where such a guarantee is pretty important)

However, the issue there is that not all targets support indirect tailcalls.
What about tailcalls between DSOs?

Are those also excluded in the clang impl?
Iain


Dave

I wrote more about some motivation for guaranteed tail calls here:

https://blog.reverberate.org/2021/04/21/musttail-efficient-interpreters.html

GCC successfully optimizes tail calls in many cases already. What
would it take to provide an actual guarantee, and make it apply to
non-optimized builds also?
The Clang implementation enforces several rules that must hold for the
attribute to be correct, including:

- It must be on a function call that is tail position.
- Caller and callee must have compatible function signatures
(including the implicit "this", if any), differing only in cv
qualifiers.
- Caller and callee must use the same calling convention.
- Caller and callee may not be constructors or destructors.
- All arguments, the return type, and any temporaries created must be
trivially destructible.
- All variables currently in scope must be trivially destructible.
- The caller cannot be in a try block, an Objective-C block, or a
statement expression.

Some of these restrictions may be overly strict for some calling
conventions, but they are useful as the "least common denominator"
that should be safe in all cases. When implementing this in Clang, we
found that we were able to reuse some of the checks around goto and
asm goto, since a tail call is sort of like a goto out of the
function's scope.

Thanks,
Josh


Reply via email to