Skip to content

[LLVM][DWARF] Add support for monolithic types in .debug_names #68131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions llvm/include/llvm/CodeGen/AccelTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ namespace llvm {
class AsmPrinter;
class DwarfCompileUnit;
class DwarfDebug;
class DwarfTypeUnit;
class MCSymbol;
class raw_ostream;

Expand Down Expand Up @@ -197,6 +198,9 @@ template <typename DataT> class AccelTable : public AccelTableBase {

template <typename... Types>
void addName(DwarfStringPoolEntryRef Name, Types &&... Args);
void clear() { Entries.clear(); }
void addEntries(AccelTable<DataT> &Table);
const StringEntries getEntries() const { return Entries; }
};

template <typename AccelTableDataT>
Expand All @@ -215,6 +219,16 @@ void AccelTable<AccelTableDataT>::addName(DwarfStringPoolEntryRef Name,
AccelTableDataT(std::forward<Types>(Args)...));
}

template <typename AccelTableDataT>
void AccelTable<AccelTableDataT>::addEntries(
AccelTable<AccelTableDataT> &Table) {
for (auto &Entry : Table.getEntries()) {
for (AccelTableData *Value : Entry.second.Values)
addName(Entry.second.Name,
static_cast<AccelTableDataT *>(Value)->getDie());
}
}

/// A base class for different implementations of Data classes for Apple
/// Accelerator Tables. The columns in the table are defined by the static Atoms
/// variable defined on the subclasses.
Expand Down Expand Up @@ -250,6 +264,10 @@ class AppleAccelTableData : public AccelTableData {
/// emitDWARF5AccelTable function.
class DWARF5AccelTableData : public AccelTableData {
public:
struct AttributeEncoding {
dwarf::Index Index;
dwarf::Form Form;
};
static uint32_t hash(StringRef Name) { return caseFoldingDjbHash(Name); }

DWARF5AccelTableData(const DIE &Die) : Die(Die) {}
Expand Down Expand Up @@ -309,17 +327,20 @@ void emitAppleAccelTable(AsmPrinter *Asm, AccelTable<DataT> &Contents,
void emitDWARF5AccelTable(AsmPrinter *Asm,
AccelTable<DWARF5AccelTableData> &Contents,
const DwarfDebug &DD,
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs);

ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs,
ArrayRef<std::unique_ptr<DwarfTypeUnit>> TUs);
using GetIndexForEntryReturnType =
std::optional<std::pair<unsigned, DWARF5AccelTableData::AttributeEncoding>>;
/// Emit a DWARFv5 Accelerator Table consisting of entries in the specified
/// AccelTable. The \p CUs contains either symbols keeping offsets to the
/// start of compilation unit, either offsets to the start of compilation
/// unit themselves.
void emitDWARF5AccelTable(
AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
getCUIndexForEntry);
void emitDWARF5AccelTable(AsmPrinter *Asm,
AccelTable<DWARF5AccelTableStaticData> &Contents,
ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
llvm::function_ref<GetIndexForEntryReturnType(
const DWARF5AccelTableStaticData &)>
getIndexForEntry);

/// Accelerator table data implementation for simple Apple accelerator tables
/// with just a DIE reference.
Expand Down
172 changes: 112 additions & 60 deletions llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "llvm/CodeGen/AccelTable.h"
#include "DwarfCompileUnit.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
Expand Down Expand Up @@ -200,32 +199,30 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
uint32_t AugmentationStringSize = sizeof(AugmentationString);
char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};

Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount)
: CompUnitCount(CompUnitCount), BucketCount(BucketCount),
NameCount(NameCount) {}
Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
uint32_t BucketCount, uint32_t NameCount)
: CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
BucketCount(BucketCount), NameCount(NameCount) {}

void emit(Dwarf5AccelTableWriter &Ctx);
};
struct AttributeEncoding {
dwarf::Index Index;
dwarf::Form Form;
};

Header Header;
DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
DenseMap<uint32_t, SmallVector<DWARF5AccelTableData::AttributeEncoding, 2>>
Abbreviations;
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry;
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
llvm::function_ref<GetIndexForEntryReturnType(const DataT &)>
getIndexForEntry;
MCSymbol *ContributionEnd = nullptr;
MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");

DenseSet<uint32_t> getUniqueTags() const;

// Right now, we emit uniform attributes for all tags.
SmallVector<AttributeEncoding, 2> getUniformAttributes() const;
void populateAbbrevsMap();

void emitCUList() const;
void emitTUList() const;
void emitBuckets() const;
void emitStringOffsets() const;
void emitAbbrevs() const;
Expand All @@ -236,7 +233,9 @@ class Dwarf5AccelTableWriter : public AccelTableWriter {
Dwarf5AccelTableWriter(
AsmPrinter *Asm, const AccelTableBase &Contents,
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry);
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
llvm::function_ref<GetIndexForEntryReturnType(const DataT &)>
getIndexForEntry);

void emit();
};
Expand Down Expand Up @@ -388,31 +387,39 @@ void Dwarf5AccelTableWriter<DataT>::Header::emit(Dwarf5AccelTableWriter &Ctx) {
Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
}

static uint32_t constexpr LowerBitSize = dwarf::DW_IDX_type_hash;
static uint32_t getTagFromAbbreviationTag(const uint32_t AbbrvTag) {
return AbbrvTag >> LowerBitSize;
}
static uint32_t
constructAbbreviationTag(const unsigned Tag,
const GetIndexForEntryReturnType &EntryRet) {
uint32_t AbbrvTag = 0;
if (EntryRet)
AbbrvTag |= 1 << EntryRet->second.Index;
AbbrvTag |= 1 << dwarf::DW_IDX_die_offset;
AbbrvTag |= Tag << LowerBitSize;
return AbbrvTag;
}
template <typename DataT>
DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const {
DenseSet<uint32_t> UniqueTags;
void Dwarf5AccelTableWriter<DataT>::populateAbbrevsMap() {
for (auto &Bucket : Contents.getBuckets()) {
for (auto *Hash : Bucket) {
for (auto *Value : Hash->Values) {
GetIndexForEntryReturnType EntryRet =
getIndexForEntry(*static_cast<const DataT *>(Value));
unsigned Tag = static_cast<const DataT *>(Value)->getDieTag();
UniqueTags.insert(Tag);
uint32_t AbbrvTag = constructAbbreviationTag(Tag, EntryRet);
if (Abbreviations.count(AbbrvTag) == 0) {
SmallVector<DWARF5AccelTableData::AttributeEncoding, 2> UA;
if (EntryRet)
UA.push_back(EntryRet->second);
UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
Abbreviations.try_emplace(AbbrvTag, UA);
}
}
}
}
return UniqueTags;
}

template <typename DataT>
SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2>
Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const {
SmallVector<AttributeEncoding, 2> UA;
if (CompUnits.size() > 1) {
size_t LargestCUIndex = CompUnits.size() - 1;
dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex);
UA.push_back({dwarf::DW_IDX_compile_unit, Form});
}
UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
return UA;
}

template <typename DataT>
Expand All @@ -426,6 +433,17 @@ void Dwarf5AccelTableWriter<DataT>::emitCUList() const {
}
}

template <typename DataT>
void Dwarf5AccelTableWriter<DataT>::emitTUList() const {
for (const auto &TU : enumerate(TypeUnits)) {
Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
if (std::holds_alternative<MCSymbol *>(TU.value()))
Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
else
Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
}
}

template <typename DataT>
void Dwarf5AccelTableWriter<DataT>::emitBuckets() const {
uint32_t Index = 1;
Expand Down Expand Up @@ -453,10 +471,11 @@ void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {
Asm->OutStreamer->emitLabel(AbbrevStart);
for (const auto &Abbrev : Abbreviations) {
Asm->OutStreamer->AddComment("Abbrev code");
assert(Abbrev.first != 0);
Asm->emitULEB128(Abbrev.first);
Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first));
uint32_t Tag = getTagFromAbbreviationTag(Abbrev.first);
assert(Tag != 0);
Asm->emitULEB128(Abbrev.first);
Asm->OutStreamer->AddComment(dwarf::TagString(Tag));
Asm->emitULEB128(Tag);
for (const auto &AttrEnc : Abbrev.second) {
Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
Asm->emitULEB128(AttrEnc.Form,
Expand All @@ -471,16 +490,21 @@ void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {

template <typename DataT>
void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
auto AbbrevIt = Abbreviations.find(Entry.getDieTag());
GetIndexForEntryReturnType EntryRet = getIndexForEntry(Entry);
uint32_t AbbrvTag = constructAbbreviationTag(Entry.getDieTag(), EntryRet);
auto AbbrevIt = Abbreviations.find(AbbrvTag);
assert(AbbrevIt != Abbreviations.end() &&
"Why wasn't this abbrev generated?");

assert(getTagFromAbbreviationTag(AbbrevIt->first) == Entry.getDieTag() &&
"Invalid Tag");
Asm->emitULEB128(AbbrevIt->first, "Abbreviation code");

for (const auto &AttrEnc : AbbrevIt->second) {
Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
switch (AttrEnc.Index) {
case dwarf::DW_IDX_compile_unit: {
DIEInteger ID(getCUIndexForEntry(Entry));
case dwarf::DW_IDX_compile_unit:
case dwarf::DW_IDX_type_unit: {
DIEInteger ID(EntryRet->first);
ID.emitValue(Asm, AttrEnc.Form);
break;
}
Expand Down Expand Up @@ -512,22 +536,21 @@ template <typename DataT>
Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter(
AsmPrinter *Asm, const AccelTableBase &Contents,
ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry)
ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
llvm::function_ref<GetIndexForEntryReturnType(const DataT &)>
getIndexForEntry)
: AccelTableWriter(Asm, Contents, false),
Header(CompUnits.size(), Contents.getBucketCount(),
Header(CompUnits.size(), TypeUnits.size(), Contents.getBucketCount(),
Contents.getUniqueNameCount()),
CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) {
DenseSet<uint32_t> UniqueTags = getUniqueTags();
SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();

Abbreviations.reserve(UniqueTags.size());
for (uint32_t Tag : UniqueTags)
Abbreviations.try_emplace(Tag, UniformAttributes);
CompUnits(CompUnits), TypeUnits(TypeUnits),
getIndexForEntry(std::move(getIndexForEntry)) {
populateAbbrevsMap();
}

template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() {
Header.emit(*this);
emitCUList();
emitTUList();
emitBuckets();
emitHashes();
emitStringOffsets();
Expand All @@ -545,12 +568,17 @@ void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
}

void llvm::emitDWARF5AccelTable(
AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
void llvm::emitDWARF5AccelTable(AsmPrinter *Asm,
AccelTable<DWARF5AccelTableData> &Contents,
const DwarfDebug &DD,
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs,
ArrayRef<std::unique_ptr<DwarfTypeUnit>> TUs) {
std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
SmallVector<unsigned, 1> CUIndex(CUs.size());
int Count = 0;
DenseMap<const DIE *, unsigned> TUIndex(TUs.size());
int CUCount = 0;
int TUCount = 0;
for (const auto &CU : enumerate(CUs)) {
switch (CU.value()->getCUNode()->getNameTableKind()) {
case DICompileUnit::DebugNameTableKind::Default:
Expand All @@ -559,37 +587,61 @@ void llvm::emitDWARF5AccelTable(
default:
continue;
}
CUIndex[CU.index()] = Count++;
CUIndex[CU.index()] = CUCount++;
assert(CU.index() == CU.value()->getUniqueID());
const DwarfCompileUnit *MainCU =
DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
CompUnits.push_back(MainCU->getLabelBegin());
}

for (const auto &TU : enumerate(TUs)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this using enumerate if it's only using the values anyway? Perhaps this could iterate over TUs directly instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following the example of CUs iteration to try to keep coding style consistent.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a stylistic thing in this case - the CU iteration needed indexes, so it used enumerate, whereas the TU iteration doesn't need them, so it shouldn't use enumerate, I think.

(but, again, happy to wait on resolving a bunch of this stuff until we better understand the general approach/memory concerns, etc)

switch (TU.value()->getCUNode()->getNameTableKind()) {
case DICompileUnit::DebugNameTableKind::Default:
break;
default:
continue;
}
Comment on lines +598 to +603
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a bit convoluted (unless there's an expectation to add more here) compared to:

if (TU.value()->getCUNode()->getNameTableKind() != DICompileUnit::DebugNameTableKind::Default)
  continue;

TUIndex[&TU.value()->getUnitDie()] = TUCount++;
const DwarfTypeUnit *MainTU = TU.value().get();
TypeUnits.push_back(MainTU->getLabelBegin());
}

if (CompUnits.empty())
return;

Asm->OutStreamer->switchSection(
Asm->getObjFileLowering().getDwarfDebugNamesSection());

Contents.finalize(Asm, "names");
dwarf::Form CUIndexForm =
DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
dwarf::Form TUIndexForm =
DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
Dwarf5AccelTableWriter<DWARF5AccelTableData>(
Asm, Contents, CompUnits,
[&](const DWARF5AccelTableData &Entry) {
Asm, Contents, CompUnits, TypeUnits,
[&](const DWARF5AccelTableData &Entry) -> GetIndexForEntryReturnType {
const DIE *CUDie = Entry.getDie().getUnitDie();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CUDie might be a misleading name now that this might be a TUDie instead - UnitDie?

return CUIndex[DD.lookupCU(CUDie)->getUniqueID()];
GetIndexForEntryReturnType Index = std::nullopt;
if (CUDie->getTag() == dwarf::DW_TAG_type_unit)
Index = {TUIndex[CUDie], {dwarf::DW_IDX_type_unit, TUIndexForm}};
else if (CUIndex.size() > 1)
Index = {CUIndex[DD.lookupCU(CUDie)->getUniqueID()],
{dwarf::DW_IDX_compile_unit, CUIndexForm}};
return Index;
})
.emit();
}

void llvm::emitDWARF5AccelTable(
AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
getCUIndexForEntry) {
llvm::function_ref<
GetIndexForEntryReturnType(const DWARF5AccelTableStaticData &)>
getIndexForEntry) {
std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
Contents.finalize(Asm, "names");
Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs,
getCUIndexForEntry)
Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(
Asm, Contents, CUs, TypeUnits, getIndexForEntry)
.emit();
}

Expand Down
Loading