1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 10:32:48 +02:00

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@sony.com>

Conflicts:
	llvm/test/DebugInfo/X86/convert-loclist.ll
This commit is contained in:
Jeremy Morse 2021-08-09 12:40:21 +01:00 committed by Tom Stellard
parent e4e6f3eeff
commit fa3a9f0fc7
14 changed files with 135 additions and 375 deletions

View File

@ -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);
}

View File

@ -249,16 +249,14 @@ public:
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.

View File

@ -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;

View File

@ -471,9 +471,6 @@ private:
/// 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);

View File

@ -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 {

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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 ([[foo_SP:.*]])
# 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_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"

View File

@ -13,7 +13,7 @@
; often - add another IR file with a different DW_OP_convert that's otherwise
; identical and demonstrate that they have different 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

View File

@ -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@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@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@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)

View File

@ -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@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@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@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)

View File

@ -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@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@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@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)