Hi! The just posted inliner patch can regress musttail calls if we perform function splitting and then inline the outlined body back into the original (or inline both the small function and outlined large body into something else). If there are any musttail calls, I think we need to call the outlined body using a musttail call, so that the inliner will preserve musttail attributes in the body.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2025-03-20 Jakub Jelinek <ja...@redhat.com> PR ipa/119376 * ipa-split.cc (split_function): Call gimple_call_set_must_tail on the call to outlined partition if has_musttail and !add_tsan_func_exit. * g++.dg/opt/musttail1.C: New test. --- gcc/ipa-split.cc.jj 2025-01-02 11:23:02.827707968 +0100 +++ gcc/ipa-split.cc 2025-03-20 13:54:57.541594191 +0100 @@ -1473,6 +1473,8 @@ split_function (basic_block return_bb, c args_to_pass[i] = arg; } call = gimple_build_call_vec (node->decl, args_to_pass); + if (cur_node->get_fun ()->has_musttail && !add_tsan_func_exit) + gimple_call_set_must_tail (call, true); gimple_set_block (call, DECL_INITIAL (current_function_decl)); args_to_pass.release (); --- gcc/testsuite/g++.dg/opt/musttail1.C.jj 2025-03-20 15:07:38.236255098 +0100 +++ gcc/testsuite/g++.dg/opt/musttail1.C 2025-03-20 15:08:48.625280661 +0100 @@ -0,0 +1,35 @@ +// PR ipa/119376 +// { dg-do compile { target musttail } } +// { dg-options "-O2 -fdump-tree-optimized" } +// { dg-final { scan-tree-dump-times " \[^\n\r]* = foo \\\(\[^\n\r]*\\\); \\\[tail call\\\] \\\[must tail call\\\]" 2 "optimized" } } +// { dg-final { scan-tree-dump-times " \[^\n\r]* = foo \\\(\[^\n\r]*\\\); \\\[tail call\\\]" 3 "optimized" } } + +int foo (int x); +typedef int (*F) (int); +int v; + +inline int +bar (int x) +{ + if (__builtin_expect (x == 42, 1)) + return 1; + [[gnu::musttail]] return foo (x + v * (x | v) * (x & v) * (x - v) * (x + v * v)); +} + +int +baz (int x) +{ + [[gnu::musttail]] return bar (x); +} + +int +qux (int x) +{ + return bar (x + 1); +} + +F +corge () +{ + return &bar; +} Jakub