[DebugInfo][DWARF] Emit DW_AT_abstract_origin for concrete/inlined DW_TAG_lexical_blocks (#136205)
During the discussion under https://github.com/llvm/llvm-project/pull/119001, it was noticed that concrete DW_TAG_lexical_blocks should refer to corresponding abstract DW_TAG_lexical_blocks by having DW_AT_abstract_origin, to avoid ambiguity. This behavior is implemented in GCC (https://godbolt.org/z/Khrzdq1Wx), but not in LLVM. Fixes https://github.com/llvm/llvm-project/issues/49297.
This commit is contained in:
committed by
GitHub
parent
8832a5950f
commit
1143a04f34
@@ -782,6 +782,8 @@ DIE *DwarfCompileUnit::constructLexicalScopeDIE(LexicalScope *Scope) {
|
||||
assert(!LexicalBlockDIEs.count(DS) &&
|
||||
"Concrete out-of-line DIE for this scope exists!");
|
||||
LexicalBlockDIEs[DS] = ScopeDIE;
|
||||
} else {
|
||||
InlinedLocalScopeDIEs[DS].push_back(ScopeDIE);
|
||||
}
|
||||
|
||||
attachRangesOrLowHighPC(*ScopeDIE, Scope->getRanges());
|
||||
@@ -1491,6 +1493,19 @@ void DwarfCompileUnit::finishEntityDefinition(const DbgEntity *Entity) {
|
||||
getDwarfDebug().addAccelName(*this, CUNode->getNameTableKind(), Name, *Die);
|
||||
}
|
||||
|
||||
void DwarfCompileUnit::attachLexicalScopesAbstractOrigins() {
|
||||
auto AttachAO = [&](const DILocalScope *LS, DIE *ScopeDIE) {
|
||||
if (auto *AbsLSDie = getAbstractScopeDIEs().lookup(LS))
|
||||
addDIEEntry(*ScopeDIE, dwarf::DW_AT_abstract_origin, *AbsLSDie);
|
||||
};
|
||||
|
||||
for (auto [LScope, ScopeDIE] : LexicalBlockDIEs)
|
||||
AttachAO(LScope, ScopeDIE);
|
||||
for (auto &[LScope, ScopeDIEs] : InlinedLocalScopeDIEs)
|
||||
for (auto *ScopeDIE : ScopeDIEs)
|
||||
AttachAO(LScope, ScopeDIE);
|
||||
}
|
||||
|
||||
DbgEntity *DwarfCompileUnit::getExistingAbstractEntity(const DINode *Node) {
|
||||
auto &AbstractEntities = getAbstractEntities();
|
||||
auto I = AbstractEntities.find(Node);
|
||||
|
||||
@@ -82,6 +82,10 @@ class DwarfCompileUnit final : public DwarfUnit {
|
||||
// List of abstract local scopes (either DISubprogram or DILexicalBlock).
|
||||
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
|
||||
|
||||
// List of inlined lexical block scopes that belong to subprograms within this
|
||||
// CU.
|
||||
DenseMap<const DILocalScope *, SmallVector<DIE *, 2>> InlinedLocalScopeDIEs;
|
||||
|
||||
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
|
||||
|
||||
/// DWO ID for correlating skeleton and split units.
|
||||
@@ -299,6 +303,7 @@ public:
|
||||
|
||||
void finishSubprogramDefinition(const DISubprogram *SP);
|
||||
void finishEntityDefinition(const DbgEntity *Entity);
|
||||
void attachLexicalScopesAbstractOrigins();
|
||||
|
||||
/// Find abstract variable associated with Var.
|
||||
using InlinedEntity = DbgValueHistoryMap::InlinedEntity;
|
||||
|
||||
@@ -1262,6 +1262,7 @@ void DwarfDebug::finalizeModuleInfo() {
|
||||
auto &TheCU = *P.second;
|
||||
if (TheCU.getCUNode()->isDebugDirectivesOnly())
|
||||
continue;
|
||||
TheCU.attachLexicalScopesAbstractOrigins();
|
||||
// Emit DW_AT_containing_type attribute to connect types with their
|
||||
// vtable holding type.
|
||||
TheCU.constructContainingTypeDIEs();
|
||||
|
||||
@@ -20,16 +20,29 @@
|
||||
; }
|
||||
|
||||
; Ensure that lexical_blocks within inlined_subroutines are preserved/emitted.
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK-NEXT: DW_AT_linkage_name ("_Z2f1v")
|
||||
; CHECK: [[ADDR1:0x[0-9a-f]+]]: DW_TAG_lexical_block
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK-NEXT: DW_AT_linkage_name ("_Z2f2v")
|
||||
; CHECK: [[ADDR2:0x[0-9a-f]+]]: DW_TAG_lexical_block
|
||||
; CHECK: DW_TAG_inlined_subroutine
|
||||
; CHECK-NOT: DW_TAG
|
||||
; CHECK-NOT: NULL
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin ([[ADDR1]]
|
||||
; CHECK-NOT: DW_TAG
|
||||
; CHECK-NOT: NULL
|
||||
; CHECK: DW_TAG_variable
|
||||
; Ensure that file changes don't interfere with creating inlined subroutines.
|
||||
; (see the line directive inside 'f2' in thesource)
|
||||
; CHECK: DW_TAG_inlined_subroutine
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin ([[ADDR2]]
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK-NOT: DW_TAG
|
||||
; CHECK: DW_AT_abstract_origin
|
||||
|
||||
56
llvm/test/DebugInfo/Generic/lexical-block-abstract-origin.ll
Normal file
56
llvm/test/DebugInfo/Generic/lexical-block-abstract-origin.ll
Normal file
@@ -0,0 +1,56 @@
|
||||
; RUN: %llc_dwarf -filetype=obj -O0 %s -o - | llvm-dwarfdump -debug-info - | FileCheck %s
|
||||
|
||||
; Check that DW_AT_abstract_origin is generated for concrete lexical block.
|
||||
|
||||
; Generated from:
|
||||
; inline __attribute__((always_inline)) int foo(int x) {
|
||||
; {
|
||||
; int y = x + 5;
|
||||
; return y - 10;
|
||||
; }
|
||||
; }
|
||||
;
|
||||
; int bar(int x) {
|
||||
; int y = foo(7);
|
||||
; return y + 8;
|
||||
; }
|
||||
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK-NEXT: DW_AT_name ("foo")
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: [[LB:.*]]: DW_TAG_lexical_block
|
||||
|
||||
; CHECK: DW_TAG_inlined_subroutine
|
||||
; CHECK-NEXT: DW_AT_abstract_origin {{.*}} "foo"
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin {{.*}}[[LB]]
|
||||
|
||||
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
|
||||
target triple = "arm64-apple-macosx15.0.0"
|
||||
|
||||
define i32 @bar() !dbg !9 {
|
||||
entry:
|
||||
%y.i = alloca i32, align 4
|
||||
#dbg_declare(ptr %y.i, !22, !DIExpression(), !24)
|
||||
store i32 0, ptr %y.i, align 4, !dbg !24
|
||||
%1 = load i32, ptr %y.i, align 4
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, emissionKind: FullDebug)
|
||||
!1 = !DIFile(filename: "test.c", directory: "")
|
||||
!3 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!9 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 8, type: !10, spFlags: DISPFlagDefinition, unit: !0)
|
||||
!10 = !DISubroutineType(types: !13)
|
||||
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!13 = !{}
|
||||
!19 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
|
||||
!21 = distinct !DILocation(line: 9, column: 11, scope: !9)
|
||||
!22 = !DILocalVariable(name: "y", scope: !23, file: !1, line: 3, type: !12)
|
||||
!23 = distinct !DILexicalBlock(scope: !19, file: !1, line: 2, column: 3)
|
||||
!24 = !DILocation(line: 3, column: 9, scope: !23, inlinedAt: !21)
|
||||
@@ -28,9 +28,11 @@
|
||||
; CHECK: DW_TAG_subprogram
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin {{.*}} {[[Offset_bar:0x[0-9abcdef]+]]}
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin {{.*}}[[Offset_lb:0x[0-9a-f]+]]
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
|
||||
;; Abstract "bar" function
|
||||
@@ -40,7 +42,7 @@
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_inline
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK: [[Offset_lb]]: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
@@ -56,8 +58,10 @@
|
||||
; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[Offset_bar]]}
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin {{.*}}[[Offset_lb]]
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
|
||||
; Function Attrs: alwaysinline nounwind
|
||||
define i32 @_Z3barv() #0 !dbg !4 {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
; CHECK-NOT: DW_TAG
|
||||
; CHECK: DW_AT_name ("b")
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK: [[LB_DECL:.*]]: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK-NOT: DW_TAG
|
||||
@@ -82,7 +82,9 @@
|
||||
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_lexical_block
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_AT_abstract_origin {{.*}}[[LB_DECL]]
|
||||
; CHECK-NOT: {{DW_TAG|NULL}}
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK-NOT: DW_TAG
|
||||
; CHECK: DW_AT_abstract_origin {{.*}} "s"
|
||||
|
||||
Reference in New Issue
Block a user