diff options
-rw-r--r-- | gcc/testsuite/c-c++-common/musttail26.c | 33 | ||||
-rw-r--r-- | gcc/tree-inline.cc | 9 |
2 files changed, 42 insertions, 0 deletions
diff --git a/gcc/testsuite/c-c++-common/musttail26.c b/gcc/testsuite/c-c++-common/musttail26.c new file mode 100644 index 0000000..3d0f8c9 --- /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 5b35390..05843b8 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)) { |