Skip to content

Commit cb26204

Browse files
committed
[DebugInfo][DwarfDebug] Separate creation and population of abstract subprogram DIEs
With this change, construction of abstract subprogram DIEs is split in two stages/functions: creation of DIE (in DwarfCompileUnit::getOrCreateAbstractSubprogramDIE) and its population with children (in DwarfCompileUnit::constructAbstractSubprogramScopeDIE). With that, abstract subprograms can be created/referenced from DwarfDebug::beginModule, which should solve the issue with static local variables DIE creation of inlined functons with optimized-out definitions. It fixes llvm#29985. LexicalScopes class now stores mapping from DISubprograms to their corresponding llvm::Function's. It is supposed to be built before processing of each function (so, now it has a method for "module initialization" alongside the method for "function initialization"). It is used by DwarfCompileUnit to determine whether a DISubprogram needs an abstract DIE before DwarfDebug::beginFunction is invoked. DwarfCompileUnit::getOrCreateSubprogramDIE method is added, which can create an abstract or a concrete DIE for a subprogram. It accepts llvm::Function* argument to determine whether a concrete DIE must be created. This is a temporary fix for llvm#29985. Ideally, it will be fixed by moving global variables and types emission to DwarfDebug::endModule (https://reviews.llvm.org/D144007, https://reviews.llvm.org/D144005). However, I'm not sure if these patches can be merged before llvm#75385. The last attempt to make it mergeable was llvm#142166. @dwblaikie came up with an idea of making DISubprograms unique in LLVM IR. To implement that, I've tried making a patch that allows DwarfDebug to handle multiple llvm::Functions referring to the same DISubprogram, and it also needs parts of the functionality of this patch. Some changes made by @ellishg in llvm#90523 were taken for this commit.
1 parent 47bd167 commit cb26204

20 files changed

+442
-82
lines changed

llvm/include/llvm/CodeGen/DebugHandlerBase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ class DebugHandlerBase : public AsmPrinterHandler {
144144
static bool isUnsignedDIType(const DIType *Ty);
145145

146146
const InstructionOrdering &getInstOrdering() const { return InstOrdering; }
147+
148+
const LexicalScopes &getLexicalScopes() const { return LScopes; }
147149
};
148150

149151
} // namespace llvm

llvm/include/llvm/CodeGen/LexicalScopes.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,18 @@ class LexicalScopes {
141141
public:
142142
LexicalScopes() = default;
143143

144+
/// Scan module to build subprogram-to-function map.
145+
LLVM_ABI void initialize(const Module &);
146+
144147
/// Scan machine function and constuct lexical scope nest, resets
145148
/// the instance if necessary.
146-
LLVM_ABI void initialize(const MachineFunction &);
149+
LLVM_ABI void scanFunction(const MachineFunction &);
150+
151+
/// Reset the instance so that it's prepared for another module.
152+
LLVM_ABI void resetModule();
147153

148-
/// Release memory.
149-
LLVM_ABI void reset();
154+
/// Reset the instance so that it's prepared for another function.
155+
LLVM_ABI void resetFunction();
150156

151157
/// Return true if there is any lexical scope information available.
152158
bool empty() { return CurrentFnLexicalScope == nullptr; }
@@ -196,6 +202,11 @@ class LexicalScopes {
196202
/// Find or create an abstract lexical scope.
197203
LLVM_ABI LexicalScope *getOrCreateAbstractScope(const DILocalScope *Scope);
198204

205+
/// Get function to which the given subprogram is attached, if exists.
206+
const Function *getFunction(const DISubprogram *SP) const {
207+
return FunctionMap.lookup(SP);
208+
}
209+
199210
private:
200211
/// Find lexical scope for the given Scope/IA. If not available
201212
/// then create new lexical scope.
@@ -225,6 +236,9 @@ class LexicalScopes {
225236

226237
const MachineFunction *MF = nullptr;
227238

239+
/// Mapping between DISubprograms and IR functions.
240+
DenseMap<const DISubprogram *, const Function *> FunctionMap;
241+
228242
/// Tracks the scopes in the current function.
229243
// Use an unordered_map to ensure value pointer validity over insertion.
230244
std::unordered_map<const DILocalScope *, LexicalScope> LexicalScopeMap;

llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,12 @@ DebugHandlerBase::DebugHandlerBase(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {}
103103
DebugHandlerBase::~DebugHandlerBase() = default;
104104

105105
void DebugHandlerBase::beginModule(Module *M) {
106-
if (M->debug_compile_units().empty())
106+
if (M->debug_compile_units().empty()) {
107107
Asm = nullptr;
108+
return;
109+
}
110+
111+
LScopes.initialize(*M);
108112
}
109113

110114
// Each LexicalScope has first instruction and last instruction to mark
@@ -269,7 +273,7 @@ void DebugHandlerBase::beginFunction(const MachineFunction *MF) {
269273

270274
// Grab the lexical scopes for the function, if we don't have any of those
271275
// then we're not going to be able to do anything.
272-
LScopes.initialize(*MF);
276+
LScopes.scanFunction(*MF);
273277
if (LScopes.empty()) {
274278
beginFunctionImpl(MF);
275279
return;

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,9 @@ void DwarfCompileUnit::addWasmRelocBaseGlobal(DIELoc *Loc, StringRef GlobalName,
537537
// and DW_AT_high_pc attributes. If there are global variables in this
538538
// scope then create and insert DIEs for these variables.
539539
DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP,
540+
const Function &F,
540541
MCSymbol *LineTableSym) {
541-
DIE *SPDie = getOrCreateSubprogramDIE(SP, includeMinimalInlineScopes());
542+
DIE *SPDie = getOrCreateSubprogramDIE(SP, &F, includeMinimalInlineScopes());
542543
SmallVector<RangeSpan, 2> BB_List;
543544
// If basic block sections are on, ranges for each basic block section has
544545
// to be emitted separately.
@@ -1122,9 +1123,10 @@ sortLocalVars(SmallVectorImpl<DbgVariable *> &Input) {
11221123
}
11231124

11241125
DIE &DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub,
1126+
const Function &F,
11251127
LexicalScope *Scope,
11261128
MCSymbol *LineTableSym) {
1127-
DIE &ScopeDIE = updateSubprogramScopeDIE(Sub, LineTableSym);
1129+
DIE &ScopeDIE = updateSubprogramScopeDIE(Sub, F, LineTableSym);
11281130

11291131
if (Scope) {
11301132
assert(!Scope->getInlinedAt());
@@ -1198,31 +1200,12 @@ DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
11981200
return ObjectPointer;
11991201
}
12001202

1201-
void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
1202-
LexicalScope *Scope) {
1203-
auto *SP = cast<DISubprogram>(Scope->getScopeNode());
1204-
if (getAbstractScopeDIEs().count(SP))
1205-
return;
1203+
DIE &DwarfCompileUnit::getOrCreateAbstractSubprogramDIE(
1204+
const DISubprogram *SP) {
1205+
if (auto *AbsDef = getAbstractScopeDIEs().lookup(SP))
1206+
return *AbsDef;
12061207

1207-
DIE *ContextDIE;
1208-
DwarfCompileUnit *ContextCU = this;
1209-
1210-
if (includeMinimalInlineScopes())
1211-
ContextDIE = &getUnitDie();
1212-
// Some of this is duplicated from DwarfUnit::getOrCreateSubprogramDIE, with
1213-
// the important distinction that the debug node is not associated with the
1214-
// DIE (since the debug node will be associated with the concrete DIE, if
1215-
// any). It could be refactored to some common utility function.
1216-
else if (auto *SPDecl = SP->getDeclaration()) {
1217-
ContextDIE = &getUnitDie();
1218-
getOrCreateSubprogramDIE(SPDecl);
1219-
} else {
1220-
ContextDIE = getOrCreateContextDIE(SP->getScope());
1221-
// The scope may be shared with a subprogram that has already been
1222-
// constructed in another CU, in which case we need to construct this
1223-
// subprogram in the same CU.
1224-
ContextCU = DD->lookupCU(ContextDIE->getUnitDie());
1225-
}
1208+
auto [ContextDIE, ContextCU] = getOrCreateAbstractSubprogramContextDIE(SP);
12261209

12271210
// Passing null as the associated node because the abstract definition
12281211
// shouldn't be found by lookup.
@@ -1237,6 +1220,42 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
12371220
DD->getDwarfVersion() <= 4 ? std::optional<dwarf::Form>()
12381221
: dwarf::DW_FORM_implicit_const,
12391222
dwarf::DW_INL_inlined);
1223+
1224+
return AbsDef;
1225+
}
1226+
1227+
std::pair<DIE *, DwarfCompileUnit *>
1228+
DwarfCompileUnit::getOrCreateAbstractSubprogramContextDIE(
1229+
const DISubprogram *SP) {
1230+
bool Minimal = includeMinimalInlineScopes();
1231+
bool IgnoreScope = shouldPlaceInUnitDIE(SP, Minimal);
1232+
DIE *ContextDIE = getOrCreateSubprogramContextDIE(SP, IgnoreScope);
1233+
1234+
if (auto *SPDecl = SP->getDeclaration())
1235+
if (!Minimal)
1236+
getOrCreateSubprogramDIE(SPDecl, nullptr);
1237+
1238+
// The scope may be shared with a subprogram that has already been
1239+
// constructed in another CU, in which case we need to construct this
1240+
// subprogram in the same CU.
1241+
auto *ContextCU = IgnoreScope ? this : DD->lookupCU(ContextDIE->getUnitDie());
1242+
1243+
return std::make_pair(ContextDIE, ContextCU);
1244+
}
1245+
1246+
void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
1247+
LexicalScope *Scope) {
1248+
auto *SP = cast<DISubprogram>(Scope->getScopeNode());
1249+
1250+
if (getFinalizedAbstractSubprograms().contains(SP)) {
1251+
return;
1252+
}
1253+
1254+
DIE &AbsDef = getOrCreateAbstractSubprogramDIE(SP);
1255+
auto [ContextDIE, ContextCU] = getOrCreateAbstractSubprogramContextDIE(SP);
1256+
1257+
getFinalizedAbstractSubprograms().insert(SP);
1258+
12401259
if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, AbsDef))
12411260
ContextCU->addDIEEntry(AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
12421261
}
@@ -1293,9 +1312,9 @@ DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const {
12931312
}
12941313

12951314
DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
1296-
DIE &ScopeDIE, const DISubprogram *CalleeSP, bool IsTail,
1297-
const MCSymbol *PCAddr, const MCSymbol *CallAddr, unsigned CallReg,
1298-
DIType *AllocSiteTy) {
1315+
DIE &ScopeDIE, const DISubprogram *CalleeSP, const Function *CalleeF,
1316+
bool IsTail, const MCSymbol *PCAddr, const MCSymbol *CallAddr,
1317+
unsigned CallReg, DIType *AllocSiteTy) {
12991318
// Insert a call site entry DIE within ScopeDIE.
13001319
DIE &CallSiteDIE = createAndAddDIE(getDwarf5OrGNUTag(dwarf::DW_TAG_call_site),
13011320
ScopeDIE, nullptr);
@@ -1305,7 +1324,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
13051324
addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target),
13061325
MachineLocation(CallReg));
13071326
} else if (CalleeSP) {
1308-
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP);
1327+
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP, CalleeF);
13091328
assert(CalleeDIE && "Could not create DIE for call site entry origin");
13101329
if (AddLinkageNamesToDeclCallOriginsForTuning(DD) &&
13111330
!CalleeSP->isDefinition() &&
@@ -1396,7 +1415,7 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE(
13961415
if (auto *AbsSPDie = getAbstractScopeDIEs().lookup(SP))
13971416
EntityDie = AbsSPDie;
13981417
else
1399-
EntityDie = getOrCreateSubprogramDIE(SP);
1418+
EntityDie = getOrCreateSubprogramDIE(SP, nullptr);
14001419
} else if (auto *T = dyn_cast<DIType>(Entity))
14011420
EntityDie = getOrCreateTypeDIE(T);
14021421
else if (auto *GV = dyn_cast<DIGlobalVariable>(Entity))
@@ -1805,3 +1824,16 @@ DIE *DwarfCompileUnit::getOrCreateContextDIE(const DIScope *Context) {
18051824
}
18061825
return DwarfUnit::getOrCreateContextDIE(Context);
18071826
}
1827+
1828+
DIE *DwarfCompileUnit::getOrCreateSubprogramDIE(const DISubprogram *SP,
1829+
const Function *F,
1830+
bool Minimal) {
1831+
if (!F && SP->isDefinition()) {
1832+
F = DD->getLexicalScopes().getFunction(SP);
1833+
1834+
if (!F)
1835+
return &getCU().getOrCreateAbstractSubprogramDIE(SP);
1836+
}
1837+
1838+
return DwarfUnit::getOrCreateSubprogramDIE(SP, F, Minimal);
1839+
}

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class DwarfCompileUnit final : public DwarfUnit {
8181

8282
// List of abstract local scopes (either DISubprogram or DILexicalBlock).
8383
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
84+
SmallPtrSet<const DISubprogram *, 8> FinalizedAbstractSubprograms;
8485

8586
// List of inlined lexical block scopes that belong to subprograms within this
8687
// CU.
@@ -137,12 +138,24 @@ class DwarfCompileUnit final : public DwarfUnit {
137138
return DU->getAbstractEntities();
138139
}
139140

141+
auto &getFinalizedAbstractSubprograms() {
142+
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
143+
return FinalizedAbstractSubprograms;
144+
return DU->getFinalizedAbstractSubprograms();
145+
}
146+
140147
void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) override;
141148

142149
/// Add info for Wasm-global-based relocation.
143150
void addWasmRelocBaseGlobal(DIELoc *Loc, StringRef GlobalName,
144151
uint64_t GlobalIndex);
145152

153+
/// Create context DIE for abstract subprogram.
154+
/// \returns The context DIE and the compile unit where abstract
155+
/// DIE should be constructed.
156+
std::pair<DIE *, DwarfCompileUnit *>
157+
getOrCreateAbstractSubprogramContextDIE(const DISubprogram *SP);
158+
146159
public:
147160
DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A,
148161
DwarfDebug *DW, DwarfFile *DWU,
@@ -216,7 +229,8 @@ class DwarfCompileUnit final : public DwarfUnit {
216229
/// DW_AT_low_pc, DW_AT_high_pc and DW_AT_LLVM_stmt_sequence attributes.
217230
/// If there are global variables in this scope then create and insert DIEs
218231
/// for these variables.
219-
DIE &updateSubprogramScopeDIE(const DISubprogram *SP, MCSymbol *LineTableSym);
232+
DIE &updateSubprogramScopeDIE(const DISubprogram *SP, const Function &F,
233+
MCSymbol *LineTableSym);
220234

221235
void constructScopeDIE(LexicalScope *Scope, DIE &ParentScopeDIE);
222236

@@ -259,12 +273,18 @@ class DwarfCompileUnit final : public DwarfUnit {
259273
/// This instance of 'getOrCreateContextDIE()' can handle DILocalScope.
260274
DIE *getOrCreateContextDIE(const DIScope *Ty) override;
261275

276+
DIE *getOrCreateSubprogramDIE(const DISubprogram *SP, const Function *F,
277+
bool Minimal = false) override;
278+
262279
/// Construct a DIE for this subprogram scope.
263-
DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope,
264-
MCSymbol *LineTableSym);
280+
DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, const Function &F,
281+
LexicalScope *Scope, MCSymbol *LineTableSym);
265282

266283
DIE *createAndAddScopeChildren(LexicalScope *Scope, DIE &ScopeDIE);
267284

285+
/// Create an abstract subprogram DIE, that should later be populated
286+
/// by \ref constructAbstractSubprogramScopeDIE.
287+
DIE &getOrCreateAbstractSubprogramDIE(const DISubprogram *SP);
268288
void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);
269289

270290
/// Whether to use the GNU analog for a DWARF5 tag, attribute, or location
@@ -281,14 +301,15 @@ class DwarfCompileUnit final : public DwarfUnit {
281301
dwarf::LocationAtom getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const;
282302

283303
/// Construct a call site entry DIE describing a call within \p Scope to a
284-
/// callee described by \p CalleeSP.
304+
/// callee described by \p CalleeSP and \p CalleeF.
285305
/// \p IsTail specifies whether the call is a tail call.
286306
/// \p PCAddr points to the PC value after the call instruction.
287307
/// \p CallAddr points to the PC value at the call instruction (or is null).
288308
/// \p CallReg is a register location for an indirect call. For direct calls
289309
/// the \p CallReg is set to 0.
290310
DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP,
291-
bool IsTail, const MCSymbol *PCAddr,
311+
const Function *CalleeF, bool IsTail,
312+
const MCSymbol *PCAddr,
292313
const MCSymbol *CallAddr, unsigned CallReg,
293314
DIType *AllocSiteTy);
294315
/// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params

llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,8 +1001,9 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP,
10011001
->getName(CallReg)))
10021002
<< (IsTail ? " [IsTail]" : "") << "\n");
10031003

1004-
DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(
1005-
ScopeDIE, CalleeSP, IsTail, PCAddr, CallAddr, CallReg, AllocSiteTy);
1004+
DIE &CallSiteDIE =
1005+
CU.constructCallSiteEntryDIE(ScopeDIE, CalleeSP, CalleeDecl, IsTail,
1006+
PCAddr, CallAddr, CallReg, AllocSiteTy);
10061007

10071008
// Optionally emit call-site-param debug info.
10081009
if (emitDebugEntryValues()) {
@@ -2711,7 +2712,8 @@ void DwarfDebug::skippedNonDebugFunction() {
27112712

27122713
// Gather and emit post-function debug information.
27132714
void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
2714-
const DISubprogram *SP = MF->getFunction().getSubprogram();
2715+
const Function &F = MF->getFunction();
2716+
const DISubprogram *SP = F.getSubprogram();
27152717

27162718
assert(CurFn == MF &&
27172719
"endFunction should be called with the same function as beginFunction");
@@ -2780,11 +2782,12 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
27802782

27812783
ProcessedSPNodes.insert(SP);
27822784
DIE &ScopeDIE =
2783-
TheCU.constructSubprogramScopeDIE(SP, FnScope, FunctionLineTableLabel);
2785+
TheCU.constructSubprogramScopeDIE(SP, F, FnScope, FunctionLineTableLabel);
27842786
if (auto *SkelCU = TheCU.getSkeleton())
27852787
if (!LScopes.getAbstractScopesList().empty() &&
27862788
TheCU.getCUNode()->getSplitDebugInlining())
2787-
SkelCU->constructSubprogramScopeDIE(SP, FnScope, FunctionLineTableLabel);
2789+
SkelCU->constructSubprogramScopeDIE(SP, F, FnScope,
2790+
FunctionLineTableLabel);
27882791

27892792
FunctionLineTableLabel = nullptr;
27902793

llvm/lib/CodeGen/AsmPrinter/DwarfFile.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "DwarfStringPool.h"
1313
#include "llvm/ADT/DenseMap.h"
14+
#include "llvm/ADT/SmallPtrSet.h"
1415
#include "llvm/ADT/SmallVector.h"
1516
#include "llvm/ADT/StringRef.h"
1617
#include "llvm/CodeGen/DIE.h"
@@ -27,6 +28,7 @@ class DbgVariable;
2728
class DbgLabel;
2829
class DINode;
2930
class DILocalScope;
31+
class DISubprogram;
3032
class DwarfCompileUnit;
3133
class DwarfUnit;
3234
class LexicalScope;
@@ -94,6 +96,8 @@ class DwarfFile {
9496
// Collection of abstract subprogram DIEs.
9597
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
9698
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
99+
// FIXME: merge creation and population of abstract scopes.
100+
SmallPtrSet<const DISubprogram *, 8> FinalizedAbstractSubprograms;
97101

98102
/// Maps MDNodes for type system with the corresponding DIEs. These DIEs can
99103
/// be shared across CUs, that is why we keep the map here instead
@@ -174,6 +178,10 @@ class DwarfFile {
174178
return AbstractEntities;
175179
}
176180

181+
auto &getFinalizedAbstractSubprograms() {
182+
return FinalizedAbstractSubprograms;
183+
}
184+
177185
void insertDIE(const MDNode *TypeMD, DIE *Die) {
178186
DITypeNodeToDieMap.insert(std::make_pair(TypeMD, Die));
179187
}

0 commit comments

Comments
 (0)