https://gcc.gnu.org/g:37ae2e055687a22974d7bcb9e618f258fa49ab1a

commit r15-8492-g37ae2e055687a22974d7bcb9e618f258fa49ab1a
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri Mar 21 12:17:01 2025 +0100

    inliner: Silently drop musttail flag on calls during inlining unless the 
inlined routine was musttail called [PR119376]
    
    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.).
    
    2025-03-21  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.

Diff:
---
 gcc/testsuite/c-c++-common/musttail26.c | 33 +++++++++++++++++++++++++++++++++
 gcc/tree-inline.cc                      |  9 +++++++++
 2 files changed, 42 insertions(+)

diff --git a/gcc/testsuite/c-c++-common/musttail26.c 
b/gcc/testsuite/c-c++-common/musttail26.c
new file mode 100644
index 000000000000..3d0f8c97d9b3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/musttail26.c
@@ -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;
+}
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index 5b3539009a38..05843b8ccf09 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -1892,6 +1892,15 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
            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))
              {

Reply via email to