summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp244
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp89
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h24
3 files changed, 332 insertions, 25 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
index c80cc59691f..d6cfbdb37e5 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/AccelTable.h"
+#include "DwarfCompileUnit.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
@@ -86,6 +87,8 @@ void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
}
namespace {
+/// Base class for writing out Accelerator tables. It holds the common
+/// functionality for the two Accelerator table types.
class AccelTableEmitter {
protected:
AsmPrinter *const Asm; ///< Destination.
@@ -176,6 +179,63 @@ public:
void dump() const { print(dbgs()); }
#endif
};
+
+/// Class responsible for emitting a DWARF v5 Accelerator Table. The only public
+/// function is emit(), which performs the actual emission.
+class Dwarf5AccelTableEmitter : public AccelTableEmitter {
+ struct Header {
+ uint32_t UnitLength = 0;
+ uint16_t Version = 5;
+ uint16_t Padding = 0;
+ uint32_t CompUnitCount;
+ uint32_t LocalTypeUnitCount = 0;
+ uint32_t ForeignTypeUnitCount = 0;
+ uint32_t BucketCount;
+ uint32_t NameCount;
+ uint32_t AbbrevTableSize = 0;
+ 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) {}
+
+ void emit(const Dwarf5AccelTableEmitter &Ctx) const;
+ };
+ struct AttributeEncoding {
+ dwarf::Index Index;
+ dwarf::Form Form;
+ };
+
+ Header Header;
+ DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
+ const DwarfDebug &DD;
+ ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits;
+ MCSymbol *ContributionStart = Asm->createTempSymbol("names_start");
+ MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end");
+ 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 emitCUList() const;
+ void emitBuckets() const;
+ void emitStringOffsets() const;
+ void emitAbbrevs() const;
+ void emitEntry(const DWARF5AccelTableData &Data) const;
+ void emitData() const;
+
+public:
+ Dwarf5AccelTableEmitter(
+ AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD,
+ ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits);
+
+ void emit() const;
+};
} // namespace
void AccelTableEmitter::emitHashes() const {
@@ -294,6 +354,178 @@ void AppleAccelTableEmitter::emit() const {
emitData();
}
+void Dwarf5AccelTableEmitter::Header::emit(
+ const Dwarf5AccelTableEmitter &Ctx) const {
+ AsmPrinter *Asm = Ctx.Asm;
+ Asm->OutStreamer->AddComment("Header: unit length");
+ Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart,
+ sizeof(uint32_t));
+ Asm->OutStreamer->EmitLabel(Ctx.ContributionStart);
+ Asm->OutStreamer->AddComment("Header: version");
+ Asm->emitInt16(Version);
+ Asm->OutStreamer->AddComment("Header: padding");
+ Asm->emitInt16(Padding);
+ Asm->OutStreamer->AddComment("Header: compilation unit count");
+ Asm->emitInt32(CompUnitCount);
+ Asm->OutStreamer->AddComment("Header: local type unit count");
+ Asm->emitInt32(LocalTypeUnitCount);
+ Asm->OutStreamer->AddComment("Header: foreign type unit count");
+ Asm->emitInt32(ForeignTypeUnitCount);
+ Asm->OutStreamer->AddComment("Header: bucket count");
+ Asm->emitInt32(BucketCount);
+ Asm->OutStreamer->AddComment("Header: name count");
+ Asm->emitInt32(NameCount);
+ Asm->OutStreamer->AddComment("Header: abbreviation table size");
+ Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
+ Asm->OutStreamer->AddComment("Header: augmentation string size");
+ assert(AugmentationStringSize % 4 == 0);
+ Asm->emitInt32(AugmentationStringSize);
+ Asm->OutStreamer->AddComment("Header: augmentation string");
+ Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize});
+}
+
+DenseSet<uint32_t> Dwarf5AccelTableEmitter::getUniqueTags() const {
+ DenseSet<uint32_t> UniqueTags;
+ for (auto &Bucket : Contents.getBuckets()) {
+ for (auto *Hash : Bucket) {
+ for (auto *Value : Hash->Values) {
+ const DIE &Die =
+ static_cast<const DWARF5AccelTableData *>(Value)->getDie();
+ UniqueTags.insert(Die.getTag());
+ }
+ }
+ }
+ return UniqueTags;
+}
+
+SmallVector<Dwarf5AccelTableEmitter::AttributeEncoding, 2>
+Dwarf5AccelTableEmitter::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;
+}
+
+void Dwarf5AccelTableEmitter::emitCUList() const {
+ for (const auto &CU : enumerate(CompUnits)) {
+ assert(CU.index() == CU.value()->getUniqueID());
+ Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
+ Asm->emitDwarfSymbolReference(CU.value()->getLabelBegin());
+ }
+}
+
+void Dwarf5AccelTableEmitter::emitBuckets() const {
+ uint32_t Index = 1;
+ for (const auto &Bucket : enumerate(Contents.getBuckets())) {
+ Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
+ Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
+ Index += Bucket.value().size();
+ }
+}
+
+void Dwarf5AccelTableEmitter::emitStringOffsets() const {
+ for (const auto &Bucket : enumerate(Contents.getBuckets())) {
+ for (auto *Hash : Bucket.value()) {
+ DwarfStringPoolEntryRef String = Hash->Name;
+ Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
+ ": " + String.getString());
+ Asm->emitDwarfStringOffset(String);
+ }
+ }
+}
+
+void Dwarf5AccelTableEmitter::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));
+ Asm->EmitULEB128(Abbrev.first);
+ for (const auto &AttrEnc : Abbrev.second) {
+ Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
+ Asm->EmitULEB128(AttrEnc.Form,
+ dwarf::FormEncodingString(AttrEnc.Form).data());
+ }
+ Asm->EmitULEB128(0, "End of abbrev");
+ Asm->EmitULEB128(0, "End of abbrev");
+ }
+ Asm->EmitULEB128(0, "End of abbrev list");
+ Asm->OutStreamer->EmitLabel(AbbrevEnd);
+}
+
+void Dwarf5AccelTableEmitter::emitEntry(
+ const DWARF5AccelTableData &Entry) const {
+ auto AbbrevIt = Abbreviations.find(Entry.getDie().getTag());
+ assert(AbbrevIt != Abbreviations.end() &&
+ "Why wasn't this abbrev generated?");
+
+ 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: {
+ const DIE *CUDie = Entry.getDie().getUnitDie();
+ DIEInteger ID(DD.lookupCU(CUDie)->getUniqueID());
+ ID.EmitValue(Asm, AttrEnc.Form);
+ break;
+ }
+ case dwarf::DW_IDX_die_offset:
+ assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
+ Asm->emitInt32(Entry.getDie().getOffset());
+ break;
+ default:
+ llvm_unreachable("Unexpected index attribute!");
+ }
+ }
+}
+
+void Dwarf5AccelTableEmitter::emitData() const {
+ Asm->OutStreamer->EmitLabel(EntryPool);
+ for (auto &Bucket : Contents.getBuckets()) {
+ for (auto *Hash : Bucket) {
+ // Remember to emit the label for our offset.
+ Asm->OutStreamer->EmitLabel(Hash->Sym);
+ for (const auto *Value : Hash->Values)
+ emitEntry(*static_cast<const DWARF5AccelTableData *>(Value));
+ Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
+ Asm->emitInt32(0);
+ }
+ }
+}
+
+Dwarf5AccelTableEmitter::Dwarf5AccelTableEmitter(
+ AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD,
+ ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits)
+ : AccelTableEmitter(Asm, Contents, false),
+ Header(CompUnits.size(), Contents.getBucketCount(),
+ Contents.getUniqueNameCount()),
+ DD(DD), CompUnits(CompUnits) {
+ DenseSet<uint32_t> UniqueTags = getUniqueTags();
+ SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();
+
+ Abbreviations.reserve(UniqueTags.size());
+ for (uint32_t Tag : UniqueTags)
+ Abbreviations.try_emplace(Tag, UniformAttributes);
+}
+
+void Dwarf5AccelTableEmitter::emit() const {
+ Header.emit(*this);
+ emitCUList();
+ emitBuckets();
+ emitHashes();
+ emitStringOffsets();
+ emitOffsets(EntryPool);
+ emitAbbrevs();
+ emitData();
+ Asm->OutStreamer->EmitValueToAlignment(4, 0);
+ Asm->OutStreamer->EmitLabel(ContributionEnd);
+}
+
void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
StringRef Prefix, const MCSymbol *SecBegin,
ArrayRef<AppleAccelTableData::Atom> Atoms) {
@@ -301,6 +533,13 @@ void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
AppleAccelTableEmitter(Asm, Contents, Atoms, SecBegin).emit();
}
+void llvm::emitDWARF5AccelTable(
+ AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
+ const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
+ Contents.finalize(Asm, "names");
+ Dwarf5AccelTableEmitter(Asm, Contents, DD, CUs).emit();
+}
+
void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
Asm->emitInt32(Die->getDebugSectionOffset());
}
@@ -407,6 +646,11 @@ void AccelTableBase::print(raw_ostream &OS) const {
E.second.print(OS);
}
+void DWARF5AccelTableData::print(raw_ostream &OS) const {
+ OS << " Offset: " << Die.getOffset() << "\n";
+ OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
+}
+
void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
OS << " Offset: " << Die->getOffset() << "\n";
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 7353875ad39..76a360d2ca2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -107,13 +107,14 @@ static cl::opt<DefaultOnOff> UnknownLocations(
clEnumVal(Enable, "In all cases"), clEnumVal(Disable, "Never")),
cl::init(Default));
-static cl::opt<DefaultOnOff>
-DwarfAccelTables("dwarf-accel-tables", cl::Hidden,
- cl::desc("Output prototype dwarf accelerator tables."),
- cl::values(clEnumVal(Default, "Default for platform"),
- clEnumVal(Enable, "Enabled"),
- clEnumVal(Disable, "Disabled")),
- cl::init(Default));
+static cl::opt<AccelTableKind> AccelTables(
+ "accel-tables", cl::Hidden, cl::desc("Output dwarf accelerator tables."),
+ cl::values(clEnumValN(AccelTableKind::Default, "Default",
+ "Default for platform"),
+ clEnumValN(AccelTableKind::None, "Disable", "Disabled."),
+ clEnumValN(AccelTableKind::Apple, "Apple", "Apple"),
+ clEnumValN(AccelTableKind::Dwarf, "Dwarf", "DWARF")),
+ cl::init(AccelTableKind::Default));
static cl::opt<DefaultOnOff>
DwarfInlinedStrings("dwarf-inlined-strings", cl::Hidden,
@@ -303,11 +304,13 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
// Turn on accelerator tables by default, if tuning for LLDB and the target is
// supported.
- if (DwarfAccelTables == Default)
- HasDwarfAccelTables =
- tuneForLLDB() && A->TM.getTargetTriple().isOSBinFormatMachO();
- else
- HasDwarfAccelTables = DwarfAccelTables == Enable;
+ if (AccelTables == AccelTableKind::Default) {
+ if (tuneForLLDB() && A->TM.getTargetTriple().isOSBinFormatMachO())
+ AccelTableKind = AccelTableKind::Apple;
+ else
+ AccelTableKind = AccelTableKind::None;
+ } else
+ AccelTableKind = AccelTables;
UseInlineStrings = DwarfInlinedStrings == Enable;
HasAppleExtensionAttributes = tuneForLLDB();
@@ -839,11 +842,20 @@ void DwarfDebug::endModule() {
}
// Emit info into the dwarf accelerator table sections.
- if (useDwarfAccelTables()) {
+ switch (getAccelTableKind()) {
+ case AccelTableKind::Apple:
emitAccelNames();
emitAccelObjC();
emitAccelNamespaces();
emitAccelTypes();
+ break;
+ case AccelTableKind::Dwarf:
+ emitAccelDebugNames();
+ break;
+ case AccelTableKind::None:
+ break;
+ case AccelTableKind::Default:
+ llvm_unreachable("Default should have already been resolved.");
}
// Emit the pubnames and pubtypes sections if requested.
@@ -1455,6 +1467,12 @@ void DwarfDebug::emitAccel(AccelTableT &Accel, MCSection *Section,
emitAppleAccelTable(Asm, Accel, TableName, Section->getBeginSymbol());
}
+void DwarfDebug::emitAccelDebugNames() {
+ Asm->OutStreamer->SwitchSection(
+ Asm->getObjFileLowering().getDwarfDebugNamesSection());
+ emitDWARF5AccelTable(Asm, AccelDebugNames, *this, getUnits());
+}
+
// Emit visible names into a hashed accelerator table section.
void DwarfDebug::emitAccelNames() {
emitAccel(AccelNames, Asm->getObjFileLowering().getDwarfAccelNamesSection(),
@@ -2250,27 +2268,58 @@ void DwarfDebug::addDwarfTypeUnitType(DwarfCompileUnit &CU,
// to reference is in the string table. We do this since the names we
// add may not only be identical to the names in the DIE.
void DwarfDebug::addAccelName(StringRef Name, const DIE &Die) {
- if (!useDwarfAccelTables())
+ switch (getAccelTableKind()) {
+ case AccelTableKind::Apple:
+ AccelNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die);
+ break;
+ case AccelTableKind::Dwarf:
+ AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name),
+ Die);
+ break;
+ case AccelTableKind::None:
return;
- AccelNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die);
+ case AccelTableKind::Default:
+ llvm_unreachable("Default should have already been resolved.");
+ }
}
void DwarfDebug::addAccelObjC(StringRef Name, const DIE &Die) {
- if (!useDwarfAccelTables())
+ if (getAccelTableKind() != AccelTableKind::Apple)
return;
AccelObjC.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die);
}
void DwarfDebug::addAccelNamespace(StringRef Name, const DIE &Die) {
- if (!useDwarfAccelTables())
+ switch (getAccelTableKind()) {
+ case AccelTableKind::Apple:
+ AccelNamespace.addName(InfoHolder.getStringPool().getEntry(*Asm, Name),
+ &Die);
+ break;
+ case AccelTableKind::Dwarf:
+ AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name),
+ Die);
+ break;
+ case AccelTableKind::None:
return;
- AccelNamespace.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die);
+ case AccelTableKind::Default:
+ llvm_unreachable("Default should have already been resolved.");
+ }
}
void DwarfDebug::addAccelType(StringRef Name, const DIE &Die, char Flags) {
- if (!useDwarfAccelTables())
+ switch (getAccelTableKind()) {
+ case AccelTableKind::Apple:
+ AccelTypes.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die);
+ break;
+ case AccelTableKind::Dwarf:
+ AccelDebugNames.addName(InfoHolder.getStringPool().getEntry(*Asm, Name),
+ Die);
+ break;
+ case AccelTableKind::None:
return;
- AccelTypes.addName(InfoHolder.getStringPool().getEntry(*Asm, Name), &Die);
+ case AccelTableKind::Default:
+ llvm_unreachable("Default should have already been resolved.");
+ }
}
uint16_t DwarfDebug::getDwarfVersion() const {
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 3ee78710e8f..b1703e9a46a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -192,6 +192,14 @@ struct SymbolCU {
DwarfCompileUnit *CU;
};
+/// The kind of accelerator tables we should emit.
+enum class AccelTableKind {
+ Default, ///< Platform default.
+ None, ///< None.
+ Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc.
+ Dwarf, ///< DWARF v5 .debug_names.
+};
+
/// Collects and handles dwarf debug information.
class DwarfDebug : public DebugHandlerBase {
/// All DIEValues are allocated through this allocator.
@@ -270,7 +278,7 @@ class DwarfDebug : public DebugHandlerBase {
/// DWARF5 Experimental Options
/// @{
- bool HasDwarfAccelTables;
+ AccelTableKind AccelTableKind;
bool HasAppleExtensionAttributes;
bool HasSplitDwarf;
@@ -302,7 +310,8 @@ class DwarfDebug : public DebugHandlerBase {
AddressPool AddrPool;
- /// Apple accelerator tables.
+ /// Accelerator tables.
+ AccelTable<DWARF5AccelTableData> AccelDebugNames;
AccelTable<AppleAccelTableOffsetData> AccelNames;
AccelTable<AppleAccelTableOffsetData> AccelObjC;
AccelTable<AppleAccelTableOffsetData> AccelNamespace;
@@ -351,6 +360,9 @@ class DwarfDebug : public DebugHandlerBase {
template <typename AccelTableT>
void emitAccel(AccelTableT &Accel, MCSection *Section, StringRef TableName);
+ /// Emit DWARF v5 accelerator table.
+ void emitAccelDebugNames();
+
/// Emit visible names into a hashed accelerator table section.
void emitAccelNames();
@@ -523,9 +535,8 @@ public:
// Experimental DWARF5 features.
- /// Returns whether or not to emit tables that dwarf consumers can
- /// use to accelerate lookup.
- bool useDwarfAccelTables() const { return HasDwarfAccelTables; }
+ /// Returns what kind (if any) of accelerator tables to emit.
+ llvm::AccelTableKind getAccelTableKind() const { return AccelTableKind; }
bool useAppleExtensionAttributes() const {
return HasAppleExtensionAttributes;
@@ -590,6 +601,9 @@ public:
/// Find the matching DwarfCompileUnit for the given CU DIE.
DwarfCompileUnit *lookupCU(const DIE *Die) { return CUDieMap.lookup(Die); }
+ const DwarfCompileUnit *lookupCU(const DIE *Die) const {
+ return CUDieMap.lookup(Die);
+ }
/// \defgroup DebuggerTuning Predicates to tune DWARF for a given debugger.
///
OpenPOWER on IntegriCloud