On Fri, 21 Mar 2025, Jakub Jelinek wrote:

> Hi!
> 
> As discussed in the PR, some packages fail to build because they use
> musttail attribute on calls in functions which we inline, and if they
> are inlined into a middle of the function, that results in an error
> because we have a musttail call in the middle of a function and so it
> can't be tail called there.
> 
> Now, guess the primary intent of the musttail attribute is ensuring
> we don't get an extra stack frame in the backtrace.  Inlining itself
> removes one extra stack frame from the backtrace as well (sure, not
> counting virtual backtraces in gdb), so I think erroring out on that
> is unnecessary.
> 
> Except when we are inlining a musttail call which has musttail calls
> in it, in that case we are being asked to remove 2 stack frames from
> the backtrace, inlining removes one, so we need to keep musttail
> on the calls so that another stack frame is removed through a tail call.
> 
> The following patch implements that, keeping previous behavior when
> id->call_stmt is NULL (i.e. when versioning/cloning etc.).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2025-03-20  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR ipa/119376
>       * tree-inline.cc (remap_gimple_stmt): Silently clear
>       gimple_call_must_tail_p on inlined call stmts if id->call_stmt
>       is a call without that flag set.
> 
>       * c-c++-common/musttail26.c: New test.
> 
> --- gcc/tree-inline.cc.jj     2025-01-20 17:58:39.244480277 +0100
> +++ gcc/tree-inline.cc        2025-03-20 12:08:42.957453514 +0100
> @@ -1892,6 +1892,15 @@ remap_gimple_stmt (gimple *stmt, copy_bo
>           gimple_call_set_tail (call_stmt, false);
>         if (gimple_call_from_thunk_p (call_stmt))
>           gimple_call_set_from_thunk (call_stmt, false);
> +       /* Silently clear musttail flag when inlining a function
> +          with must tail call from a non-musttail call.  The inlining
> +          removes one frame so acts like musttail's intent, and we
> +          can be inlining a function with musttail calls in the middle
> +          of caller where musttail will always error.  */
> +       if (gimple_call_must_tail_p (call_stmt)
> +           && id->call_stmt
> +           && !gimple_call_must_tail_p (id->call_stmt))
> +         gimple_call_set_must_tail (call_stmt, false);
>         if (gimple_call_internal_p (call_stmt))
>           switch (gimple_call_internal_fn (call_stmt))
>             {
> --- gcc/testsuite/c-c++-common/musttail26.c.jj        2025-03-20 
> 12:47:53.443730606 +0100
> +++ gcc/testsuite/c-c++-common/musttail26.c   2025-03-20 12:53:26.110082182 
> +0100
> @@ -0,0 +1,33 @@
> +/* PR ipa/119376 */
> +/* { dg-do compile { target musttail } } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump-times "  \[^\n\r]* = foo \\\(3, 
> \[^\n\r]*\\\); \\\[tail call\\\] \\\[must tail call\\\]" 1 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "  \[^\n\r]* = foo \\\(4, 
> \[^\n\r]*\\\); \\\[tail call\\\] \\\[must tail call\\\]" 1 "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "  foo \\\(\[12], \[^\n\r]*\\\); \\\[tail 
> call\\\]" "optimized" } } */
> +
> +int foo (int, int);
> +int v, w[10];
> +
> +static inline __attribute__((always_inline)) int
> +bar (int x, int y)
> +{
> +  [[gnu::musttail]] return foo (x, y);
> +}
> +
> +static int
> +baz (int x, int y)
> +{
> +  [[gnu::musttail]] return foo (x, x + y + (v | y) * (v & y));
> +}
> +
> +int
> +qux (int x, int y)
> +{
> +  w[0] = bar (1, x + y);
> +  w[1] = baz (2, x + y);
> +  if (x == 42)
> +    [[gnu::musttail]] return bar (3, x + y);
> +  if (x == -42)
> +    [[gnu::musttail]] return baz (4, x + y);
> +  return 0;
> +}
> 
>       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)

Reply via email to