On Tue, May 14, 2024 at 04:15:08PM +0200, Richard Biener wrote: > On Sun, May 5, 2024 at 8:16 PM Andi Kleen <a...@linux.intel.com> wrote: > > > > - Give error messages for all causes of non sibling call generation > > - Don't override choices of other non sibling call checks with > > must tail. This causes ICEs. The must tail attribute now only > > overrides flag_optimize_sibling_calls locally. > > - Error out when tree-tailcall failed to mark a must-tail call > > sibcall. In this case it doesn't know the true reason and only gives > > a vague message (this could be improved, but it's already useful without > > that) tree-tailcall usually fails without optimization, so must > > adjust the existing must-tail plugin test to specify -O2. > > > > PR83324 > > > > gcc/ChangeLog: > > > > * calls.cc (expand_call): Fix mustcall implementation. > > > > gcc/testsuite/ChangeLog: > > > > * gcc.dg/plugin/must-tail-call-1.c: Adjust. > > --- > > gcc/calls.cc | 30 ++++++++++++------- > > .../gcc.dg/plugin/must-tail-call-1.c | 1 + > > 2 files changed, 21 insertions(+), 10 deletions(-) > > > > diff --git a/gcc/calls.cc b/gcc/calls.cc > > index 21d78f9779fe..a6b8ee44cc29 100644 > > --- a/gcc/calls.cc > > +++ b/gcc/calls.cc > > @@ -2650,7 +2650,9 @@ expand_call (tree exp, rtx target, int ignore) > > /* The type of the function being called. */ > > tree fntype; > > bool try_tail_call = CALL_EXPR_TAILCALL (exp); > > - bool must_tail_call = CALL_EXPR_MUST_TAIL_CALL (exp); > > + /* tree-tailcall decided not to do tail calls. Error for the musttail > > case. */ > > + if (!try_tail_call) > > + maybe_complain_about_tail_call (exp, "other reasons"); > > int pass; > > > > /* Register in which non-BLKmode value will be returned, > > @@ -3022,10 +3024,22 @@ expand_call (tree exp, rtx target, int ignore) > > 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 (currently_expanding_call++ != 0 > > - || (!flag_optimize_sibling_calls && !CALL_FROM_THUNK_P (exp)) > > - || args_size.var > > - || dbg_cnt (tail_call) == false) > > + if (currently_expanding_call++ != 0) > > + { > > + maybe_complain_about_tail_call (exp, "inside another call"); > > + try_tail_call = 0; > > + } > > + if (!flag_optimize_sibling_calls > > + && !CALL_FROM_THUNK_P (exp) > > + && !CALL_EXPR_MUST_TAIL_CALL (exp)) > > + try_tail_call = 0; > > + if (args_size.var) > > If we are both inside another call and run into this we give two errors, > but I guess that's OK ... > > > + { > > + /* ??? correct message? */ > > + maybe_complain_about_tail_call (exp, "stack space needed"); > > args_size.var != NULL_TREE means the argument size is not constant. > I'm quite sure this is an overly conservative check. > > > + try_tail_call = 0; > > + } > > + if (dbg_cnt (tail_call) == false) > > try_tail_call = 0; > > > > /* Workaround buggy C/C++ wrappers around Fortran routines with > > @@ -3046,15 +3060,11 @@ expand_call (tree exp, rtx target, int ignore) > > if (MEM_P (*iter)) > > { > > try_tail_call = 0; > > + maybe_complain_about_tail_call (exp, "hidden string length > > argument"); > > "hidden string length argument passed on stack" > > from what I read the code. > > > break; > > } > > } > > > > - /* If the user has marked the function as requiring tail-call > > - optimization, attempt it. */ > > - if (must_tail_call) > > - try_tail_call = 1; > > - > > /* Rest of purposes for tail call optimizations to fail. */ > > if (try_tail_call) > > try_tail_call = can_implement_as_sibling_call_p (exp, > > diff --git a/gcc/testsuite/gcc.dg/plugin/must-tail-call-1.c > > b/gcc/testsuite/gcc.dg/plugin/must-tail-call-1.c > > index 3a6d4cceaba7..44af361e2925 100644 > > --- a/gcc/testsuite/gcc.dg/plugin/must-tail-call-1.c > > +++ b/gcc/testsuite/gcc.dg/plugin/must-tail-call-1.c > > @@ -1,4 +1,5 @@ > > /* { dg-do compile { target tail_call } } */ > > +/* { dg-options "-O2" } */ > > So I think this is unfortunate - I think when there's a must-tail attribute > we should either run the tailcall pass to check the call even at -O0 or > trust the user with correctness (hoping no optimization interfered with > the ability to tail-call). > > What were the ICEs you ran into? > > I would guess it's for example problematic to duplicate must-tail calls?
I experimented more with this, the problem I have currently is that in -O0 when returning a struct I get something like D.2846 = caller3<Bar> (D.2836); [must tail call] <bb 3> : D.2836 ={v} {CLOBBER(eos)}; return D.2846; And this always fails this check in tree-tailcall: /* If the statement references memory or volatile operands, fail. */ if (gimple_references_memory_p (stmt) || gimple_has_volatile_ops (stmt)) return; In a optimized build this passes, but with -O0 it always fails when the pass is placed before pass_optimizations_g. I assume it's some problem with mem ssa form. Any ideas how to fix that? Otherwise I can restrict musttail to non structs. -Andi