Skip to content

Commit a4610c7

Browse files
authored
[BOLT][DWARF] Add support for DW_IDX_parent (llvm#85285)
This adds support for DW_IDX_parent. If DIE has a parent then DW_IDX_parent in Entry will point to Entry for that parent DIE. Otherwise it will have DW_FORM_flag_present in abbrev. Which takes zero space in Entry. This came from https://discourse.llvm.org/t/rfc-improve-dwarf-5-debug-names-type-lookup-parsing-speed/74151
1 parent 8ff96eb commit a4610c7

15 files changed

+424
-185
lines changed

bolt/include/bolt/Core/DIEBuilder.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,13 @@ class DIEBuilder {
209209
void updateReferences();
210210

211211
/// Update the Offset and Size of DIE, populate DebugNames table.
212-
uint32_t finalizeDIEs(DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
212+
/// Along with current CU, and DIE being processed and the new DIE offset to
213+
/// be updated, it takes in Parents vector that can be empty if this DIE has
214+
/// no parents.
215+
uint32_t
216+
finalizeDIEs(DWARFUnit &CU, DIE &Die,
217+
std::vector<std::optional<BOLTDWARF5AccelTableData *>> &Parents,
218+
uint32_t &CurOffset);
213219

214220
void registerUnit(DWARFUnit &DU, bool NeedSort);
215221

bolt/include/bolt/Core/DebugNames.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class BOLTDWARF5AccelTableData : public DWARF5AccelTableData {
3636
bool isTU() const { return DWARF5AccelTableData::isTU(); }
3737
std::optional<unsigned> getSecondUnitID() const { return SecondUnitID; }
3838

39+
void setPatchOffset(uint64_t PatchOffset) { OffsetVal = PatchOffset; }
40+
uint64_t getPatchOffset() const { return std::get<uint64_t>(OffsetVal); }
41+
3942
private:
4043
std::optional<unsigned> SecondUnitID;
4144
};
@@ -49,10 +52,12 @@ class DWARF5AcceleratorTable {
4952
Abbrev->~DebugNamesAbbrev();
5053
}
5154
/// Add DWARF5 Accelerator table entry.
52-
/// Input is DWARFUnit being processed, DIE that belongs to it, and potential
53-
/// SkeletonCU if the Unit comes from a DWO section.
54-
void addAccelTableEntry(DWARFUnit &Unit, const DIE &Die,
55-
const std::optional<uint64_t> &DWOID);
55+
/// Input is DWARFUnit being processed, DIE that belongs to it, potential
56+
/// DWOID if the Unit comes from a DWO section, and potential parent entry.
57+
std::optional<BOLTDWARF5AccelTableData *>
58+
addAccelTableEntry(DWARFUnit &Unit, const DIE &Die,
59+
const std::optional<uint64_t> &DWOID,
60+
std::optional<BOLTDWARF5AccelTableData *> &Parent);
5661
/// Set current unit being processed.
5762
void setCurrentUnit(DWARFUnit &Unit, const uint64_t UnitStartOffset);
5863
/// Emit Accelerator table.
@@ -121,6 +126,8 @@ class DWARF5AcceleratorTable {
121126
llvm::DenseMap<llvm::hash_code, uint64_t> StrCacheToOffsetMap;
122127
// Contains DWO ID to CUList Index.
123128
llvm::DenseMap<uint64_t, uint32_t> CUOffsetsToPatch;
129+
// Contains a map of Entry ID to Entry relative offset.
130+
llvm::DenseMap<uint64_t, uint32_t> EntryRelativeOffsets;
124131
/// Adds Unit to either CUList, LocalTUList or ForeignTUList.
125132
/// Input Unit being processed, and DWO ID if Unit is being processed comes
126133
/// from a DWO section.
@@ -143,7 +150,7 @@ class DWARF5AcceleratorTable {
143150
/// Write Entries.
144151
void writeEntries();
145152
/// Write an Entry.
146-
void writeEntry(const BOLTDWARF5AccelTableData &Entry);
153+
void writeEntry(BOLTDWARF5AccelTableData &Entry);
147154
/// Write augmentation_string for BOLT.
148155
void writeAugmentationString();
149156
/// Emit out Header for DWARF5 Accelerator table.

bolt/lib/Core/DIEBuilder.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,32 @@ getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx,
377377
return nullptr;
378378
}
379379

380-
uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
381-
uint32_t &CurOffset) {
380+
uint32_t DIEBuilder::finalizeDIEs(
381+
DWARFUnit &CU, DIE &Die,
382+
std::vector<std::optional<BOLTDWARF5AccelTableData *>> &Parents,
383+
uint32_t &CurOffset) {
382384
getState().DWARFDieAddressesParsed.erase(Die.getOffset());
383385
uint32_t CurSize = 0;
384386
Die.setOffset(CurOffset);
385-
DebugNamesTable.addAccelTableEntry(
386-
CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt);
387+
std::optional<BOLTDWARF5AccelTableData *> NameEntry =
388+
DebugNamesTable.addAccelTableEntry(
389+
CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt,
390+
Parents.back());
391+
// It is possible that an indexed debugging information entry has a parent
392+
// that is not indexed (for example, if its parent does not have a name
393+
// attribute). In such a case, a parent attribute may point to a nameless
394+
// index entry (that is, one that cannot be reached from any entry in the name
395+
// table), or it may point to the nearest ancestor that does have an index
396+
// entry.
397+
if (NameEntry)
398+
Parents.push_back(std::move(NameEntry));
387399
for (DIEValue &Val : Die.values())
388400
CurSize += Val.sizeOf(CU.getFormParams());
389401
CurSize += getULEB128Size(Die.getAbbrevNumber());
390402
CurOffset += CurSize;
391403

392404
for (DIE &Child : Die.children()) {
393-
uint32_t ChildSize = finalizeDIEs(CU, Child, CurOffset);
405+
uint32_t ChildSize = finalizeDIEs(CU, Child, Parents, CurOffset);
394406
CurSize += ChildSize;
395407
}
396408
// for children end mark.
@@ -400,6 +412,8 @@ uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
400412
}
401413

402414
Die.setSize(CurSize);
415+
if (NameEntry)
416+
Parents.pop_back();
403417

404418
return CurSize;
405419
}
@@ -410,7 +424,9 @@ void DIEBuilder::finish() {
410424
uint32_t HeaderSize = CU.getHeaderSize();
411425
uint32_t CurOffset = HeaderSize;
412426
DebugNamesTable.setCurrentUnit(CU, UnitStartOffset);
413-
finalizeDIEs(CU, *UnitDIE, CurOffset);
427+
std::vector<std::optional<BOLTDWARF5AccelTableData *>> Parents;
428+
Parents.push_back(std::nullopt);
429+
finalizeDIEs(CU, *UnitDIE, Parents, CurOffset);
414430

415431
DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);
416432
CurUnitInfo.UnitOffset = UnitStartOffset;

bolt/lib/Core/DebugNames.cpp

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/Support/EndianStream.h"
1414
#include "llvm/Support/LEB128.h"
1515
#include <cstdint>
16+
#include <optional>
1617

1718
namespace llvm {
1819
namespace bolt {
@@ -163,10 +164,16 @@ static uint64_t getNameOffset(BinaryContext &BC, DWARFUnit &Unit,
163164
Index * DwarfOffsetByteSize);
164165
}
165166

166-
void DWARF5AcceleratorTable::addAccelTableEntry(
167-
DWARFUnit &Unit, const DIE &Die, const std::optional<uint64_t> &DWOID) {
167+
static uint64_t getEntryID(const BOLTDWARF5AccelTableData &Entry) {
168+
return reinterpret_cast<uint64_t>(&Entry);
169+
}
170+
171+
std::optional<BOLTDWARF5AccelTableData *>
172+
DWARF5AcceleratorTable::addAccelTableEntry(
173+
DWARFUnit &Unit, const DIE &Die, const std::optional<uint64_t> &DWOID,
174+
std::optional<BOLTDWARF5AccelTableData *> &Parent) {
168175
if (Unit.getVersion() < 5 || !NeedToCreate)
169-
return;
176+
return std::nullopt;
170177
std::string NameToUse = "";
171178
auto canProcess = [&](const DIE &Die) -> bool {
172179
switch (Die.getTag()) {
@@ -217,7 +224,7 @@ void DWARF5AcceleratorTable::addAccelTableEntry(
217224
};
218225

219226
if (!canProcess(Die))
220-
return;
227+
return std::nullopt;
221228

222229
// Addes a Unit to either CU, LocalTU or ForeignTU list the first time we
223230
// encounter it.
@@ -227,10 +234,11 @@ void DWARF5AcceleratorTable::addAccelTableEntry(
227234
addUnit(Unit, DWOID);
228235
}
229236

230-
auto addEntry = [&](DIEValue ValName) -> void {
237+
auto addEntry =
238+
[&](DIEValue ValName) -> std::optional<BOLTDWARF5AccelTableData *> {
231239
if ((!ValName || ValName.getForm() == dwarf::DW_FORM_string) &&
232240
NameToUse.empty())
233-
return;
241+
return std::nullopt;
234242
std::string Name = "";
235243
uint64_t NameIndexOffset = 0;
236244
if (NameToUse.empty()) {
@@ -275,13 +283,23 @@ void DWARF5AcceleratorTable::addAccelTableEntry(
275283
<< ".\n";
276284
SecondIndex = Iter->second;
277285
}
286+
std::optional<uint64_t> ParentOffset =
287+
(Parent ? std::optional<uint64_t>(getEntryID(**Parent)) : std::nullopt);
288+
// This will be populated later in writeEntry.
289+
// This way only parent entries get tracked.
290+
// Keeping memory footprint down.
291+
if (ParentOffset)
292+
EntryRelativeOffsets.insert({*ParentOffset, 0});
278293
It.Values.push_back(new (Allocator) BOLTDWARF5AccelTableData(
279-
Die.getOffset(), std::nullopt, DieTag, UnitID, IsTU, SecondIndex));
294+
Die.getOffset(), ParentOffset, DieTag, UnitID, IsTU, SecondIndex));
295+
return It.Values.back();
280296
};
281297

282-
addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_name));
283-
addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_linkage_name));
284-
return;
298+
std::optional<BOLTDWARF5AccelTableData *> NameEntry =
299+
addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_name));
300+
std::optional<BOLTDWARF5AccelTableData *> LinkageNameEntry =
301+
addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_linkage_name));
302+
return NameEntry ? NameEntry : LinkageNameEntry;
285303
}
286304

287305
/// Algorithm from llvm implementation.
@@ -382,6 +400,11 @@ void DWARF5AcceleratorTable::populateAbbrevsMap() {
382400
if (SecondEntryRet)
383401
Abbrev.addAttribute(SecondEntryRet->Encoding);
384402
Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
403+
if (std::optional<uint64_t> Offset = Value->getParentDieOffset())
404+
Abbrev.addAttribute({dwarf::DW_IDX_parent, dwarf::DW_FORM_ref4});
405+
else
406+
Abbrev.addAttribute(
407+
{dwarf::DW_IDX_parent, dwarf::DW_FORM_flag_present});
385408
FoldingSetNodeID ID;
386409
Abbrev.Profile(ID);
387410
void *InsertPos;
@@ -401,7 +424,11 @@ void DWARF5AcceleratorTable::populateAbbrevsMap() {
401424
}
402425
}
403426

404-
void DWARF5AcceleratorTable::writeEntry(const BOLTDWARF5AccelTableData &Entry) {
427+
void DWARF5AcceleratorTable::writeEntry(BOLTDWARF5AccelTableData &Entry) {
428+
const uint64_t EntryID = getEntryID(Entry);
429+
if (EntryRelativeOffsets.find(EntryID) != EntryRelativeOffsets.end())
430+
EntryRelativeOffsets[EntryID] = EntriesBuffer->size();
431+
405432
const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
406433
getIndexForEntry(Entry);
407434
// For forgeign type (FTU) units that need to refer to the FTU and to the CU.
@@ -456,6 +483,17 @@ void DWARF5AcceleratorTable::writeEntry(const BOLTDWARF5AccelTableData &Entry) {
456483
llvm::endianness::little);
457484
break;
458485
}
486+
case dwarf::DW_IDX_parent: {
487+
assert(
488+
(AttrEnc.Form == dwarf::DW_FORM_ref4 && Entry.getParentDieOffset()) ||
489+
AttrEnc.Form == dwarf::DW_FORM_flag_present);
490+
if (std::optional<uint64_t> ParentOffset = Entry.getParentDieOffset()) {
491+
Entry.setPatchOffset(EntriesBuffer->size());
492+
support::endian::write(*Entriestream, static_cast<uint32_t>(UINT32_MAX),
493+
llvm::endianness::little);
494+
}
495+
break;
496+
}
459497
}
460498
}
461499
}
@@ -464,13 +502,34 @@ void DWARF5AcceleratorTable::writeEntries() {
464502
for (auto &Bucket : getBuckets()) {
465503
for (DWARF5AcceleratorTable::HashData *Hash : Bucket) {
466504
Hash->EntryOffset = EntriesBuffer->size();
467-
for (const BOLTDWARF5AccelTableData *Value : Hash->Values) {
505+
for (BOLTDWARF5AccelTableData *Value : Hash->Values) {
468506
writeEntry(*Value);
469507
}
470508
support::endian::write(*Entriestream, static_cast<uint8_t>(0),
471509
llvm::endianness::little);
472510
}
473511
}
512+
// Patching parent offsets.
513+
for (auto &Bucket : getBuckets()) {
514+
for (DWARF5AcceleratorTable::HashData *Hash : Bucket) {
515+
for (BOLTDWARF5AccelTableData *Entry : Hash->Values) {
516+
std::optional<uint64_t> ParentOffset = Entry->getParentDieOffset();
517+
if (!ParentOffset)
518+
continue;
519+
if (const auto Iter = EntryRelativeOffsets.find(*ParentOffset);
520+
Iter != EntryRelativeOffsets.end()) {
521+
const uint64_t PatchOffset = Entry->getPatchOffset();
522+
uint32_t *Ptr = reinterpret_cast<uint32_t *>(
523+
&EntriesBuffer.get()->data()[PatchOffset]);
524+
*Ptr = Iter->second;
525+
} else {
526+
BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "
527+
"entry with offset "
528+
<< *ParentOffset << "\n";
529+
}
530+
}
531+
}
532+
}
474533
}
475534

476535
void DWARF5AcceleratorTable::writeAugmentationString() {

bolt/test/X86/dwarf5-debug-names-generate-debug-names.test

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
; BOLT: [[OFFSET2:0x[0-9a-f]*]]: Compile Unit
1515
; BOLT: Name Index @ 0x0 {
1616
; BOLT-NEXT: Header {
17-
; BOLT-NEXT: Length: 0x103
17+
; BOLT-NEXT: Length: 0x109
1818
; BOLT-NEXT: Format: DWARF32
1919
; BOLT-NEXT: Version: 5
2020
; BOLT-NEXT: CU count: 2
2121
; BOLT-NEXT: Local TU count: 0
2222
; BOLT-NEXT: Foreign TU count: 0
2323
; BOLT-NEXT: Bucket count: 8
2424
; BOLT-NEXT: Name count: 8
25-
; BOLT-NEXT: Abbreviations table size: 0x19
25+
; BOLT-NEXT: Abbreviations table size: 0x1F
2626
; BOLT-NEXT: Augmentation: 'BOLT'
2727
; BOLT-NEXT: }
2828
; BOLT-NEXT: Compilation Unit offsets [
@@ -34,16 +34,19 @@
3434
; BOLT-NEXT: Tag: DW_TAG_base_type
3535
; BOLT-NEXT: DW_IDX_compile_unit: DW_FORM_data1
3636
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
37+
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
3738
; BOLT-NEXT: }
3839
; BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
3940
; BOLT-NEXT: Tag: DW_TAG_subprogram
4041
; BOLT-NEXT: DW_IDX_compile_unit: DW_FORM_data1
4142
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
43+
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
4244
; BOLT-NEXT: }
4345
; BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
4446
; BOLT-NEXT: Tag: DW_TAG_variable
4547
; BOLT-NEXT: DW_IDX_compile_unit: DW_FORM_data1
4648
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
49+
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
4750
; BOLT-NEXT: }
4851
; BOLT-NEXT: ]
4952
; BOLT-NEXT: Bucket 0 [
@@ -55,12 +58,14 @@
5558
; BOLT-NEXT: Tag: DW_TAG_base_type
5659
; BOLT-NEXT: DW_IDX_compile_unit: 0x01
5760
; BOLT-NEXT: DW_IDX_die_offset: 0x00000033
61+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
5862
; BOLT-NEXT: }
5963
; BOLT-NEXT: Entry @ {{.+}} {
6064
; BOLT-NEXT: Abbrev: [[ABBREV1]]
6165
; BOLT-NEXT: Tag: DW_TAG_base_type
6266
; BOLT-NEXT: DW_IDX_compile_unit: 0x00
6367
; BOLT-NEXT: DW_IDX_die_offset: 0x0000007f
68+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
6469
; BOLT-NEXT: }
6570
; BOLT-NEXT: }
6671
; BOLT-NEXT: ]
@@ -73,6 +78,7 @@
7378
; BOLT-NEXT: Tag: DW_TAG_subprogram
7479
; BOLT-NEXT: DW_IDX_compile_unit: 0x01
7580
; BOLT-NEXT: DW_IDX_die_offset: 0x0000005e
81+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
7682
; BOLT-NEXT: }
7783
; BOLT-NEXT: }
7884
; BOLT-NEXT: Name 3 {
@@ -83,6 +89,7 @@
8389
; BOLT-NEXT: Tag: DW_TAG_subprogram
8490
; BOLT-NEXT: DW_IDX_compile_unit: 0x00
8591
; BOLT-NEXT: DW_IDX_die_offset: 0x00000028
92+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
8693
; BOLT-NEXT: }
8794
; BOLT-NEXT: }
8895
; BOLT-NEXT: ]
@@ -95,6 +102,7 @@
95102
; BOLT-NEXT: Tag: DW_TAG_subprogram
96103
; BOLT-NEXT: DW_IDX_compile_unit: 0x00
97104
; BOLT-NEXT: DW_IDX_die_offset: 0x00000028
105+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
98106
; BOLT-NEXT: }
99107
; BOLT-NEXT: }
100108
; BOLT-NEXT: Name 5 {
@@ -105,6 +113,7 @@
105113
; BOLT-NEXT: Tag: DW_TAG_subprogram
106114
; BOLT-NEXT: DW_IDX_compile_unit: 0x00
107115
; BOLT-NEXT: DW_IDX_die_offset: 0x00000049
116+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
108117
; BOLT-NEXT: }
109118
; BOLT-NEXT: }
110119
; BOLT-NEXT: Name 6 {
@@ -115,6 +124,7 @@
115124
; BOLT-NEXT: Tag: DW_TAG_variable
116125
; BOLT-NEXT: DW_IDX_compile_unit: 0x01
117126
; BOLT-NEXT: DW_IDX_die_offset: 0x00000028
127+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
118128
; BOLT-NEXT: }
119129
; BOLT-NEXT: }
120130
; BOLT-NEXT: ]
@@ -127,6 +137,7 @@
127137
; BOLT-NEXT: Tag: DW_TAG_base_type
128138
; BOLT-NEXT: DW_IDX_compile_unit: 0x00
129139
; BOLT-NEXT: DW_IDX_die_offset: 0x00000092
140+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
130141
; BOLT-NEXT: }
131142
; BOLT-NEXT: }
132143
; BOLT-NEXT: ]
@@ -145,6 +156,7 @@
145156
; BOLT-NEXT: Tag: DW_TAG_subprogram
146157
; BOLT-NEXT: DW_IDX_compile_unit: 0x01
147158
; BOLT-NEXT: DW_IDX_die_offset: 0x0000005e
159+
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
148160
; BOLT-NEXT: }
149161
; BOLT-NEXT: }
150162
; BOLT-NEXT: ]

0 commit comments

Comments
 (0)