An IPA split clone can have no early DIE of its own.  In that case
dwarf2out_die_ref_for_decl fails to stream an external DIE reference for
the clone.  During LTO merging, the function origin can then resolve to
the prevailing TU while direct parameters and local variables retain
origins from the physical input TU.  This leaves an out-of-line split-clone
DW_TAG_subprogram and its direct children referring to different input TUs.

When lookup_decl_die fails for a compiler-generated FUNCTION_DECL, use the
early DIE of its ultimate abstract origin.  The existing external-DIE
streaming machinery then preserves the clone's input TU provenance.  Limit
the fallback to artificial functions because the C front end also uses
DECL_ABSTRACT_ORIGIN for nested redeclarations.

Tested on x86_64-pc-linux-gnu.  The added test fails before the change
and passes afterwards.

        PR debug/126348

gcc/ChangeLog:

        * dwarf2out.cc (dwarf2out_die_ref_for_decl): Fall back to the
        ultimate abstract origin's early DIE for artificial function clones
        without an early DIE.

gcc/testsuite/ChangeLog:

        * g++.dg/lto/pr126348.h: New test.
        * g++.dg/lto/pr126348_0.C: Likewise.
        * g++.dg/lto/pr126348_1.C: Likewise.

Signed-off-by: Longjun Luo <[email protected]>
---
 gcc/dwarf2out.cc                      | 18 +++++++++++---
 gcc/testsuite/g++.dg/lto/pr126348.h   | 28 +++++++++++++++++++++
 gcc/testsuite/g++.dg/lto/pr126348_0.C | 23 +++++++++++++++++
 gcc/testsuite/g++.dg/lto/pr126348_1.C | 36 +++++++++++++++++++++++++++
 4 files changed, 102 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126348.h
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_0.C
 create mode 100644 gcc/testsuite/g++.dg/lto/pr126348_1.C

diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 0b974d63c80..a603d0d9420 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -6034,8 +6034,8 @@ equate_block_to_die (tree block, dw_die_ref die)
 
 
 /* For DECL which might have early dwarf output query a SYMBOL + OFFSET
-   style reference.  Return true if we found one referring to a DIE for
-   DECL, otherwise return false.  */
+   style reference.  Return true if a suitable DIE reference is found,
+   otherwise return false.  */
 
 static bool
 dwarf2out_die_ref_for_decl (tree decl, const char **sym,
@@ -6060,7 +6060,19 @@ dwarf2out_die_ref_for_decl (tree decl, const char **sym,
   if (TREE_CODE (decl) == BLOCK)
     die = lookup_block_die (decl);
   else
-    die = lookup_decl_die (decl);
+    {
+      die = lookup_decl_die (decl);
+      if (!die
+         && TREE_CODE (decl) == FUNCTION_DECL
+         && DECL_ARTIFICIAL (decl))
+       {
+         /* An LTO clone can have no early DIE of its own.  The early DIE of
+            its abstract origin retains the input TU provenance.  */
+         tree origin = decl_ultimate_origin (decl);
+         if (origin && origin != decl)
+           die = lookup_decl_die (origin);
+       }
+    }
   if (!die)
     return false;
 
diff --git a/gcc/testsuite/g++.dg/lto/pr126348.h 
b/gcc/testsuite/g++.dg/lto/pr126348.h
new file mode 100644
index 00000000000..eac6698064a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348.h
@@ -0,0 +1,28 @@
+struct Location
+{
+  const char *file;
+  const char *function;
+  int line;
+};
+
+extern void fail (int, const char *, const Location &)
+  __attribute__ ((noreturn, cold, noipa));
+extern void note (const char *, int) __attribute__ ((cold, noipa));
+
+static const char source_file[] = __BASE_FILE__;
+
+struct Buffer
+{
+  int length;
+
+  int printable_length () const
+  {
+    if (__builtin_expect (length < 1024, 1))
+      return length;
+    const Location location = { source_file, __func__, __LINE__ };
+    note (location.file, location.line);
+    note (location.function, length);
+    note (location.file, length + 1);
+    fail (3, "length < 1024", location);
+  }
+};
diff --git a/gcc/testsuite/g++.dg/lto/pr126348_0.C 
b/gcc/testsuite/g++.dg/lto/pr126348_0.C
new file mode 100644
index 00000000000..b532dda0f47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348_0.C
@@ -0,0 +1,23 @@
+/* PR debug/126348 */
+/* Verify that an out-of-line split function and its direct children retain
+   the same input TU provenance.  */
+/* { dg-lto-do link } */
+/* { dg-skip-if "No DWARF debug support" { hppa*-*-hpux* } } */
+/* { dg-skip-if "AIX DWARF5" { powerpc-ibm-aix* } } */
+/* { dg-lto-options { { -O2 -g -gdwarf-5 -dA -save-temps -flto 
-flto-partition=one -fno-ipa-icf } } } */
+/* { dg-final { scan-lto-assembler 
"DW_TAG_subprogram\\)\n\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin\n(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)\n\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin\n(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)\n\[^\n\]*pr126348_0\[^\n\]*DW_AT_abstract_origin"
 } } */
+/* { dg-final { scan-lto-assembler 
"DW_TAG_subprogram\\)\n\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin\n(?:\[^\n\]*\n){1,8}\[^\n\]*DW_TAG_formal_parameter\\)\n\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin\n(?:\[^\n\]*\n){1,4}\[^\n\]*DW_TAG_variable\\)\n\[^\n\]*pr126348_1\[^\n\]*DW_AT_abstract_origin"
 } } */
+
+#include "pr126348.h"
+
+__attribute__ ((noinline)) int
+one (const Buffer &buffer)
+{
+  return buffer.printable_length ();
+}
+
+__attribute__ ((noinline)) int
+one_extra (const Buffer &buffer)
+{
+  return buffer.printable_length ();
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126348_1.C 
b/gcc/testsuite/g++.dg/lto/pr126348_1.C
new file mode 100644
index 00000000000..f4aeafa6435
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126348_1.C
@@ -0,0 +1,36 @@
+#include "pr126348.h"
+
+__attribute__ ((noinline)) int one (const Buffer &);
+__attribute__ ((noinline)) int one_extra (const Buffer &);
+
+void
+fail (int, const char *, const Location &)
+{
+  __builtin_trap ();
+}
+
+void
+note (const char *, int)
+{
+  asm volatile ("" ::: "memory");
+}
+
+__attribute__ ((noinline)) int
+two (const Buffer &buffer)
+{
+  return buffer.printable_length ();
+}
+
+__attribute__ ((noinline)) int
+two_extra (const Buffer &buffer)
+{
+  return buffer.printable_length ();
+}
+
+int
+main (int argc, char **)
+{
+  Buffer buffer = { argc };
+  return one (buffer) + one_extra (buffer)
+         + two (buffer) + two_extra (buffer);
+}
-- 
2.43.7

Reply via email to