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.

Co-authored-by: Andrew Pinski

        PR 118442

gcc/ChangeLog:

        * tree-cfg.cc (stmt_can_terminate_bb_p):

gcc/testsuite/ChangeLog:

        * c-c++-common/pr118442.c: New test.
---
 gcc/input.cc                          |  2 ++
 gcc/testsuite/c-c++-common/pr118442.c | 15 +++++++++++++++
 gcc/tree-cfg.cc                       |  7 +++++++
 3 files changed, 24 insertions(+)
 create mode 100644 gcc/testsuite/c-c++-common/pr118442.c

diff --git a/gcc/input.cc b/gcc/input.cc
index fabfbfb6eaa..d3b12037ba8 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -1325,6 +1325,8 @@ dump_line_table_statistics (void)
   if (s.num_expanded_macros != 0)
     fprintf (stderr, "Average number of tokens per macro expansion:  %5ld\n",
              s.num_macro_tokens / s.num_expanded_macros);
+  fprintf (stderr, "Number of expanded tokens:           " PRsa (5) "\n",
+          SIZE_AMOUNT (s.num_macro_tokens));
   fprintf (stderr,
            "\nLine Table allocations during the "
           "compilation process\n");
diff --git a/gcc/testsuite/c-c++-common/pr118442.c 
b/gcc/testsuite/c-c++-common/pr118442.c
new file mode 100644
index 00000000000..9554583bec5
--- /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;
+    [[clang::musttail]] return resolveToBufferSlow(buffer);
+}
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 2fa5678051a..006a34b104b 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -8871,6 +8871,13 @@ stmt_can_terminate_bb_p (gimple *t)
       edge e;
       basic_block bb;
 
+      /* 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.  */
+      if (gimple_call_must_tail_p (as_a <const gcall *> (t)))
+       return false;
+
       if (call_flags & (ECF_PURE | ECF_CONST)
          && !(call_flags & ECF_LOOPING_CONST_OR_PURE))
        return false;
-- 
2.47.1

Reply via email to