aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp839
1 files changed, 839 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
new file mode 100644
index 000000000000..4957f70b23f0
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
@@ -0,0 +1,839 @@
+//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for writing accelerator tables.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/AccelTable.h"
+#include "DwarfCompileUnit.h"
+#include "DwarfUnit.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <vector>
+
+using namespace llvm;
+
+void AccelTableBase::computeBucketCount() {
+ SmallVector<uint32_t, 0> Uniques;
+ Uniques.reserve(Entries.size());
+ for (const auto &E : Entries)
+ Uniques.push_back(E.second.HashValue);
+ llvm::sort(Uniques);
+ UniqueHashCount = llvm::unique(Uniques) - Uniques.begin();
+ BucketCount = dwarf::getDebugNamesBucketCount(UniqueHashCount);
+}
+
+void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
+ // Create the individual hash data outputs.
+ for (auto &E : Entries) {
+ // Unique the entries.
+ llvm::stable_sort(E.second.Values,
+ [](const AccelTableData *A, const AccelTableData *B) {
+ return *A < *B;
+ });
+ E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end());
+ }
+
+ // Figure out how many buckets we need, then compute the bucket contents and
+ // the final ordering. The hashes and offsets can be emitted by walking these
+ // data structures. We add temporary symbols to the data so they can be
+ // referenced when emitting the offsets.
+ computeBucketCount();
+
+ // Compute bucket contents and final ordering.
+ Buckets.resize(BucketCount);
+ for (auto &E : Entries) {
+ uint32_t Bucket = E.second.HashValue % BucketCount;
+ Buckets[Bucket].push_back(&E.second);
+ E.second.Sym = Asm->createTempSymbol(Prefix);
+ }
+
+ // Sort the contents of the buckets by hash value so that hash collisions end
+ // up together. Stable sort makes testing easier and doesn't cost much more.
+ for (auto &Bucket : Buckets)
+ llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
+ return LHS->HashValue < RHS->HashValue;
+ });
+}
+
+namespace {
+/// Base class for writing out Accelerator tables. It holds the common
+/// functionality for the two Accelerator table types.
+class AccelTableWriter {
+protected:
+ AsmPrinter *const Asm; ///< Destination.
+ const AccelTableBase &Contents; ///< Data to emit.
+
+ /// Controls whether to emit duplicate hash and offset table entries for names
+ /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
+ /// tables do.
+ const bool SkipIdenticalHashes;
+
+ void emitHashes() const;
+
+ /// Emit offsets to lists of entries with identical names. The offsets are
+ /// relative to the Base argument.
+ void emitOffsets(const MCSymbol *Base) const;
+
+public:
+ AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
+ bool SkipIdenticalHashes)
+ : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
+ }
+};
+
+class AppleAccelTableWriter : public AccelTableWriter {
+ using Atom = AppleAccelTableData::Atom;
+
+ /// The fixed header of an Apple Accelerator Table.
+ struct Header {
+ uint32_t Magic = MagicHash;
+ uint16_t Version = 1;
+ uint16_t HashFunction = dwarf::DW_hash_function_djb;
+ uint32_t BucketCount;
+ uint32_t HashCount;
+ uint32_t HeaderDataLength;
+
+ /// 'HASH' magic value to detect endianness.
+ static const uint32_t MagicHash = 0x48415348;
+
+ Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
+ : BucketCount(BucketCount), HashCount(UniqueHashCount),
+ HeaderDataLength(DataLength) {}
+
+ void emit(AsmPrinter *Asm) const;
+#ifndef NDEBUG
+ void print(raw_ostream &OS) const;
+ void dump() const { print(dbgs()); }
+#endif
+ };
+
+ /// The HeaderData describes the structure of an Apple accelerator table
+ /// through a list of Atoms.
+ struct HeaderData {
+ /// In the case of data that is referenced via DW_FORM_ref_* the offset
+ /// base is used to describe the offset for all forms in the list of atoms.
+ uint32_t DieOffsetBase;
+
+ const SmallVector<Atom, 4> Atoms;
+
+ HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
+ : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
+
+ void emit(AsmPrinter *Asm) const;
+#ifndef NDEBUG
+ void print(raw_ostream &OS) const;
+ void dump() const { print(dbgs()); }
+#endif
+ };
+
+ Header Header;
+ HeaderData HeaderData;
+ const MCSymbol *SecBegin;
+
+ void emitBuckets() const;
+ void emitData() const;
+
+public:
+ AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
+ ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
+ : AccelTableWriter(Asm, Contents, true),
+ Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
+ 8 + (Atoms.size() * 4)),
+ HeaderData(Atoms), SecBegin(SecBegin) {}
+
+ void emit() const;
+
+#ifndef NDEBUG
+ void print(raw_ostream &OS) const;
+ 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.
+///
+/// A callback abstracts the logic to provide a CU index for a given entry.
+class Dwarf5AccelTableWriter : public AccelTableWriter {
+ struct Header {
+ uint16_t Version = 5;
+ uint16_t Padding = 0;
+ uint32_t CompUnitCount;
+ uint32_t LocalTypeUnitCount = 0;
+ uint32_t ForeignTypeUnitCount = 0;
+ uint32_t BucketCount = 0;
+ uint32_t NameCount = 0;
+ 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 LocalTypeUnitCount,
+ uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
+ uint32_t NameCount)
+ : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
+ ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
+ NameCount(NameCount) {}
+
+ void emit(Dwarf5AccelTableWriter &Ctx);
+ };
+
+ Header Header;
+ /// FoldingSet that uniques the abbreviations.
+ FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
+ /// Vector containing DebugNames abbreviations for iteration in order.
+ SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
+ /// The bump allocator to use when creating DIEAbbrev objects in the uniqued
+ /// storage container.
+ BumpPtrAllocator Alloc;
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
+ llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
+ const DWARF5AccelTableData &)>
+ getIndexForEntry;
+ MCSymbol *ContributionEnd = nullptr;
+ MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
+ MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
+ MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
+ // Indicates if this module is built with Split Dwarf enabled.
+ bool IsSplitDwarf = false;
+ /// Stores the DIE offsets which are indexed by this table.
+ DenseSet<OffsetAndUnitID> IndexedOffsets;
+
+ void populateAbbrevsMap();
+
+ void emitCUList() const;
+ void emitTUList() const;
+ void emitBuckets() const;
+ void emitStringOffsets() const;
+ void emitAbbrevs() const;
+ void emitEntry(
+ const DWARF5AccelTableData &Entry,
+ const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
+ DenseSet<MCSymbol *> &EmittedAccelEntrySymbols);
+ void emitData();
+
+public:
+ Dwarf5AccelTableWriter(
+ AsmPrinter *Asm, const AccelTableBase &Contents,
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
+ llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
+ const DWARF5AccelTableData &)>
+ getIndexForEntry,
+ bool IsSplitDwarf);
+ ~Dwarf5AccelTableWriter() {
+ for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
+ Abbrev->~DebugNamesAbbrev();
+ }
+ void emit();
+};
+} // namespace
+
+void AccelTableWriter::emitHashes() const {
+ uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
+ unsigned BucketIdx = 0;
+ for (const auto &Bucket : Contents.getBuckets()) {
+ for (const auto &Hash : Bucket) {
+ uint32_t HashValue = Hash->HashValue;
+ if (SkipIdenticalHashes && PrevHash == HashValue)
+ continue;
+ Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
+ Asm->emitInt32(HashValue);
+ PrevHash = HashValue;
+ }
+ BucketIdx++;
+ }
+}
+
+void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
+ const auto &Buckets = Contents.getBuckets();
+ uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
+ for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
+ for (auto *Hash : Buckets[i]) {
+ uint32_t HashValue = Hash->HashValue;
+ if (SkipIdenticalHashes && PrevHash == HashValue)
+ continue;
+ PrevHash = HashValue;
+ Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
+ Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
+ }
+ }
+}
+
+void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
+ Asm->OutStreamer->AddComment("Header Magic");
+ Asm->emitInt32(Magic);
+ Asm->OutStreamer->AddComment("Header Version");
+ Asm->emitInt16(Version);
+ Asm->OutStreamer->AddComment("Header Hash Function");
+ Asm->emitInt16(HashFunction);
+ Asm->OutStreamer->AddComment("Header Bucket Count");
+ Asm->emitInt32(BucketCount);
+ Asm->OutStreamer->AddComment("Header Hash Count");
+ Asm->emitInt32(HashCount);
+ Asm->OutStreamer->AddComment("Header Data Length");
+ Asm->emitInt32(HeaderDataLength);
+}
+
+void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
+ Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
+ Asm->emitInt32(DieOffsetBase);
+ Asm->OutStreamer->AddComment("HeaderData Atom Count");
+ Asm->emitInt32(Atoms.size());
+
+ for (const Atom &A : Atoms) {
+ Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
+ Asm->emitInt16(A.Type);
+ Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
+ Asm->emitInt16(A.Form);
+ }
+}
+
+void AppleAccelTableWriter::emitBuckets() const {
+ const auto &Buckets = Contents.getBuckets();
+ unsigned index = 0;
+ for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
+ Asm->OutStreamer->AddComment("Bucket " + Twine(i));
+ if (!Buckets[i].empty())
+ Asm->emitInt32(index);
+ else
+ Asm->emitInt32(std::numeric_limits<uint32_t>::max());
+ // Buckets point in the list of hashes, not to the data. Do not increment
+ // the index multiple times in case of hash collisions.
+ uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
+ for (auto *HD : Buckets[i]) {
+ uint32_t HashValue = HD->HashValue;
+ if (PrevHash != HashValue)
+ ++index;
+ PrevHash = HashValue;
+ }
+ }
+}
+
+void AppleAccelTableWriter::emitData() const {
+ const auto &Buckets = Contents.getBuckets();
+ for (const AccelTableBase::HashList &Bucket : Buckets) {
+ uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
+ for (const auto &Hash : Bucket) {
+ // Terminate the previous entry if there is no hash collision with the
+ // current one.
+ if (PrevHash != std::numeric_limits<uint64_t>::max() &&
+ PrevHash != Hash->HashValue)
+ Asm->emitInt32(0);
+ // Remember to emit the label for our offset.
+ Asm->OutStreamer->emitLabel(Hash->Sym);
+ Asm->OutStreamer->AddComment(Hash->Name.getString());
+ Asm->emitDwarfStringOffset(Hash->Name);
+ Asm->OutStreamer->AddComment("Num DIEs");
+ Asm->emitInt32(Hash->Values.size());
+ for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
+ V->emit(Asm);
+ PrevHash = Hash->HashValue;
+ }
+ // Emit the final end marker for the bucket.
+ if (!Bucket.empty())
+ Asm->emitInt32(0);
+ }
+}
+
+void AppleAccelTableWriter::emit() const {
+ Header.emit(Asm);
+ HeaderData.emit(Asm);
+ emitBuckets();
+ emitHashes();
+ emitOffsets(SecBegin);
+ emitData();
+}
+
+DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
+ const uint32_t UnitID,
+ const bool IsTU)
+ : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
+ UnitID(UnitID) {}
+
+void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
+ assert(CompUnitCount > 0 && "Index must have at least one CU.");
+
+ AsmPrinter *Asm = Ctx.Asm;
+ Ctx.ContributionEnd =
+ Asm->emitDwarfUnitLength("names", "Header: unit length");
+ 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});
+}
+
+std::optional<uint64_t>
+DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
+ if (auto *Parent = Die.getParent();
+ Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
+ return Parent->getOffset();
+ return {};
+}
+
+static std::optional<dwarf::Form>
+getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
+ std::optional<OffsetAndUnitID> ParentOffset) {
+ // No parent information
+ if (!ParentOffset)
+ return std::nullopt;
+ // Parent is indexed by this table.
+ if (IndexedOffsets.contains(*ParentOffset))
+ return dwarf::Form::DW_FORM_ref4;
+ // Parent is not indexed by this table.
+ return dwarf::Form::DW_FORM_flag_present;
+}
+
+void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const {
+ ID.AddInteger(DieTag);
+ for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
+ ID.AddInteger(Enc.Index);
+ ID.AddInteger(Enc.Form);
+ }
+}
+
+void Dwarf5AccelTableWriter::populateAbbrevsMap() {
+ for (auto &Bucket : Contents.getBuckets()) {
+ for (auto *Hash : Bucket) {
+ for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
+ std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
+ getIndexForEntry(*Value);
+ std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
+ IndexedOffsets, Value->getParentDieOffsetAndUnitID());
+ DebugNamesAbbrev Abbrev(Value->getDieTag());
+ if (EntryRet)
+ Abbrev.addAttribute(EntryRet->Encoding);
+ Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
+ if (MaybeParentForm)
+ Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
+ FoldingSetNodeID ID;
+ Abbrev.Profile(ID);
+ void *InsertPos;
+ if (DebugNamesAbbrev *Existing =
+ AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
+ Value->setAbbrevNumber(Existing->getNumber());
+ continue;
+ }
+ DebugNamesAbbrev *NewAbbrev =
+ new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
+ AbbreviationsVector.push_back(NewAbbrev);
+ NewAbbrev->setNumber(AbbreviationsVector.size());
+ AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);
+ Value->setAbbrevNumber(NewAbbrev->getNumber());
+ }
+ }
+ }
+}
+
+void Dwarf5AccelTableWriter::emitCUList() const {
+ for (const auto &CU : enumerate(CompUnits)) {
+ Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
+ if (std::holds_alternative<MCSymbol *>(CU.value()))
+ Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
+ else
+ Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
+ }
+}
+
+void Dwarf5AccelTableWriter::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 if (IsSplitDwarf)
+ Asm->emitInt64(std::get<uint64_t>(TU.value()));
+ else
+ Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
+ }
+}
+
+void Dwarf5AccelTableWriter::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 Dwarf5AccelTableWriter::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 Dwarf5AccelTableWriter::emitAbbrevs() const {
+ Asm->OutStreamer->emitLabel(AbbrevStart);
+ for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
+ Asm->OutStreamer->AddComment("Abbrev code");
+ Asm->emitULEB128(Abbrev->getNumber());
+ Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
+ Asm->emitULEB128(Abbrev->getDieTag());
+ for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
+ Abbrev->getAttributes()) {
+ 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 Dwarf5AccelTableWriter::emitEntry(
+ const DWARF5AccelTableData &Entry,
+ const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
+ DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) {
+ unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
+ assert(AbbrevIndex < AbbreviationsVector.size() &&
+ "Entry abbrev index is outside of abbreviations vector range.");
+ DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
+ std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
+ getIndexForEntry(Entry);
+ std::optional<OffsetAndUnitID> MaybeParentOffset =
+ Entry.getParentDieOffsetAndUnitID();
+ auto EntrySymbolIt =
+ DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
+ assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
+ MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
+
+ // Emit the label for this Entry, so that IDX_parents may refer to it.
+ // Note: a DIE may have multiple accelerator Entries; this check avoids
+ // creating/emitting multiple labels for the same DIE.
+ if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
+ Asm->OutStreamer->emitLabel(EntrySymbol);
+
+ Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
+
+ for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
+ Abbrev->getAttributes()) {
+ Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
+ switch (AttrEnc.Index) {
+ case dwarf::DW_IDX_compile_unit:
+ case dwarf::DW_IDX_type_unit: {
+ DIEInteger ID(EntryRet->Index);
+ ID.emitValue(Asm, AttrEnc.Form);
+ break;
+ }
+ case dwarf::DW_IDX_die_offset:
+ assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
+ Asm->emitInt32(Entry.getDieOffset());
+ break;
+ case dwarf::DW_IDX_parent: {
+ if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
+ break;
+ auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
+ assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
+ Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
+ break;
+ }
+ default:
+ llvm_unreachable("Unexpected index attribute!");
+ }
+ }
+}
+
+void Dwarf5AccelTableWriter::emitData() {
+ DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
+
+ for (OffsetAndUnitID Offset : IndexedOffsets)
+ DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
+
+ Asm->OutStreamer->emitLabel(EntryPool);
+ DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
+ 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->getValues<DWARF5AccelTableData *>())
+ emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
+ Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
+ Asm->emitInt8(0);
+ }
+ }
+}
+
+Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
+ AsmPrinter *Asm, const AccelTableBase &Contents,
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
+ llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
+ const DWARF5AccelTableData &)>
+ getIndexForEntry,
+ bool IsSplitDwarf)
+ : AccelTableWriter(Asm, Contents, false),
+ Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
+ IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
+ Contents.getUniqueNameCount()),
+ CompUnits(CompUnits), TypeUnits(TypeUnits),
+ getIndexForEntry(std::move(getIndexForEntry)),
+ IsSplitDwarf(IsSplitDwarf) {
+
+ for (auto &Bucket : Contents.getBuckets())
+ for (auto *Hash : Bucket)
+ for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
+ IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
+
+ populateAbbrevsMap();
+}
+
+void Dwarf5AccelTableWriter::emit() {
+ Header.emit(*this);
+ emitCUList();
+ emitTUList();
+ emitBuckets();
+ emitHashes();
+ emitStringOffsets();
+ emitOffsets(EntryPool);
+ emitAbbrevs();
+ emitData();
+ Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
+ Asm->OutStreamer->emitLabel(ContributionEnd);
+}
+
+void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
+ StringRef Prefix, const MCSymbol *SecBegin,
+ ArrayRef<AppleAccelTableData::Atom> Atoms) {
+ Contents.finalize(Asm, Prefix);
+ AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
+}
+
+void llvm::emitDWARF5AccelTable(
+ AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
+ ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
+ TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
+ std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
+ std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
+ SmallVector<unsigned, 1> CUIndex(CUs.size());
+ DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
+ int CUCount = 0;
+ int TUCount = 0;
+ for (const auto &CU : enumerate(CUs)) {
+ switch (CU.value()->getCUNode()->getNameTableKind()) {
+ case DICompileUnit::DebugNameTableKind::Default:
+ case DICompileUnit::DebugNameTableKind::Apple:
+ break;
+ default:
+ continue;
+ }
+ 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 : TUSymbols) {
+ TUIndex[TU.UniqueID] = TUCount++;
+ if (DD.useSplitDwarf())
+ TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
+ else
+ TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
+ }
+
+ 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(
+ Asm, Contents, CompUnits, TypeUnits,
+ [&](const DWARF5AccelTableData &Entry)
+ -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
+ if (Entry.isTU())
+ return {{TUIndex[Entry.getUnitID()],
+ {dwarf::DW_IDX_type_unit, TUIndexForm}}};
+ if (CUIndex.size() > 1)
+ return {{CUIndex[Entry.getUnitID()],
+ {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
+ return std::nullopt;
+ },
+ DD.useSplitDwarf())
+ .emit();
+}
+
+void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
+ TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
+}
+
+void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
+ TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
+}
+
+void llvm::emitDWARF5AccelTable(
+ AsmPrinter *Asm, DWARF5AccelTable &Contents,
+ ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
+ llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
+ const DWARF5AccelTableData &)>
+ getIndexForEntry) {
+ std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
+ Contents.finalize(Asm, "names");
+ Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
+ .emit();
+}
+
+void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
+ assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
+ "The section offset exceeds the limit.");
+ Asm->emitInt32(Die.getDebugSectionOffset());
+}
+
+void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
+ assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
+ "The section offset exceeds the limit.");
+ Asm->emitInt32(Die.getDebugSectionOffset());
+ Asm->emitInt16(Die.getTag());
+ Asm->emitInt8(0);
+}
+
+void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
+ Asm->emitInt32(Offset);
+}
+
+void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
+ Asm->emitInt32(Offset);
+ Asm->emitInt16(Tag);
+ Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
+ : 0);
+ Asm->emitInt32(QualifiedNameHash);
+}
+
+constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
+constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
+constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
+constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
+
+#ifndef NDEBUG
+void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
+ OS << "Magic: " << format("0x%x", Magic) << "\n"
+ << "Version: " << Version << "\n"
+ << "Hash Function: " << HashFunction << "\n"
+ << "Bucket Count: " << BucketCount << "\n"
+ << "Header Data Length: " << HeaderDataLength << "\n";
+}
+
+void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
+ OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
+ << "Form: " << dwarf::FormEncodingString(Form) << "\n";
+}
+
+void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
+ OS << "DIE Offset Base: " << DieOffsetBase << "\n";
+ for (auto Atom : Atoms)
+ Atom.print(OS);
+}
+
+void AppleAccelTableWriter::print(raw_ostream &OS) const {
+ Header.print(OS);
+ HeaderData.print(OS);
+ Contents.print(OS);
+ SecBegin->print(OS, nullptr);
+}
+
+void AccelTableBase::HashData::print(raw_ostream &OS) const {
+ OS << "Name: " << Name.getString() << "\n";
+ OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
+ OS << " Symbol: ";
+ if (Sym)
+ OS << *Sym;
+ else
+ OS << "<none>";
+ OS << "\n";
+ for (auto *Value : Values)
+ Value->print(OS);
+}
+
+void AccelTableBase::print(raw_ostream &OS) const {
+ // Print Content.
+ OS << "Entries: \n";
+ for (const auto &[Name, Data] : Entries) {
+ OS << "Name: " << Name << "\n";
+ for (auto *V : Data.Values)
+ V->print(OS);
+ }
+
+ OS << "Buckets and Hashes: \n";
+ for (const auto &Bucket : Buckets)
+ for (const auto &Hash : Bucket)
+ Hash->print(OS);
+
+ OS << "Data: \n";
+ for (const auto &E : Entries)
+ E.second.print(OS);
+}
+
+void DWARF5AccelTableData::print(raw_ostream &OS) const {
+ OS << " Offset: " << getDieOffset() << "\n";
+ OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
+}
+
+void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
+ OS << " Offset: " << Die.getOffset() << "\n";
+}
+
+void AppleAccelTableTypeData::print(raw_ostream &OS) const {
+ OS << " Offset: " << Die.getOffset() << "\n";
+ OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
+}
+
+void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
+ OS << " Static Offset: " << Offset << "\n";
+}
+
+void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
+ OS << " Static Offset: " << Offset << "\n";
+ OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
+ OS << " Tag: " << dwarf::TagString(Tag) << "\n";
+ OS << " ObjCClassIsImplementation: "
+ << (ObjCClassIsImplementation ? "true" : "false");
+ OS << "\n";
+}
+#endif