From: Andi Kleen <a...@gcc.gnu.org> When -fprofile-generate is used musttail often fails because the compiler adds instrumentation after the tail calls.
This patch prevents adding exit extra edges after musttail because for a tail call the execution leaves the function and can never come back even on a unwind or exception. This is only done for musttail. In principle it could be done for any tail calls, but the problem is that there might be other reasons why the tail fails later, and then the edge might be still needed. Passes bootstrap and full testing on x86_64 with no new failures. [v2 version: Don't affect stmt_can_terminate_bb_p. Fix changelog. Adjust test case for clang:: removal.] Co-authored-by: Andrew Pinski gcc/ChangeLog: PR gcov-profile/118442 * tree-cfg.cc (must_tail_call_p): New function. (gimple_flow_call_edges_add): Avoid exit edges for musttail calls. gcc/testsuite/ChangeLog: * c-c++-common/pr118442.c: New test. --- gcc/testsuite/c-c++-common/pr118442.c | 15 +++++++++++++++ gcc/tree-cfg.cc | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/pr118442.c diff --git a/gcc/testsuite/c-c++-common/pr118442.c b/gcc/testsuite/c-c++-common/pr118442.c new file mode 100644 index 00000000000..24b7f546c98 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr118442.c @@ -0,0 +1,15 @@ +/* PR118442 */ +/* { dg-do compile { target { struct_musttail && { c || c++11 } } } } */ +/* { dg-options "-fprofile-generate -O2" } */ + +struct Span { + int test[5]; +}; + +void resolveToBufferSlow(struct Span *buffer); + +void resolveToBuffer(struct Span *buffer) +{ + buffer->test[0] = 4; + [[gnu::musttail]] return resolveToBufferSlow(buffer); +} diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 2fa5678051a..85c8082c297 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -8894,6 +8894,18 @@ stmt_can_terminate_bb_p (gimple *t) return false; } +/* Is T a gimple must tail call? */ + +static bool +must_tail_call_p (gimple *t) +{ + /* When it's a enforced tail call there is no edge because + the control flow has left the function and can never come back. + This prevents instrumenting the edge which would make the must + tail call fail. */ + return is_gimple_call (t) + && gimple_call_must_tail_p (as_a <const gcall *> (t)); +} /* Add fake edges to the function exit for any non constant and non noreturn calls (or noreturn calls with EH/abnormal edges), @@ -8942,7 +8954,7 @@ gimple_flow_call_edges_add (sbitmap blocks) if (!gsi_end_p (gsi)) t = gsi_stmt (gsi); - if (t && stmt_can_terminate_bb_p (t)) + if (t && stmt_can_terminate_bb_p (t) && !must_tail_call_p (t)) { edge e; @@ -8977,7 +8989,7 @@ gimple_flow_call_edges_add (sbitmap blocks) do { stmt = gsi_stmt (gsi); - if (stmt_can_terminate_bb_p (stmt)) + if (stmt_can_terminate_bb_p (stmt) && !must_tail_call_p (stmt)) { edge e; -- 2.47.1