On Tue, 1 Apr 2025, Jakub Jelinek wrote: > Hi! > > While working on the previous tailc patch, I've noticed the following > problem. > The testcase below fails, because we decide to tail recursion optimize > the call, but tail recursion (as documented in tree-tailcall.cc) needs to > add some result multiplication and/or addition if any tail recursion uses > accumulator, which is added right before the return. > So, if there are musttail non-recurive calls in the function, successful > tail recursion optimization will mean we'll later error on the musttail > calls. musttail recursive calls are ok, those would be tail recursion > optimized. > > So, the following patch punts on all tail recursion optimizations if it > needs accumulators (add and/or mult) if there is at least one non-recursive > musttail call. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK. Do we update cfun->has_musttail at some point for optimized away musttail calls with respect to inlining/DCE? I do wonder whether tree-tailcall.cc itself could "quickly" determine whether we have any musttail calls that we can handle and will not diagnose? Thanks, Richard. > 2025-04-01 Jakub Jelinek <ja...@redhat.com> > > PR tree-optimization/119493 > * tree-tailcall.cc (tree_optimize_tail_calls_1): Ignore tail recursion > candidates which need accumulators if there is at least one musttail > non-recursive call. > > * gcc.dg/pr119493-2.c: New test. > > --- gcc/tree-tailcall.cc.jj 2025-03-31 13:00:58.288725496 +0200 > +++ gcc/tree-tailcall.cc 2025-03-31 14:34:31.285106333 +0200 > @@ -1373,6 +1373,38 @@ tree_optimize_tail_calls_1 (bool opt_tai > live_vars = NULL; > } > > + if (cfun->has_musttail) > + { > + /* We can't mix non-recursive must tail calls with tail recursive > + calls which require accumulators, because in that case we have to > + emit code in between the musttail calls and return, which prevent > + calling them as tail calls. So, in that case give up on the > + tail recursion. */ > + for (act = tailcalls; act; act = act->next) > + if (!act->tail_recursion) > + { > + gcall *call = as_a <gcall *> (gsi_stmt (act->call_gsi)); > + if (gimple_call_must_tail_p (call)) > + break; > + } > + if (act) > + for (struct tailcall **p = &tailcalls; *p; ) > + { > + if ((*p)->tail_recursion && ((*p)->add || (*p)->mult)) > + { > + struct tailcall *a = *p; > + *p = (*p)->next; > + gcall *call = as_a <gcall *> (gsi_stmt (a->call_gsi)); > + maybe_error_musttail (call, > + _("tail recursion with accumulation " > + "mixed with musttail " > + "non-recursive call"), diag_musttail); > + free (a); > + } > + else > + p = &(*p)->next; > + } > + } > /* Construct the phi nodes and accumulators if necessary. */ > a_acc = m_acc = NULL_TREE; > for (act = tailcalls; act; act = act->next) > --- gcc/testsuite/gcc.dg/pr119493-2.c.jj 2025-03-31 14:41:18.977464154 > +0200 > +++ gcc/testsuite/gcc.dg/pr119493-2.c 2025-03-31 14:45:24.327068682 +0200 > @@ -0,0 +1,22 @@ > +/* PR tree-optimization/119493 */ > +/* { dg-do compile { target musttail } } */ > +/* { dg-options "-O2 -fdump-tree-tailr1-details" } */ > +/* { dg-final { scan-tree-dump-times "tail recursion with accumulation mixed > with musttail non-recursive call" 2 "tailr1" } } */ > + > +[[gnu::noipa]] int > +bar (int x, int y) > +{ > + return x + y; > +} > + > +[[gnu::noinline, gnu::noclone]] int > +foo (int x, int y) > +{ > + if (x < 10) > + [[gnu::musttail]] return bar (x, y); > + if (y & 2) > + return foo (x - 1, y) * 2; > + if (y & 1) > + [[gnu::musttail]] return foo (x - 1, y); > + return foo (x - 1, y) * 3; > +} > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)