[llvm-branch-commits] [llvm] 7f2f829 - Revert sharing subprograms across CUs

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Aug 23 11:19:13 PDT 2021


Author: Jeremy Morse
Date: 2021-08-23T11:18:57-07:00
New Revision: 7f2f829479dcb4254149670cc3b16f89a85127bb

URL: https://github.com/llvm/llvm-project/commit/7f2f829479dcb4254149670cc3b16f89a85127bb
DIFF: https://github.com/llvm/llvm-project/commit/7f2f829479dcb4254149670cc3b16f89a85127bb.diff

LOG: Revert sharing subprograms across CUs

This patch is a revert of e08f205f5c2c. In that patch, DW_TAG_subprograms
were permitted to be referenced across CU boundaries, to improve stack
trace construction using call site information. Unfortunately, as
documented in PR48790, the way that subprograms are "owned" by dwarf units
is sufficiently complicated that subprograms end up in unexpected units,
invalidating cross-unit references.

There's no obvious way to easily fix this, and several attempts have
failed. Revert this to ensure correct DWARF is always emitted.

Three tests change in addition to the reversion, but they're all very
light alterations.

Differential Revision: https://reviews.llvm.org/D107076

(cherry picked from commit d4ce9e463d51b18547dbd181884046abf77c5c91)
Signed-off-by: Jeremy Morse <jeremy.morse at sony.com>

Conflicts:
	llvm/test/DebugInfo/X86/convert-loclist.ll

Added: 
    llvm/test/DebugInfo/X86/subprogram-across-cus.ll

Modified: 
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
    llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
    llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir
    llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir
    llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir
    llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir
    llvm/test/DebugInfo/X86/convert-loclist.ll

Removed: 
    llvm/test/DebugInfo/AArch64/unretained-declaration-subprogram.ll
    llvm/test/DebugInfo/X86/fission-call-site.ll
    llvm/test/DebugInfo/X86/lto-cross-cu-call-origin-ref.ll


################################################################################
diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index faa14dca1c3f1..7edc44c48bbd6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -1162,7 +1162,7 @@ DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const {
 }
 
 DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
-                                                 DIE *CalleeDIE,
+                                                 const DISubprogram *CalleeSP,
                                                  bool IsTail,
                                                  const MCSymbol *PCAddr,
                                                  const MCSymbol *CallAddr,
@@ -1176,7 +1176,8 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE,
     addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target),
                MachineLocation(CallReg));
   } else {
-    assert(CalleeDIE && "No DIE for call site entry origin");
+    DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP);
+    assert(CalleeDIE && "Could not create DIE for call site entry origin");
     addDIEEntry(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_origin),
                 *CalleeDIE);
   }

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index 6d8186a5ee2b3..6e9261087686b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -249,16 +249,14 @@ class DwarfCompileUnit final : public DwarfUnit {
   dwarf::LocationAtom getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const;
 
   /// Construct a call site entry DIE describing a call within \p Scope to a
-  /// callee described by \p CalleeDIE.
-  /// \p CalleeDIE is a declaration or definition subprogram DIE for the callee.
-  /// For indirect calls \p CalleeDIE is set to nullptr.
+  /// callee described by \p CalleeSP.
   /// \p IsTail specifies whether the call is a tail call.
   /// \p PCAddr points to the PC value after the call instruction.
   /// \p CallAddr points to the PC value at the call instruction (or is null).
   /// \p CallReg is a register location for an indirect call. For direct calls
   /// the \p CallReg is set to 0.
-  DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail,
-                                 const MCSymbol *PCAddr,
+  DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP,
+                                 bool IsTail, const MCSymbol *PCAddr,
                                  const MCSymbol *CallAddr, unsigned CallReg);
   /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params
   /// were collected by the \ref collectCallSiteParameters.

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index ee14423ca3d05..52591a18791f2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -587,14 +587,6 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU,
   }
 }
 
-DIE &DwarfDebug::constructSubprogramDefinitionDIE(const DISubprogram *SP) {
-  DICompileUnit *Unit = SP->getUnit();
-  assert(SP->isDefinition() && "Subprogram not a definition");
-  assert(Unit && "Subprogram definition without parent unit");
-  auto &CU = getOrCreateDwarfCompileUnit(Unit);
-  return *CU.getOrCreateSubprogramDIE(SP);
-}
-
 /// Represents a parameter whose call site value can be described by applying a
 /// debug expression to a register in the forwarded register worklist.
 struct FwdRegParamInfo {
@@ -945,7 +937,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
         continue;
 
       unsigned CallReg = 0;
-      DIE *CalleeDIE = nullptr;
+      const DISubprogram *CalleeSP = nullptr;
       const Function *CalleeDecl = nullptr;
       if (CalleeOp.isReg()) {
         CallReg = CalleeOp.getReg();
@@ -955,19 +947,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
         CalleeDecl = dyn_cast<Function>(CalleeOp.getGlobal());
         if (!CalleeDecl || !CalleeDecl->getSubprogram())
           continue;
-        const DISubprogram *CalleeSP = CalleeDecl->getSubprogram();
-
-        if (CalleeSP->isDefinition()) {
-          // Ensure that a subprogram DIE for the callee is available in the
-          // appropriate CU.
-          CalleeDIE = &constructSubprogramDefinitionDIE(CalleeSP);
-        } else {
-          // Create the declaration DIE if it is missing. This is required to
-          // support compilation of old bitcode with an incomplete list of
-          // retained metadata.
-          CalleeDIE = CU.getOrCreateSubprogramDIE(CalleeSP);
-        }
-        assert(CalleeDIE && "Must have a DIE for the callee");
+        CalleeSP = CalleeDecl->getSubprogram();
       }
 
       // TODO: Omit call site entries for runtime calls (objc_msgSend, etc).
@@ -1004,7 +984,7 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
                         << (IsTail ? " [IsTail]" : "") << "\n");
 
       DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(
-          ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg);
+          ScopeDIE, CalleeSP, IsTail, PCAddr, CallAddr, CallReg);
 
       // Optionally emit call-site-param debug info.
       if (emitDebugEntryValues()) {
@@ -1121,6 +1101,11 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
     NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection());
   }
 
+  // Create DIEs for function declarations used for call site debug info.
+  for (auto Scope : DIUnit->getRetainedTypes())
+    if (auto *SP = dyn_cast_or_null<DISubprogram>(Scope))
+      NewCU.getOrCreateSubprogramDIE(SP);
+
   CUMap.insert({DIUnit, &NewCU});
   CUDieMap.insert({&NewCU.getUnitDie(), &NewCU});
   return NewCU;

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 6356a65b50d38..b55be799b6bcc 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -471,9 +471,6 @@ class DwarfDebug : public DebugHandlerBase {
   /// Construct a DIE for this abstract scope.
   void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope);
 
-  /// Construct a DIE for the subprogram definition \p SP and return it.
-  DIE &constructSubprogramDefinitionDIE(const DISubprogram *SP);
-
   /// Construct DIEs for call site entries describing the calls in \p MF.
   void constructCallSiteEntryDIEs(const DISubprogram &SP, DwarfCompileUnit &CU,
                                   DIE &ScopeDIE, const MachineFunction &MF);

diff  --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 344d30fad3471..9d7b3d6e18910 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -186,9 +186,8 @@ int64_t DwarfUnit::getDefaultLowerBound() const {
 
 /// Check whether the DIE for this MDNode can be shared across CUs.
 bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const {
-  // When the MDNode can be part of the type system (this includes subprogram
-  // declarations *and* subprogram definitions, even local definitions), the
-  // DIE must be shared across CUs.
+  // When the MDNode can be part of the type system, the DIE can be shared
+  // across CUs.
   // Combining type units and cross-CU DIE sharing is lower value (since
   // cross-CU DIE sharing is used in LTO and removes type redundancy at that
   // level already) but may be implementable for some value in projects
@@ -196,7 +195,9 @@ bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const {
   // together.
   if (isDwoUnit() && !DD->shareAcrossDWOCUs())
     return false;
-  return (isa<DIType>(D) || isa<DISubprogram>(D)) && !DD->generateTypeUnits();
+  return (isa<DIType>(D) ||
+          (isa<DISubprogram>(D) && !cast<DISubprogram>(D)->isDefinition())) &&
+         !DD->generateTypeUnits();
 }
 
 DIE *DwarfUnit::getDIE(const DINode *D) const {

diff  --git a/llvm/test/DebugInfo/AArch64/unretained-declaration-subprogram.ll b/llvm/test/DebugInfo/AArch64/unretained-declaration-subprogram.ll
deleted file mode 100644
index 17ead0e812421..0000000000000
--- a/llvm/test/DebugInfo/AArch64/unretained-declaration-subprogram.ll
+++ /dev/null
@@ -1,44 +0,0 @@
-; RUN: llc -mtriple=arm64-apple-ios -filetype=obj < %s -o %t.o
-; RUN: llvm-dwarfdump %t.o | FileCheck %s -implicit-check-not=DW_TAG_subprogram
-
-; The declaration subprogram for "function" is not in the CU's list of
-; retained types. Test that a DWARF call site entry can still be constructed.
-
-; CHECK: DW_TAG_subprogram
-; CHECK:   DW_AT_name {{.*}}__hidden#3_
-; CHECK:   DW_TAG_call_site
-; CHECK:     DW_AT_call_origin (0x{{0+}}[[FUNCTION_DIE:.*]])
-
-; CHECK: 0x{{0+}}[[FUNCTION_DIE]]: DW_TAG_subprogram
-; CHECK:   DW_AT_name {{.*}}function
-
-target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
-target triple = "arm64-apple-ios9.0.0"
-
-define i32 @main() local_unnamed_addr !dbg !8 {
-  %1 = tail call [2 x i64] @function([2 x i64] zeroinitializer), !dbg !11
-  %2 = extractvalue [2 x i64] %1, 0, !dbg !11
-  %3 = trunc i64 %2 to i32, !dbg !11
-  ret i32 %3, !dbg !12
-}
-
-declare !dbg !13 [2 x i64] @function([2 x i64]) local_unnamed_addr
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4}
-!llvm.dbg.cu = !{!5}
-!llvm.ident = !{!7}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 4]}
-!1 = !{i32 7, !"Dwarf Version", i32 4}
-!2 = !{i32 2, !"Debug Info Version", i32 3}
-!3 = !{i32 1, !"wchar_size", i32 4}
-!4 = !{i32 7, !"PIC Level", i32 2}
-!5 = distinct !DICompileUnit(language: DW_LANG_C99, file: !6, producer: "__hidden#0_", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, nameTableKind: None)
-!6 = !DIFile(filename: "__hidden#1_", directory: "__hidden#2_")
-!7 = !{!"Apple clang version 11.0.0 (llvm-project fa407d93fd5e618d76378c1ce4e4f517e0563278) (+internal-os)"}
-!8 = distinct !DISubprogram(name: "__hidden#3_", scope: !6, file: !6, line: 9, type: !9, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !5)
-!9 = !DISubroutineType(types: !10)
-!10 = !{}
-!11 = !DILocation(line: 12, column: 10, scope: !8)
-!12 = !DILocation(line: 13, column: 3, scope: !8)
-!13 = !DISubprogram(name: "function", scope: !6, file: !6, line: 7, type: !9, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)

diff  --git a/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir b/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir
index 555effc3ccb10..ab0b58c893321 100644
--- a/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir
+++ b/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-indirect-param.mir
@@ -21,6 +21,10 @@
 
 # After w0 is clobbered, we should get an indirect parameter entry value for "f".
 
+# DWARF-LABEL: DW_TAG_subprogram
+# DWARF:       DW_AT_name ("baz")
+
+# DWARF-LABEL: DW_TAG_subprogram
 # DWARF-LABEL: DW_TAG_formal_parameter
 # DWARF-NEXT: DW_AT_location
 # DWARF-NEXT: [0x0000000000000000, 0x0000000000000010): DW_OP_breg0 W0+0

diff  --git a/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir b/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir
index 22a3442d6d4cd..dc774ee8f7940 100644
--- a/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir
+++ b/llvm/test/DebugInfo/MIR/AArch64/dbgcall-site-orr-moves.mir
@@ -159,7 +159,7 @@ body:             |
 ...
 
 # CHECK: DW_TAG_GNU_call_site
-# CHECK-NEXT: DW_AT_abstract_origin ({{.*}} "call_int")
+# CHECK-NEXT: DW_AT_abstract_origin (0x0000002a "call_int")
 #
 # CHECK: DW_TAG_GNU_call_site_parameter
 # CHECK-NEXT: DW_AT_location      (DW_OP_reg0 W0)
@@ -205,7 +205,7 @@ body:             |
 ...
 
 # CHECK: DW_TAG_GNU_call_site
-# CHECK-NEXT: DW_AT_abstract_origin ({{.*}} "call_long")
+# CHECK-NEXT: DW_AT_abstract_origin (0x0000003e "call_long")
 #
 # CHECK: DW_TAG_GNU_call_site_parameter
 # CHECK-NEXT: DW_AT_location      (DW_OP_reg0 W0)
@@ -265,7 +265,7 @@ body:             |
 ...
 
 # CHECK: DW_TAG_GNU_call_site
-# CHECK-NEXT: DW_AT_abstract_origin ({{.*}} "call_int_int")
+# CHECK-NEXT: DW_AT_abstract_origin (0x00000052 "call_int_int")
 #
 # CHECK: DW_TAG_GNU_call_site_parameter
 # CHECK-NEXT: DW_AT_location      (DW_OP_reg0 W0)

diff  --git a/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir b/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir
index 4362f8e66b214..fd26d958dc86a 100644
--- a/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir
+++ b/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir
@@ -1,8 +1,12 @@
 # RUN: llc -start-after=livedebugvalues -mtriple=x86_64-apple-darwin -o - %s -filetype=obj \
 # RUN:   -emit-call-site-info | llvm-dwarfdump - | FileCheck %s -implicit-check-not=call_site_parameter
 
-# CHECK: DW_TAG_formal_parameter
-# CHECK-NEXT: DW_AT_location (DW_OP_reg17 XMM0)
+# CHECK-LABEL: DW_TAG_subprogram
+# CHECK:       DW_AT_name ("f")
+# CHECK-LABEL: DW_TAG_subprogram
+# CHECK:       DW_AT_name ("g")
+# CHECK:       DW_TAG_formal_parameter
+# CHECK-NEXT:  DW_AT_location (DW_OP_reg17 XMM0)
 
 # struct S {
 #   float w;

diff  --git a/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir b/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir
index dd6f0d57d3a0e..627ccd62d90b2 100644
--- a/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir
+++ b/llvm/test/DebugInfo/MIR/X86/debug-call-site-param.mir
@@ -39,11 +39,17 @@
 # CHECK-GNU-NEXT:      DW_AT_location      (DW_OP_reg8 R8)
 # CHECK-GNU-NEXT:      DW_AT_GNU_call_site_value   (DW_OP_breg14 R14+3)
 
-# CHECK-DWARF5: DW_TAG_call_site
-# CHECK-DWARF5:   DW_AT_call_origin ([[getValue_SP:.*]])
+# CHECK-DWARF5: [[getValue_SP:.*]]: DW_TAG_subprogram
+# CHECK-DWARF5-NEXT: DW_AT_name      ("getVal")
 
+# CHECK-DWARF5: [[foo_SP:.*]]: DW_TAG_subprogram
+# CHECK-DWARF5-NEXT: DW_AT_name      ("foo")
+
+# CHECK-DWARF5: DW_TAG_call_site
+# CHECK-DWARF5:   DW_AT_call_origin ([[getValue_SP]])
+#
 # CHECK-DWARF5: DW_TAG_call_site
-# CHECK-DWARF5:   DW_AT_call_origin ([[foo_SP:.*]])
+# CHECK-DWARF5:   DW_AT_call_origin ([[foo_SP]])
 # CHECK-DWARF5:   DW_AT_call_return_pc {{.*}}
 # CHECK-DWARF5-EMPTY:
 # CHECK-DWARF5:         DW_TAG_call_site_parameter
@@ -65,12 +71,6 @@
 # CHECK-DWARF5-NEXT:      DW_AT_location      (DW_OP_reg8 R8)
 # CHECK-DWARF5-NEXT:      DW_AT_call_value   (DW_OP_breg14 R14+3)
 
-# CHECK-DWARF5: [[getValue_SP]]: DW_TAG_subprogram
-# CHECK-DWARF5-NEXT: DW_AT_name      ("getVal")
-
-# CHECK-DWARF5: [[foo_SP]]: DW_TAG_subprogram
-# CHECK-DWARF5-NEXT: DW_AT_name      ("foo")
-
 --- |
   ; ModuleID = 'test.c'
   source_filename = "test.c"

diff  --git a/llvm/test/DebugInfo/X86/convert-loclist.ll b/llvm/test/DebugInfo/X86/convert-loclist.ll
index b34e0420fb92f..4324d73d040c6 100644
--- a/llvm/test/DebugInfo/X86/convert-loclist.ll
+++ b/llvm/test/DebugInfo/X86/convert-loclist.ll
@@ -13,7 +13,7 @@
 ; often - add another IR file with a 
diff erent DW_OP_convert that's otherwise
 ; identical and demonstrate that they have 
diff erent DWO IDs.
 
-; SPLIT: 0x00000000: Compile Unit: {{.*}} DWO_id = 0xafd73565c68bc661
+; SPLIT: 0x00000000: Compile Unit: {{.*}} DWO_id = 0x194b4f2ceea8a1a0
 
 ; Regression testing a fairly quirky bug where instead of hashing (see above),
 ; extra bytes would be emitted into the output assembly in no

diff  --git a/llvm/test/DebugInfo/X86/fission-call-site.ll b/llvm/test/DebugInfo/X86/fission-call-site.ll
deleted file mode 100644
index 65e2ef62dd711..0000000000000
--- a/llvm/test/DebugInfo/X86/fission-call-site.ll
+++ /dev/null
@@ -1,68 +0,0 @@
-; Check that call site entries are emitted correctly when using split-dwarf
-; together with some form of LTO.
-
-; Original C source:
-;
-; // cu1.c
-; extern void callee(void);
-; void caller(void) {
-;   callee();
-; }
-;
-; // cu2.c
-; __attribute__((optnone)) void callee(void) {}
-;
-; Steps to reproduce:
-;
-; (The -O1 here is needed to trigger call site entry emission, as these tags are
-; generally not emitted at -O0.)
-;
-; clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=split -O1 ~/tmp/cu1.c -S -emit-llvm -o ~/tmp/cu1.ll
-; clang -target x86_64-unknown-linux-gnu -gsplit-dwarf=split -O1 ~/tmp/cu2.c -S -emit-llvm -o ~/tmp/cu2.ll
-; llvm-link -o ~/tmp/cu-merged.bc ~/tmp/cu1.ll ~/tmp/cu2.ll
-; llc -split-dwarf-file=foo.dwo -O0 -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o - ~/tmp/cu-merged.bc
-
-; RUN: llc -split-dwarf-file=foo.dwo -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t
-; RUN: llvm-dwarfdump %t | FileCheck %s
-
-; CHECK: DW_TAG_GNU_call_site
-; CHECK-NEXT: DW_AT_abstract_origin {{.*}} "callee"
-
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-define dso_local void @caller() local_unnamed_addr !dbg !14 {
-entry:
-  call void @callee(), !dbg !15
-  ret void, !dbg !16
-}
-
-define dso_local void @callee() local_unnamed_addr noinline optnone !dbg !17 {
-entry:
-  ret void, !dbg !19
-}
-
-!llvm.dbg.cu = !{!0, !8}
-!llvm.ident = !{!10, !10}
-!llvm.module.flags = !{!11, !12, !13}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (git at github.com:llvm/llvm-project.git 170f4b972e7bcf1f2af98bdd7145954efd16e038)", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "cu1.dwo", emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: GNU)
-!1 = !DIFile(filename: "/Users/vsk/tmp/cu1.c", directory: "/Users/vsk/src/builds/llvm-project-master-RA")
-!2 = !{}
-!3 = !{!4}
-!4 = !DISubprogram(name: "callee", scope: !5, file: !5, line: 1, type: !6, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
-!5 = !DIFile(filename: "tmp/cu1.c", directory: "/Users/vsk")
-!6 = !DISubroutineType(types: !7)
-!7 = !{null}
-!8 = distinct !DICompileUnit(language: DW_LANG_C99, file: !9, producer: "clang version 11.0.0 (git at github.com:llvm/llvm-project.git 170f4b972e7bcf1f2af98bdd7145954efd16e038)", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "cu2.dwo", emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: GNU)
-!9 = !DIFile(filename: "/Users/vsk/tmp/cu2.c", directory: "/Users/vsk/src/builds/llvm-project-master-RA")
-!10 = !{!"clang version 11.0.0 (git at github.com:llvm/llvm-project.git 170f4b972e7bcf1f2af98bdd7145954efd16e038)"}
-!11 = !{i32 7, !"Dwarf Version", i32 4}
-!12 = !{i32 2, !"Debug Info Version", i32 3}
-!13 = !{i32 1, !"wchar_size", i32 4}
-!14 = distinct !DISubprogram(name: "caller", scope: !5, file: !5, line: 2, type: !6, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
-!15 = !DILocation(line: 3, column: 3, scope: !14)
-!16 = !DILocation(line: 4, column: 1, scope: !14)
-!17 = distinct !DISubprogram(name: "callee", scope: !18, file: !18, line: 1, type: !6, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !8, retainedNodes: !2)
-!18 = !DIFile(filename: "tmp/cu2.c", directory: "/Users/vsk")
-!19 = !DILocation(line: 1, column: 45, scope: !17)

diff  --git a/llvm/test/DebugInfo/X86/lto-cross-cu-call-origin-ref.ll b/llvm/test/DebugInfo/X86/lto-cross-cu-call-origin-ref.ll
deleted file mode 100644
index 00715841ab5c0..0000000000000
--- a/llvm/test/DebugInfo/X86/lto-cross-cu-call-origin-ref.ll
+++ /dev/null
@@ -1,211 +0,0 @@
-; RUN: llc -mtriple=x86_64-apple-darwin -filetype=obj < %s -o %t.o
-; RUN: llvm-dwarfdump %t.o | FileCheck %s -implicit-check-not=DW_TAG_subprogram
-; RUN: llvm-dwarfdump --verify %t.o
-
-; This test checks that cross-CU references within call site tags to subprogram
-; definitions are well-formed. There are 5 cases checked in this test. Each set
-; of checks is numbered and has a brief summary.
-
-; Instructions to regenerate the IR:
-; clang -O1 -g -emit-llvm -o a.bc -c a.c
-; clang -O1 -g -emit-llvm -o b.bc -c b.c
-; llvm-link -o linked.bc a.bc b.bc
-; opt -O1 linked.bc -o merged.bc
-
-; Source:
-; // a.c
-; __attribute__((optnone)) void noinline_func_in_a() {}
-;
-; __attribute__((optnone)) static void foo() {}
-; __attribute__((always_inline)) void always_inline_helper_in_a_that_calls_foo() {
-;   foo();
-; }
-;
-; extern void func_from_b();
-; void call_func_in_b_from_a() {
-;   func_from_b();
-; }
-;
-; // b.c
-; extern void noinline_func_in_a();
-; void call_noinline_func_in_a_from_b() {
-;   noinline_func_in_a();
-; }
-;
-; __attribute__((optnone)) void foo() {}
-; extern void always_inline_helper_in_a_that_calls_foo();
-; void call_both_foos_from_b() {
-;   foo();
-;   always_inline_helper_in_a_that_calls_foo();
-; }
-;
-; __attribute__((optnone)) void func_from_b() {}
-; void call_func_in_b_from_b() {
-;   func_from_b();
-; }
-
-; === CU for a.c ===
-
-; CHECK: DW_TAG_compile_unit
-; CHECK:   DW_AT_name ("a.c")
-
-; CHECK: 0x{{0+}}[[NOINLINE_FUNC_IN_A:.*]]: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("noinline_func_in_a")
-
-; 1) Check that "always_inline_helper_in_a_that_calls_foo" calls the "foo" in
-; a.c, and *not* the "foo" in b.c.
-; CHECK: 0x{{0+}}[[ALWAYS_INLINE_HELPER_IN_A:.*]]: DW_TAG_subprogram
-; CHECK:   DW_AT_abstract_origin ({{.*}} "always_inline_helper_in_a_that_calls_foo")
-; CHECK:   DW_TAG_call_site
-; CHECK-NEXT: DW_AT_call_origin (0x{{0+}}[[FOO_IN_A:.*]])
-
-; CHECK: 0x{{0+}}[[FOO_IN_A]]: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("foo")
-
-; 2) Check that "call_func_in_b_from_a" has a cross-CU ref into b.c.
-; CHECK: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("call_func_in_b_from_a")
-; CHECK:   DW_TAG_call_site
-; CHECK-NEXT: DW_AT_call_origin (0x{{0+}}[[FUNC_FROM_B:.*]])
-
-; CHECK: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("always_inline_helper_in_a_that_calls_foo")
-; CHECK:   DW_AT_inline (DW_INL_inlined)
-
-; === CU for b.c ===
-
-; CHECK: DW_TAG_compile_unit
-; CHECK:   DW_AT_name ("b.c")
-
-; 3) Validate the cross-CU ref from "call_func_in_b_from_a" in a.c.
-; CHECK: 0x{{0+}}[[FUNC_FROM_B]]: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("func_from_b")
-
-; 4) Validate the cross-CU ref from "call_noinline_func_in_a_from_b" in b.c.
-; CHECK: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("call_noinline_func_in_a_from_b")
-; CHECK:   DW_TAG_call_site
-; CHECK-NEXT: DW_AT_call_origin (0x{{0+}}[[NOINLINE_FUNC_IN_A]])
-
-; CHECK: 0x{{0+}}[[FOO_IN_B:.*]]: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("foo")
-
-; 5) Validate that we correctly emit a cross-CU ref when the call is inlined
-; from another CU.
-; CHECK: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("call_both_foos_from_b")
-; CHECK:   DW_TAG_call_site
-; CHECK-NEXT: DW_AT_call_origin (0x{{0+}}[[FOO_IN_B]])
-; CHECK:   DW_TAG_call_site
-; CHECK-NEXT: DW_AT_call_origin (0x{{0+}}[[FOO_IN_A]])
-
-; CHECK: DW_TAG_subprogram
-; CHECK:   DW_AT_name ("call_func_in_b_from_b")
-; CHECK:   DW_TAG_call_site
-; CHECK-NEXT: DW_AT_call_origin (0x{{0+}}[[FUNC_FROM_B]])
-
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.14.0"
-
-define void @noinline_func_in_a() local_unnamed_addr #0 !dbg !17 {
-entry:
-  ret void, !dbg !20
-}
-
-define void @always_inline_helper_in_a_that_calls_foo() local_unnamed_addr #1 !dbg !21 {
-entry:
-  tail call fastcc void @foo.2(), !dbg !22
-  ret void, !dbg !23
-}
-
-define internal fastcc void @foo.2() unnamed_addr #0 !dbg !24 {
-entry:
-  ret void, !dbg !25
-}
-
-define void @call_func_in_b_from_a() local_unnamed_addr !dbg !26 {
-entry:
-  tail call void @func_from_b() #3, !dbg !27
-  ret void, !dbg !28
-}
-
-define void @call_noinline_func_in_a_from_b() local_unnamed_addr !dbg !29 {
-entry:
-  tail call void @noinline_func_in_a() #3, !dbg !30
-  ret void, !dbg !31
-}
-
-define void @foo() local_unnamed_addr #0 !dbg !32 {
-entry:
-  ret void, !dbg !33
-}
-
-define void @call_both_foos_from_b() local_unnamed_addr !dbg !34 {
-entry:
-  tail call void @foo(), !dbg !35
-  tail call fastcc void @foo.2() #3, !dbg !36
-  ret void, !dbg !38
-}
-
-define void @func_from_b() local_unnamed_addr #0 !dbg !39 {
-entry:
-  ret void, !dbg !40
-}
-
-define void @call_func_in_b_from_b() local_unnamed_addr !dbg !41 {
-entry:
-  tail call void @func_from_b(), !dbg !42
-  ret void, !dbg !43
-}
-
-attributes #0 = { noinline }
-attributes #1 = { alwaysinline }
-
-!llvm.dbg.cu = !{!0, !7}
-!llvm.ident = !{!12, !12}
-!llvm.module.flags = !{!13, !14, !15, !16}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (git at github.com:llvm/llvm-project.git 310e85309f870ee7347ef979d7d8da9bf28e92ea)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
-!1 = !DIFile(filename: "a.c", directory: "/Users/vsk/tmp/lto-entry-vals")
-!2 = !{}
-!3 = !{!4}
-!4 = !DISubprogram(name: "func_from_b", scope: !1, file: !1, line: 8, type: !5, spFlags: DISPFlagOptimized, retainedNodes: !2)
-!5 = !DISubroutineType(types: !6)
-!6 = !{null, null}
-!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !8, producer: "clang version 10.0.0 (git at github.com:llvm/llvm-project.git 310e85309f870ee7347ef979d7d8da9bf28e92ea)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !9, nameTableKind: None)
-!8 = !DIFile(filename: "b.c", directory: "/Users/vsk/tmp/lto-entry-vals")
-!9 = !{!10, !11}
-!10 = !DISubprogram(name: "noinline_func_in_a", scope: !8, file: !8, line: 1, type: !5, spFlags: DISPFlagOptimized, retainedNodes: !2)
-!11 = !DISubprogram(name: "always_inline_helper_in_a_that_calls_foo", scope: !8, file: !8, line: 7, type: !5, spFlags: DISPFlagOptimized, retainedNodes: !2)
-!12 = !{!"clang version 10.0.0 (git at github.com:llvm/llvm-project.git 310e85309f870ee7347ef979d7d8da9bf28e92ea)"}
-!13 = !{i32 7, !"Dwarf Version", i32 4}
-!14 = !{i32 2, !"Debug Info Version", i32 3}
-!15 = !{i32 1, !"wchar_size", i32 4}
-!16 = !{i32 7, !"PIC Level", i32 2}
-!17 = distinct !DISubprogram(name: "noinline_func_in_a", scope: !1, file: !1, line: 1, type: !18, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
-!18 = !DISubroutineType(types: !19)
-!19 = !{null}
-!20 = !DILocation(line: 1, column: 53, scope: !17)
-!21 = distinct !DISubprogram(name: "always_inline_helper_in_a_that_calls_foo", scope: !1, file: !1, line: 4, type: !18, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
-!22 = !DILocation(line: 5, column: 3, scope: !21)
-!23 = !DILocation(line: 6, column: 1, scope: !21)
-!24 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !18, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
-!25 = !DILocation(line: 3, column: 45, scope: !24)
-!26 = distinct !DISubprogram(name: "call_func_in_b_from_a", scope: !1, file: !1, line: 9, type: !18, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
-!27 = !DILocation(line: 10, column: 3, scope: !26)
-!28 = !DILocation(line: 11, column: 1, scope: !26)
-!29 = distinct !DISubprogram(name: "call_noinline_func_in_a_from_b", scope: !8, file: !8, line: 2, type: !18, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !7, retainedNodes: !2)
-!30 = !DILocation(line: 3, column: 3, scope: !29)
-!31 = !DILocation(line: 4, column: 1, scope: !29)
-!32 = distinct !DISubprogram(name: "foo", scope: !8, file: !8, line: 6, type: !18, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !7, retainedNodes: !2)
-!33 = !DILocation(line: 6, column: 38, scope: !32)
-!34 = distinct !DISubprogram(name: "call_both_foos_from_b", scope: !8, file: !8, line: 8, type: !18, scopeLine: 8, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !7, retainedNodes: !2)
-!35 = !DILocation(line: 9, column: 3, scope: !34)
-!36 = !DILocation(line: 5, column: 3, scope: !21, inlinedAt: !37)
-!37 = distinct !DILocation(line: 10, column: 3, scope: !34)
-!38 = !DILocation(line: 11, column: 1, scope: !34)
-!39 = distinct !DISubprogram(name: "func_from_b", scope: !8, file: !8, line: 13, type: !18, scopeLine: 13, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !7, retainedNodes: !2)
-!40 = !DILocation(line: 13, column: 46, scope: !39)
-!41 = distinct !DISubprogram(name: "call_func_in_b_from_b", scope: !8, file: !8, line: 14, type: !18, scopeLine: 14, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !7, retainedNodes: !2)
-!42 = !DILocation(line: 15, column: 3, scope: !41)
-!43 = !DILocation(line: 16, column: 1, scope: !41)

diff  --git a/llvm/test/DebugInfo/X86/subprogram-across-cus.ll b/llvm/test/DebugInfo/X86/subprogram-across-cus.ll
new file mode 100644
index 0000000000000..345342aecf3c2
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/subprogram-across-cus.ll
@@ -0,0 +1,93 @@
+; RUN: llc %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t
+; RUN: llvm-dwarfdump -verify %t
+; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
+; RUN: rm %t
+;
+;$ cat -n 1.cpp
+;     1  struct HHH;
+;     2  HHH *zzz;
+;
+;$ cat -n 2.cpp
+;     1  void __attribute__((optnone)) __attribute__((nodebug)) f1()  { }
+;     2
+;     3  struct HHH {
+;     4    template <typename bbb>
+;     5    static int __attribute__((always_inline)) ccc() {
+;     6      f1();
+;     7    }
+;     8  };
+;     9
+;    10  int main() {
+;    11    struct local { };
+;    12    HHH::ccc<local>();
+;    13  }
+;
+; $ clang -flto -O2 -g 1.cpp 2.cpp -o a.out
+;
+; Given this input, LLVM attempts to create a DIE for subprogram "main" in the
+; wrong context. The definition of struct "HHH" is placed in the CU for 1.cpp.
+; While creating the template instance in "HHH", function "ccc" is referenced
+; via the struct local type, and "main" is created in the CU for 1.cpp, which
+; is incorrect.
+;
+; See PR48790 for more discussion and original compile commands.
+;
+; Check that there are no verifier failures, and that the SP for "main" appears
+; in the correct CU.
+; CHECK-LABEL:      DW_TAG_compile_unit
+; CHECK:              DW_AT_name ("1.cpp")
+; CHECK-NOT:          DW_AT_name ("main")
+; CHECK-LABEL:      DW_TAG_compile_unit
+; CHECK:              DW_AT_name ("2.cpp")
+; CHECK:            DW_TAG_subprogram
+; CHECK:              DW_AT_name ("main")
+
+source_filename = "ld-temp.o"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline norecurse nounwind optnone uwtable mustprogress
+define internal fastcc void @_Z2f1v() unnamed_addr {
+entry:
+  ret void
+}
+
+; Function Attrs: norecurse noreturn nounwind uwtable mustprogress
+define dso_local i32 @main() local_unnamed_addr !dbg !17 {
+entry:
+  tail call fastcc void @_Z2f1v(), !dbg !21
+  unreachable, !dbg !21
+}
+
+!llvm.dbg.cu = !{!0, !9}
+!llvm.ident = !{!10, !10}
+!llvm.module.flags = !{!11, !12, !13, !14, !15, !16}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0 (git at github.com:llvm/llvm-project bc9ab9a5cd6bafc5e1293f3d5d51638f8f5cd26c)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "1.cpp", directory: "/tmp/bees")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = distinct !DIGlobalVariable(name: "zzz", scope: !0, file: !1, line: 2, type: !6, isLocal: false, isDefinition: true)
+!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
+!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "HHH", file: !8, line: 3, size: 8, flags: DIFlagTypePassByValue, elements: !2, identifier: "_ZTS3HHH")
+!8 = !DIFile(filename: "2.cpp", directory: "/tmp/bees")
+!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !8, producer: "clang version 12.0.0 (git at github.com:llvm/llvm-project bc9ab9a5cd6bafc5e1293f3d5d51638f8f5cd26c)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!10 = !{!"clang version 12.0.0 (git at github.com:llvm/llvm-project bc9ab9a5cd6bafc5e1293f3d5d51638f8f5cd26c)"}
+!11 = !{i32 7, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{i32 1, !"ThinLTO", i32 0}
+!15 = !{i32 1, !"EnableSplitLTOUnit", i32 1}
+!16 = !{i32 1, !"LTOPostLink", i32 1}
+!17 = distinct !DISubprogram(name: "main", scope: !8, file: !8, line: 10, type: !18, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !9, retainedNodes: !2)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!20}
+!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!21 = !DILocation(line: 6, column: 5, scope: !22, inlinedAt: !27)
+!22 = distinct !DISubprogram(name: "ccc<local>", linkageName: "_ZN3HHH3cccIZ4mainE5localEEiv", scope: !7, file: !8, line: 5, type: !18, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !9, templateParams: !24, declaration: !23, retainedNodes: !2)
+!23 = !DISubprogram(name: "ccc<local>", linkageName: "_ZN3HHH3cccIZ4mainE5localEEiv", scope: !7, file: !8, line: 5, type: !18, scopeLine: 5, flags: DIFlagPrototyped | DIFlagStaticMember, spFlags: DISPFlagOptimized, templateParams: !24)
+!24 = !{!25}
+!25 = !DITemplateTypeParameter(name: "bbb", type: !26)
+!26 = !DICompositeType(tag: DW_TAG_structure_type, name: "local", scope: !17, file: !8, line: 11, size: 8, flags: DIFlagFwdDecl)
+!27 = distinct !DILocation(line: 12, column: 3, scope: !17)


        


More information about the llvm-branch-commits mailing list