Skip to content

Commit 6442e01

Browse files
committed
[DwarfDebug] Track abstract entities in DwarfUnit separately
`DwarfCompileUnit::constructVariableDIE()` and `constructLabelDIE()` are meant for constructing both abstract and concrete DIEs of a DbgEntity. They use `DwarfUnit::insertDIE()` to store a freshly-created DIE. However, `insertDIE()`/`DwarfUnit::DITypeNodeToDieMap` store only single DIE per DINode. If `insertDIE()` is called several times for the same instance of DINode, only first DIE is saved in `DwarfUnit::DITypeNodeToDieMap`, as follows from `DenseMap::insert()` specification. It means, depending on what is called first, `DwarfCompileUnit::constructVariableDIE(LV, /* Abstract */ true)` or `DwarfCompileUnit::constructVariableDIE(LV, /* Abstract */ false)`, `DwarfUnit::DITypeNodeToDieMap` stores either abstract or concrete DIE of a node. This behavior suggests an obscure API of DwarfCompileUnit, as it depends on function call order and makes it unclear what `DwarfUnit::DITypeNodeToDieMap` is meant to store. To address that, DwarfInfoHolder class is introduced, which stores DIEs for DILocalVariables and DILabels separately from DIEs for other DINodes (as DILocalVariables and DILabels may have concrete and abstract DIEs), and allows explicit access to abstract/concrete DIEs of a debug info entity. Also, DwarfFile and DwarfUnit have a tiny duplicate code piece. AbstractEntities, AbstractLocalScopeDIEs and FinalizedAbstractSubprograms tracking were moved to DwarfInfoHolder, as the corresponding entities may be shared across CUs. DwarfInfoHolder may later be used for tracking DIEs of abstract/concrete lexical scopes. Currently, concrete lexical block/subprogram DIEs are distinguished by their DISubprogram/DILocalScope/DILocalScope+inlinedAt in DwarfCompileUnit. As a result, the same DISubprogram can't be attached to two llvm::Functions (https://lists.llvm.org/pipermail/llvm-dev/2020-September/145342.html). Matching DISubprogram/DILocalScope DIEs with their LexicalScopes and letting DwarfUnit members to access abstract scopes may enable linking DISubprogram to several llvm::Functions, and allow the transition from distinct to uniqued DISubprograms proposed here llvm#142166 (comment).
1 parent 06cffb7 commit 6442e01

File tree

6 files changed

+185
-84
lines changed

6 files changed

+185
-84
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ unsigned DwarfCompileUnit::getOrCreateSourceID(const DIFile *File) {
178178
DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(
179179
const DIGlobalVariable *GV, ArrayRef<GlobalExpr> GlobalExprs) {
180180
// Check for pre-existence.
181-
if (DIE *Die = getDIE(GV))
181+
if (DIE *Die = getDIEs(GV).getVariableDIE(GV))
182182
return Die;
183183

184184
assert(GV);
@@ -795,7 +795,9 @@ DIE *DwarfCompileUnit::constructLexicalScopeDIE(LexicalScope *Scope) {
795795

796796
DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV, bool Abstract) {
797797
auto *VariableDie = DIE::get(DIEValueAllocator, DV.getTag());
798-
insertDIE(DV.getVariable(), VariableDie);
798+
getDIEs(DV.getVariable())
799+
.getLVs()
800+
.insertDIE(DV.getVariable(), &DV, VariableDie, Abstract);
799801
DV.setDIE(*VariableDie);
800802
// Abstract variables don't get common attributes later, so apply them now.
801803
if (Abstract) {
@@ -1010,7 +1012,9 @@ DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV,
10101012
DIE *DwarfCompileUnit::constructLabelDIE(DbgLabel &DL,
10111013
const LexicalScope &Scope) {
10121014
auto LabelDie = DIE::get(DIEValueAllocator, DL.getTag());
1013-
insertDIE(DL.getLabel(), LabelDie);
1015+
getDIEs(DL.getLabel())
1016+
.getLabels()
1017+
.insertDIE(DL.getLabel(), &DL, LabelDie, Scope.isAbstractScope());
10141018
DL.setDIE(*LabelDie);
10151019

10161020
if (Scope.isAbstractScope())

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,10 @@ class DwarfCompileUnit final : public DwarfUnit {
7979
// List of concrete lexical block scopes belong to subprograms within this CU.
8080
DenseMap<const DILocalScope *, DIE *> LexicalBlockDIEs;
8181

82-
// List of abstract local scopes (either DISubprogram or DILexicalBlock).
83-
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
84-
SmallPtrSet<const DISubprogram *, 8> FinalizedAbstractSubprograms;
85-
8682
// List of inlined lexical block scopes that belong to subprograms within this
8783
// CU.
8884
DenseMap<const DILocalScope *, SmallVector<DIE *, 2>> InlinedLocalScopeDIEs;
8985

90-
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
91-
9286
/// DWO ID for correlating skeleton and split units.
9387
uint64_t DWOId = 0;
9488

@@ -126,22 +120,20 @@ class DwarfCompileUnit final : public DwarfUnit {
126120

127121
bool isDwoUnit() const override;
128122

123+
DwarfInfoHolder &getDIEs(const DINode *N) { return DwarfUnit::getDIEs(N); }
124+
125+
DwarfInfoHolder &getDIEs() { return getDIEs(nullptr); }
126+
129127
DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
130-
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
131-
return AbstractLocalScopeDIEs;
132-
return DU->getAbstractScopeDIEs();
128+
return getDIEs().getAbstractScopeDIEs();
133129
}
134130

135131
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
136-
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
137-
return AbstractEntities;
138-
return DU->getAbstractEntities();
132+
return getDIEs().getAbstractEntities();
139133
}
140134

141135
auto &getFinalizedAbstractSubprograms() {
142-
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
143-
return FinalizedAbstractSubprograms;
144-
return DU->getFinalizedAbstractSubprograms();
136+
return getDIEs().getFinalizedAbstractSubprograms();
145137
}
146138

147139
void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) override;

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,8 @@ void DwarfDebug::addSubprogramNames(
502502
// well into the name table. Only do that if we are going to actually emit
503503
// that name.
504504
if (LinkageName != "" && SP->getName() != LinkageName &&
505-
(useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(SP)))
505+
(useAllLinkageNames() ||
506+
InfoHolder.getDIEs().getAbstractScopeDIEs().lookup(SP)))
506507
addAccelName(Unit, NameTableKind, LinkageName, Die);
507508

508509
// If this is an Objective-C selector name add it to the ObjC accelerator

llvm/lib/CodeGen/AsmPrinter/DwarfFile.h

Lines changed: 136 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
#include "llvm/ADT/SmallVector.h"
1616
#include "llvm/ADT/StringRef.h"
1717
#include "llvm/CodeGen/DIE.h"
18+
#include "llvm/IR/DebugInfoMetadata.h"
1819
#include "llvm/Support/Allocator.h"
20+
#include <functional>
1921
#include <map>
2022
#include <memory>
23+
#include <optional>
2124
#include <utility>
2225

2326
namespace llvm {
@@ -26,9 +29,6 @@ class AsmPrinter;
2629
class DbgEntity;
2730
class DbgVariable;
2831
class DbgLabel;
29-
class DINode;
30-
class DILocalScope;
31-
class DISubprogram;
3232
class DwarfCompileUnit;
3333
class DwarfUnit;
3434
class LexicalScope;
@@ -53,6 +53,137 @@ struct RangeSpanList {
5353
SmallVector<RangeSpan, 2> Ranges;
5454
};
5555

56+
/// Tracks abstract and concrete DIEs for debug info entities of a certain type.
57+
template <typename DINodeT, typename DbgEntityT> class DINodeInfoHolder {
58+
public:
59+
using AbstractMapT = DenseMap<const DINodeT *, DIE *>;
60+
using ConcreteMapT =
61+
DenseMap<const DINodeT *, SmallDenseMap<const DbgEntityT *, DIE *, 2>>;
62+
63+
private:
64+
AbstractMapT AbstractMap;
65+
ConcreteMapT ConcreteMap;
66+
67+
public:
68+
void insertAbstractDIE(const DINodeT *N, DIE *D) {
69+
auto [_, Inserted] = AbstractMap.try_emplace(N, D);
70+
assert(Inserted && "Duplicate abstract DIE for debug info node");
71+
}
72+
73+
void insertConcreteDIE(const DINodeT *N, const DbgEntityT *E, DIE *D) {
74+
auto [_, Inserted] = ConcreteMap[N].try_emplace(E, D);
75+
assert(Inserted && "Duplicate concrete DIE for debug info node");
76+
}
77+
78+
void insertDIE(const DINodeT *N, const DbgEntityT *E, DIE *D, bool Abstract) {
79+
if (Abstract)
80+
insertAbstractDIE(N, D);
81+
else
82+
insertConcreteDIE(N, E, D);
83+
}
84+
85+
DIE *getAbstractDIE(const DINodeT *N) const { return AbstractMap.lookup(N); }
86+
87+
std::optional<
88+
std::reference_wrapper<const typename ConcreteMapT::mapped_type>>
89+
getConcreteDIEs(const DINodeT *N) const {
90+
if (auto I = ConcreteMap.find(N); I != ConcreteMap.end())
91+
return std::make_optional(std::ref(I->second));
92+
return std::nullopt;
93+
}
94+
95+
DIE *getConcreteDIE(const DINodeT *N, const DbgEntityT *E) const {
96+
if (auto I = getConcreteDIEs(N))
97+
return I->get().lookup(E);
98+
return nullptr;
99+
}
100+
101+
DIE *getAnyConcreteDIE(const DINodeT *N) const {
102+
if (auto I = getConcreteDIEs(N))
103+
return I->get().empty() ? nullptr : I->get().begin()->second;
104+
return nullptr;
105+
}
106+
107+
/// Returns abstract DIE for the entity.
108+
/// If no abstract DIE was created, returns any concrete DIE for the entity.
109+
DIE *getDIE(const DINodeT *N) const {
110+
if (DIE *D = getAbstractDIE(N))
111+
return D;
112+
113+
return getAnyConcreteDIE(N);
114+
}
115+
116+
AbstractMapT &getAbstractDIEs() { return AbstractMap; }
117+
};
118+
119+
/// Tracks DIEs for debug info entites.
120+
/// These DIEs can be shared across CUs, that is why we keep the map here
121+
/// instead of in DwarfCompileUnit.
122+
class DwarfInfoHolder {
123+
/// DIEs of local DbgVariables.
124+
DINodeInfoHolder<DILocalVariable, DbgVariable> LVHolder;
125+
/// DIEs of labels.
126+
DINodeInfoHolder<DILabel, DbgLabel> LabelHolder;
127+
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
128+
// List of abstract local scopes (either DISubprogram or DILexicalBlock).
129+
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
130+
/// Keeps track of abstract subprograms to populate them only once.
131+
// FIXME: merge creation and population of abstract scopes.
132+
SmallPtrSet<const DISubprogram *, 8> FinalizedAbstractSubprograms;
133+
134+
/// Other DINodes with the corresponding DIEs.
135+
DenseMap<const DINode *, DIE *> MDNodeToDieMap;
136+
137+
public:
138+
void insertDIE(const DINode *N, DIE *Die) {
139+
assert((!isa<DILabel>(N) && !isa<DILocalVariable>(N)) &&
140+
"Use getLabels().insertDIE() for labels or getLVs().insertDIE() for "
141+
"local variables");
142+
auto [_, Inserted] = MDNodeToDieMap.try_emplace(N, Die);
143+
assert((Inserted || isa<DISubprogram>(N) || isa<DIType>(N)) &&
144+
"DIE for this DINode has already been added");
145+
}
146+
147+
void insertDIE(DIE *D) { MDNodeToDieMap.try_emplace(nullptr, D); }
148+
149+
DIE *getDIE(const DINode *N) const {
150+
DIE *D = MDNodeToDieMap.lookup(N);
151+
assert((!D || (!isa<DILabel>(N) && !isa<DILocalVariable>(N))) &&
152+
"Use getLabels().getDIE() for labels or getLVs().getDIE() for "
153+
"local variables");
154+
return D;
155+
}
156+
157+
auto &getLVs() { return LVHolder; }
158+
auto &getLVs() const { return LVHolder; }
159+
160+
auto &getLabels() { return LabelHolder; }
161+
auto &getLabels() const { return LabelHolder; }
162+
163+
/// For a global variable, returns DIE of the variable.
164+
///
165+
/// For a local variable, returns abstract DIE of the variable.
166+
/// If no abstract DIE was created, returns any concrete DIE of the variable.
167+
DIE *getVariableDIE(const DIVariable *V) const {
168+
if (auto *LV = dyn_cast<DILocalVariable>(V))
169+
if (DIE *D = getLVs().getDIE(LV))
170+
return D;
171+
return getDIE(V);
172+
}
173+
174+
DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
175+
return AbstractLocalScopeDIEs;
176+
}
177+
178+
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
179+
return AbstractEntities;
180+
}
181+
182+
auto &getFinalizedAbstractSubprograms() {
183+
return FinalizedAbstractSubprograms;
184+
}
185+
};
186+
56187
class DwarfFile {
57188
// Target of Dwarf emission, used for sizing of abbreviations.
58189
AsmPrinter *Asm;
@@ -93,17 +224,7 @@ class DwarfFile {
93224
using LabelList = SmallVector<DbgLabel *, 4>;
94225
DenseMap<LexicalScope *, LabelList> ScopeLabels;
95226

96-
// Collection of abstract subprogram DIEs.
97-
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
98-
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
99-
/// Keeps track of abstract subprograms to populate them only once.
100-
// FIXME: merge creation and population of abstract scopes.
101-
SmallPtrSet<const DISubprogram *, 8> FinalizedAbstractSubprograms;
102-
103-
/// Maps MDNodes for type system with the corresponding DIEs. These DIEs can
104-
/// be shared across CUs, that is why we keep the map here instead
105-
/// of in DwarfCompileUnit.
106-
DenseMap<const MDNode *, DIE *> DITypeNodeToDieMap;
227+
DwarfInfoHolder InfoHolder;
107228

108229
public:
109230
DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA);
@@ -171,25 +292,7 @@ class DwarfFile {
171292
return ScopeLabels;
172293
}
173294

174-
DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
175-
return AbstractLocalScopeDIEs;
176-
}
177-
178-
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
179-
return AbstractEntities;
180-
}
181-
182-
auto &getFinalizedAbstractSubprograms() {
183-
return FinalizedAbstractSubprograms;
184-
}
185-
186-
void insertDIE(const MDNode *TypeMD, DIE *Die) {
187-
DITypeNodeToDieMap.insert(std::make_pair(TypeMD, Die));
188-
}
189-
190-
DIE *getDIE(const MDNode *TypeMD) {
191-
return DITypeNodeToDieMap.lookup(TypeMD);
192-
}
295+
DwarfInfoHolder &getDIEs() { return InfoHolder; }
193296
};
194297

195298
} // end namespace llvm

0 commit comments

Comments
 (0)