https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121784
--- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
To explain better what is happening under the hood,
using StageFn = void (*)(StageList list, int src, int dst, F r, F g, F b);
void m(StageList list, int src, int dst, F r, F g, F b) {
return (*list.fn)(list, src, dst, r, g, b);
}
is actually handled under the hood for these RISCV ABIs (for GCC starting with
expansion to RTL) as C++
using StageFn = void (*)(StageList list, int src, int dst, const F &, const F
&, const F &);
void m(StageList list, int src, int dst, const F &r_, const F &g_, const F &b_)
{
F r = r_, g = g_, b = b_;
return (*list.fn)(list, src, dst, r, g, b);
}
Now, if the r, g, b arguments are or could be modified, that is the only way
how it can be handled given the weird ABIs and it is simply not tail callable.
But if the arguments are unmodified, one could handle it as
void m(StageList list, int src, int dst, const F &r_, const F &g_, const F &b_)
{
return (*list.fn)(list, src, dst, r_, g_, b_);
}
instead and thus make it tail callable.
Compare that to e.g. ia32 without SSE (or x86_64 for later arguments after all
argument registers are used for other arguments), F in that case is passed on
the stack, not by invisible reference, so tail call is possible if callee
doesn't need fewer argument stack slots than the caller, before the tail call
the code can simply copy over (or if lucky just expect it to be there already)
the data into the right stack slot.
Anyway, using musttail attribute carelessly without actually thinking about the
different ABIs and their limitations/consequences is a sure way to get compiler
errors (or with clang sometimes silent not honoring of the attribute, as
happens e.g. on the s390x case). Some ABIs can't tail call anything, others
have very large limitations.