Skip to content

Commit 432b589

Browse files
authored
[DebugInfo][DwarfDebug] Separate creation and population of abstract subprogram DIEs (#159104)
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 #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 LexicalScopes class 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 #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). Some code proposed by Ellis Hoag <[email protected]> in #90523 was taken for this commit.
1 parent e56b479 commit 432b589

20 files changed

+451
-84
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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ DebugHandlerBase::~DebugHandlerBase() = default;
105105
void DebugHandlerBase::beginModule(Module *M) {
106106
if (M->debug_compile_units().empty())
107107
Asm = nullptr;
108+
else
109+
LScopes.initialize(*M);
108110
}
109111

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

270272
// Grab the lexical scopes for the function, if we don't have any of those
271273
// then we're not going to be able to do anything.
272-
LScopes.initialize(*MF);
274+
LScopes.scanFunction(*MF);
273275
if (LScopes.empty()) {
274276
beginFunctionImpl(MF);
275277
return;

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 70 additions & 33 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,32 +1200,17 @@ 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);
1209+
return createAbstractSubprogramDIE(SP, ContextDIE, ContextCU);
1210+
}
12261211

1212+
DIE &DwarfCompileUnit::createAbstractSubprogramDIE(
1213+
const DISubprogram *SP, DIE *ContextDIE, DwarfCompileUnit *ContextCU) {
12271214
// Passing null as the associated node because the abstract definition
12281215
// shouldn't be found by lookup.
12291216
DIE &AbsDef = ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram,
@@ -1237,8 +1224,45 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
12371224
DD->getDwarfVersion() <= 4 ? std::optional<dwarf::Form>()
12381225
: dwarf::DW_FORM_implicit_const,
12391226
dwarf::DW_INL_inlined);
1240-
if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, AbsDef))
1241-
ContextCU->addDIEEntry(AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer);
1227+
1228+
return AbsDef;
1229+
}
1230+
1231+
std::pair<DIE *, DwarfCompileUnit *>
1232+
DwarfCompileUnit::getOrCreateAbstractSubprogramContextDIE(
1233+
const DISubprogram *SP) {
1234+
bool Minimal = includeMinimalInlineScopes();
1235+
bool IgnoreScope = shouldPlaceInUnitDIE(SP, Minimal);
1236+
DIE *ContextDIE = getOrCreateSubprogramContextDIE(SP, IgnoreScope);
1237+
1238+
if (auto *SPDecl = SP->getDeclaration())
1239+
if (!Minimal)
1240+
getOrCreateSubprogramDIE(SPDecl, nullptr);
1241+
1242+
// The scope may be shared with a subprogram that has already been
1243+
// constructed in another CU, in which case we need to construct this
1244+
// subprogram in the same CU.
1245+
auto *ContextCU = IgnoreScope ? this : DD->lookupCU(ContextDIE->getUnitDie());
1246+
1247+
return std::make_pair(ContextDIE, ContextCU);
1248+
}
1249+
1250+
void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
1251+
LexicalScope *Scope) {
1252+
auto *SP = cast<DISubprogram>(Scope->getScopeNode());
1253+
1254+
// Populate subprogram DIE only once.
1255+
if (!getFinalizedAbstractSubprograms().insert(SP).second)
1256+
return;
1257+
1258+
auto [ContextDIE, ContextCU] = getOrCreateAbstractSubprogramContextDIE(SP);
1259+
DIE *AbsDef = getAbstractScopeDIEs().lookup(SP);
1260+
if (!AbsDef)
1261+
AbsDef = &createAbstractSubprogramDIE(SP, ContextDIE, ContextCU);
1262+
1263+
if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, *AbsDef))
1264+
ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer,
1265+
*ObjectPointer);
12421266
}
12431267

12441268
bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const {
@@ -1293,9 +1317,9 @@ DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const {
12931317
}
12941318

12951319
DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
1296-
DIE &ScopeDIE, const DISubprogram *CalleeSP, bool IsTail,
1297-
const MCSymbol *PCAddr, const MCSymbol *CallAddr, unsigned CallReg,
1298-
DIType *AllocSiteTy) {
1320+
DIE &ScopeDIE, const DISubprogram *CalleeSP, const Function *CalleeF,
1321+
bool IsTail, const MCSymbol *PCAddr, const MCSymbol *CallAddr,
1322+
unsigned CallReg, DIType *AllocSiteTy) {
12991323
// Insert a call site entry DIE within ScopeDIE.
13001324
DIE &CallSiteDIE = createAndAddDIE(getDwarf5OrGNUTag(dwarf::DW_TAG_call_site),
13011325
ScopeDIE, nullptr);
@@ -1305,7 +1329,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(
13051329
addAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_target),
13061330
MachineLocation(CallReg));
13071331
} else if (CalleeSP) {
1308-
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP);
1332+
DIE *CalleeDIE = getOrCreateSubprogramDIE(CalleeSP, CalleeF);
13091333
assert(CalleeDIE && "Could not create DIE for call site entry origin");
13101334
if (AddLinkageNamesToDeclCallOriginsForTuning(DD) &&
13111335
!CalleeSP->isDefinition() &&
@@ -1396,7 +1420,7 @@ DIE *DwarfCompileUnit::constructImportedEntityDIE(
13961420
if (auto *AbsSPDie = getAbstractScopeDIEs().lookup(SP))
13971421
EntityDie = AbsSPDie;
13981422
else
1399-
EntityDie = getOrCreateSubprogramDIE(SP);
1423+
EntityDie = getOrCreateSubprogramDIE(SP, nullptr);
14001424
} else if (auto *T = dyn_cast<DIType>(Entity))
14011425
EntityDie = getOrCreateTypeDIE(T);
14021426
else if (auto *GV = dyn_cast<DIGlobalVariable>(Entity))
@@ -1805,3 +1829,16 @@ DIE *DwarfCompileUnit::getOrCreateContextDIE(const DIScope *Context) {
18051829
}
18061830
return DwarfUnit::getOrCreateContextDIE(Context);
18071831
}
1832+
1833+
DIE *DwarfCompileUnit::getOrCreateSubprogramDIE(const DISubprogram *SP,
1834+
const Function *F,
1835+
bool Minimal) {
1836+
if (!F && SP->isDefinition()) {
1837+
F = DD->getLexicalScopes().getFunction(SP);
1838+
1839+
if (!F)
1840+
return &getCU().getOrCreateAbstractSubprogramDIE(SP);
1841+
}
1842+
1843+
return DwarfUnit::getOrCreateSubprogramDIE(SP, F, Minimal);
1844+
}

llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h

Lines changed: 30 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,28 @@ 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+
159+
/// Create new DIE for abstract subprogram.
160+
DIE &createAbstractSubprogramDIE(const DISubprogram *SP, DIE *ContextDIE,
161+
DwarfCompileUnit *ContextCU);
162+
146163
public:
147164
DwarfCompileUnit(unsigned UID, const DICompileUnit *Node, AsmPrinter *A,
148165
DwarfDebug *DW, DwarfFile *DWU,
@@ -216,7 +233,8 @@ class DwarfCompileUnit final : public DwarfUnit {
216233
/// DW_AT_low_pc, DW_AT_high_pc and DW_AT_LLVM_stmt_sequence attributes.
217234
/// If there are global variables in this scope then create and insert DIEs
218235
/// for these variables.
219-
DIE &updateSubprogramScopeDIE(const DISubprogram *SP, MCSymbol *LineTableSym);
236+
DIE &updateSubprogramScopeDIE(const DISubprogram *SP, const Function &F,
237+
MCSymbol *LineTableSym);
220238

221239
void constructScopeDIE(LexicalScope *Scope, DIE &ParentScopeDIE);
222240

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

280+
DIE *getOrCreateSubprogramDIE(const DISubprogram *SP, const Function *F,
281+
bool Minimal = false) override;
282+
262283
/// Construct a DIE for this subprogram scope.
263-
DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope,
264-
MCSymbol *LineTableSym);
284+
DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, const Function &F,
285+
LexicalScope *Scope, MCSymbol *LineTableSym);
265286

266287
DIE *createAndAddScopeChildren(LexicalScope *Scope, DIE &ScopeDIE);
267288

289+
/// Create an abstract subprogram DIE, that should later be populated
290+
/// by \ref constructAbstractSubprogramScopeDIE.
291+
DIE &getOrCreateAbstractSubprogramDIE(const DISubprogram *SP);
268292
void constructAbstractSubprogramScopeDIE(LexicalScope *Scope);
269293

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

283307
/// Construct a call site entry DIE describing a call within \p Scope to a
284-
/// callee described by \p CalleeSP.
308+
/// callee described by \p CalleeSP and \p CalleeF.
285309
/// \p IsTail specifies whether the call is a tail call.
286310
/// \p PCAddr points to the PC value after the call instruction.
287311
/// \p CallAddr points to the PC value at the call instruction (or is null).
288312
/// \p CallReg is a register location for an indirect call. For direct calls
289313
/// the \p CallReg is set to 0.
290314
DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, const DISubprogram *CalleeSP,
291-
bool IsTail, const MCSymbol *PCAddr,
315+
const Function *CalleeF, bool IsTail,
316+
const MCSymbol *PCAddr,
292317
const MCSymbol *CallAddr, unsigned CallReg,
293318
DIType *AllocSiteTy);
294319
/// 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: 9 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,9 @@ class DwarfFile {
9496
// Collection of abstract subprogram DIEs.
9597
DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
9698
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;
97102

98103
/// Maps MDNodes for type system with the corresponding DIEs. These DIEs can
99104
/// be shared across CUs, that is why we keep the map here instead
@@ -174,6 +179,10 @@ class DwarfFile {
174179
return AbstractEntities;
175180
}
176181

182+
auto &getFinalizedAbstractSubprograms() {
183+
return FinalizedAbstractSubprograms;
184+
}
185+
177186
void insertDIE(const MDNode *TypeMD, DIE *Die) {
178187
DITypeNodeToDieMap.insert(std::make_pair(TypeMD, Die));
179188
}

0 commit comments

Comments
 (0)