Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp
35271 views
//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains support for writing accelerator tables.9//10//===----------------------------------------------------------------------===//1112#include "llvm/CodeGen/AccelTable.h"13#include "DwarfCompileUnit.h"14#include "DwarfUnit.h"15#include "llvm/ADT/DenseSet.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/Twine.h"18#include "llvm/BinaryFormat/Dwarf.h"19#include "llvm/CodeGen/AsmPrinter.h"20#include "llvm/CodeGen/DIE.h"21#include "llvm/MC/MCStreamer.h"22#include "llvm/MC/MCSymbol.h"23#include "llvm/Support/raw_ostream.h"24#include "llvm/Target/TargetLoweringObjectFile.h"25#include <algorithm>26#include <cstddef>27#include <cstdint>28#include <limits>29#include <vector>3031using namespace llvm;3233void AccelTableBase::computeBucketCount() {34SmallVector<uint32_t, 0> Uniques;35Uniques.reserve(Entries.size());36for (const auto &E : Entries)37Uniques.push_back(E.second.HashValue);38llvm::sort(Uniques);39UniqueHashCount = llvm::unique(Uniques) - Uniques.begin();40BucketCount = dwarf::getDebugNamesBucketCount(UniqueHashCount);41}4243void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {44// Create the individual hash data outputs.45for (auto &E : Entries) {46// Unique the entries.47llvm::stable_sort(E.second.Values,48[](const AccelTableData *A, const AccelTableData *B) {49return *A < *B;50});51E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end());52}5354// Figure out how many buckets we need, then compute the bucket contents and55// the final ordering. The hashes and offsets can be emitted by walking these56// data structures. We add temporary symbols to the data so they can be57// referenced when emitting the offsets.58computeBucketCount();5960// Compute bucket contents and final ordering.61Buckets.resize(BucketCount);62for (auto &E : Entries) {63uint32_t Bucket = E.second.HashValue % BucketCount;64Buckets[Bucket].push_back(&E.second);65E.second.Sym = Asm->createTempSymbol(Prefix);66}6768// Sort the contents of the buckets by hash value so that hash collisions end69// up together. Stable sort makes testing easier and doesn't cost much more.70for (auto &Bucket : Buckets)71llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {72return LHS->HashValue < RHS->HashValue;73});74}7576namespace {77/// Base class for writing out Accelerator tables. It holds the common78/// functionality for the two Accelerator table types.79class AccelTableWriter {80protected:81AsmPrinter *const Asm; ///< Destination.82const AccelTableBase &Contents; ///< Data to emit.8384/// Controls whether to emit duplicate hash and offset table entries for names85/// with identical hashes. Apple tables don't emit duplicate entries, DWARF v586/// tables do.87const bool SkipIdenticalHashes;8889void emitHashes() const;9091/// Emit offsets to lists of entries with identical names. The offsets are92/// relative to the Base argument.93void emitOffsets(const MCSymbol *Base) const;9495public:96AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,97bool SkipIdenticalHashes)98: Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {99}100};101102class AppleAccelTableWriter : public AccelTableWriter {103using Atom = AppleAccelTableData::Atom;104105/// The fixed header of an Apple Accelerator Table.106struct Header {107uint32_t Magic = MagicHash;108uint16_t Version = 1;109uint16_t HashFunction = dwarf::DW_hash_function_djb;110uint32_t BucketCount;111uint32_t HashCount;112uint32_t HeaderDataLength;113114/// 'HASH' magic value to detect endianness.115static const uint32_t MagicHash = 0x48415348;116117Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)118: BucketCount(BucketCount), HashCount(UniqueHashCount),119HeaderDataLength(DataLength) {}120121void emit(AsmPrinter *Asm) const;122#ifndef NDEBUG123void print(raw_ostream &OS) const;124void dump() const { print(dbgs()); }125#endif126};127128/// The HeaderData describes the structure of an Apple accelerator table129/// through a list of Atoms.130struct HeaderData {131/// In the case of data that is referenced via DW_FORM_ref_* the offset132/// base is used to describe the offset for all forms in the list of atoms.133uint32_t DieOffsetBase;134135const SmallVector<Atom, 4> Atoms;136137HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)138: DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}139140void emit(AsmPrinter *Asm) const;141#ifndef NDEBUG142void print(raw_ostream &OS) const;143void dump() const { print(dbgs()); }144#endif145};146147Header Header;148HeaderData HeaderData;149const MCSymbol *SecBegin;150151void emitBuckets() const;152void emitData() const;153154public:155AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,156ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)157: AccelTableWriter(Asm, Contents, true),158Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),1598 + (Atoms.size() * 4)),160HeaderData(Atoms), SecBegin(SecBegin) {}161162void emit() const;163164#ifndef NDEBUG165void print(raw_ostream &OS) const;166void dump() const { print(dbgs()); }167#endif168};169170/// Class responsible for emitting a DWARF v5 Accelerator Table. The only171/// public function is emit(), which performs the actual emission.172///173/// A callback abstracts the logic to provide a CU index for a given entry.174class Dwarf5AccelTableWriter : public AccelTableWriter {175struct Header {176uint16_t Version = 5;177uint16_t Padding = 0;178uint32_t CompUnitCount;179uint32_t LocalTypeUnitCount = 0;180uint32_t ForeignTypeUnitCount = 0;181uint32_t BucketCount = 0;182uint32_t NameCount = 0;183uint32_t AbbrevTableSize = 0;184uint32_t AugmentationStringSize = sizeof(AugmentationString);185char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};186187Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,188uint32_t ForeignTypeUnitCount, uint32_t BucketCount,189uint32_t NameCount)190: CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),191ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),192NameCount(NameCount) {}193194void emit(Dwarf5AccelTableWriter &Ctx);195};196197Header Header;198/// FoldingSet that uniques the abbreviations.199FoldingSet<DebugNamesAbbrev> AbbreviationsSet;200/// Vector containing DebugNames abbreviations for iteration in order.201SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;202/// The bump allocator to use when creating DIEAbbrev objects in the uniqued203/// storage container.204BumpPtrAllocator Alloc;205ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;206ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;207llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(208const DWARF5AccelTableData &)>209getIndexForEntry;210MCSymbol *ContributionEnd = nullptr;211MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");212MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");213MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");214// Indicates if this module is built with Split Dwarf enabled.215bool IsSplitDwarf = false;216/// Stores the DIE offsets which are indexed by this table.217DenseSet<OffsetAndUnitID> IndexedOffsets;218219void populateAbbrevsMap();220221void emitCUList() const;222void emitTUList() const;223void emitBuckets() const;224void emitStringOffsets() const;225void emitAbbrevs() const;226void emitEntry(227const DWARF5AccelTableData &Entry,228const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,229DenseSet<MCSymbol *> &EmittedAccelEntrySymbols);230void emitData();231232public:233Dwarf5AccelTableWriter(234AsmPrinter *Asm, const AccelTableBase &Contents,235ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,236ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,237llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(238const DWARF5AccelTableData &)>239getIndexForEntry,240bool IsSplitDwarf);241~Dwarf5AccelTableWriter() {242for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)243Abbrev->~DebugNamesAbbrev();244}245void emit();246};247} // namespace248249void AccelTableWriter::emitHashes() const {250uint64_t PrevHash = std::numeric_limits<uint64_t>::max();251unsigned BucketIdx = 0;252for (const auto &Bucket : Contents.getBuckets()) {253for (const auto &Hash : Bucket) {254uint32_t HashValue = Hash->HashValue;255if (SkipIdenticalHashes && PrevHash == HashValue)256continue;257Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));258Asm->emitInt32(HashValue);259PrevHash = HashValue;260}261BucketIdx++;262}263}264265void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {266const auto &Buckets = Contents.getBuckets();267uint64_t PrevHash = std::numeric_limits<uint64_t>::max();268for (size_t i = 0, e = Buckets.size(); i < e; ++i) {269for (auto *Hash : Buckets[i]) {270uint32_t HashValue = Hash->HashValue;271if (SkipIdenticalHashes && PrevHash == HashValue)272continue;273PrevHash = HashValue;274Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));275Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());276}277}278}279280void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {281Asm->OutStreamer->AddComment("Header Magic");282Asm->emitInt32(Magic);283Asm->OutStreamer->AddComment("Header Version");284Asm->emitInt16(Version);285Asm->OutStreamer->AddComment("Header Hash Function");286Asm->emitInt16(HashFunction);287Asm->OutStreamer->AddComment("Header Bucket Count");288Asm->emitInt32(BucketCount);289Asm->OutStreamer->AddComment("Header Hash Count");290Asm->emitInt32(HashCount);291Asm->OutStreamer->AddComment("Header Data Length");292Asm->emitInt32(HeaderDataLength);293}294295void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {296Asm->OutStreamer->AddComment("HeaderData Die Offset Base");297Asm->emitInt32(DieOffsetBase);298Asm->OutStreamer->AddComment("HeaderData Atom Count");299Asm->emitInt32(Atoms.size());300301for (const Atom &A : Atoms) {302Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));303Asm->emitInt16(A.Type);304Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));305Asm->emitInt16(A.Form);306}307}308309void AppleAccelTableWriter::emitBuckets() const {310const auto &Buckets = Contents.getBuckets();311unsigned index = 0;312for (size_t i = 0, e = Buckets.size(); i < e; ++i) {313Asm->OutStreamer->AddComment("Bucket " + Twine(i));314if (!Buckets[i].empty())315Asm->emitInt32(index);316else317Asm->emitInt32(std::numeric_limits<uint32_t>::max());318// Buckets point in the list of hashes, not to the data. Do not increment319// the index multiple times in case of hash collisions.320uint64_t PrevHash = std::numeric_limits<uint64_t>::max();321for (auto *HD : Buckets[i]) {322uint32_t HashValue = HD->HashValue;323if (PrevHash != HashValue)324++index;325PrevHash = HashValue;326}327}328}329330void AppleAccelTableWriter::emitData() const {331const auto &Buckets = Contents.getBuckets();332for (const AccelTableBase::HashList &Bucket : Buckets) {333uint64_t PrevHash = std::numeric_limits<uint64_t>::max();334for (const auto &Hash : Bucket) {335// Terminate the previous entry if there is no hash collision with the336// current one.337if (PrevHash != std::numeric_limits<uint64_t>::max() &&338PrevHash != Hash->HashValue)339Asm->emitInt32(0);340// Remember to emit the label for our offset.341Asm->OutStreamer->emitLabel(Hash->Sym);342Asm->OutStreamer->AddComment(Hash->Name.getString());343Asm->emitDwarfStringOffset(Hash->Name);344Asm->OutStreamer->AddComment("Num DIEs");345Asm->emitInt32(Hash->Values.size());346for (const auto *V : Hash->getValues<const AppleAccelTableData *>())347V->emit(Asm);348PrevHash = Hash->HashValue;349}350// Emit the final end marker for the bucket.351if (!Bucket.empty())352Asm->emitInt32(0);353}354}355356void AppleAccelTableWriter::emit() const {357Header.emit(Asm);358HeaderData.emit(Asm);359emitBuckets();360emitHashes();361emitOffsets(SecBegin);362emitData();363}364365DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,366const uint32_t UnitID,367const bool IsTU)368: OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),369UnitID(UnitID) {}370371void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {372assert(CompUnitCount > 0 && "Index must have at least one CU.");373374AsmPrinter *Asm = Ctx.Asm;375Ctx.ContributionEnd =376Asm->emitDwarfUnitLength("names", "Header: unit length");377Asm->OutStreamer->AddComment("Header: version");378Asm->emitInt16(Version);379Asm->OutStreamer->AddComment("Header: padding");380Asm->emitInt16(Padding);381Asm->OutStreamer->AddComment("Header: compilation unit count");382Asm->emitInt32(CompUnitCount);383Asm->OutStreamer->AddComment("Header: local type unit count");384Asm->emitInt32(LocalTypeUnitCount);385Asm->OutStreamer->AddComment("Header: foreign type unit count");386Asm->emitInt32(ForeignTypeUnitCount);387Asm->OutStreamer->AddComment("Header: bucket count");388Asm->emitInt32(BucketCount);389Asm->OutStreamer->AddComment("Header: name count");390Asm->emitInt32(NameCount);391Asm->OutStreamer->AddComment("Header: abbreviation table size");392Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));393Asm->OutStreamer->AddComment("Header: augmentation string size");394assert(AugmentationStringSize % 4 == 0);395Asm->emitInt32(AugmentationStringSize);396Asm->OutStreamer->AddComment("Header: augmentation string");397Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});398}399400std::optional<uint64_t>401DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {402if (auto *Parent = Die.getParent();403Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))404return Parent->getOffset();405return {};406}407408static std::optional<dwarf::Form>409getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,410std::optional<OffsetAndUnitID> ParentOffset) {411// No parent information412if (!ParentOffset)413return std::nullopt;414// Parent is indexed by this table.415if (IndexedOffsets.contains(*ParentOffset))416return dwarf::Form::DW_FORM_ref4;417// Parent is not indexed by this table.418return dwarf::Form::DW_FORM_flag_present;419}420421void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const {422ID.AddInteger(DieTag);423for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {424ID.AddInteger(Enc.Index);425ID.AddInteger(Enc.Form);426}427}428429void Dwarf5AccelTableWriter::populateAbbrevsMap() {430for (auto &Bucket : Contents.getBuckets()) {431for (auto *Hash : Bucket) {432for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {433std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =434getIndexForEntry(*Value);435std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(436IndexedOffsets, Value->getParentDieOffsetAndUnitID());437DebugNamesAbbrev Abbrev(Value->getDieTag());438if (EntryRet)439Abbrev.addAttribute(EntryRet->Encoding);440Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});441if (MaybeParentForm)442Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});443FoldingSetNodeID ID;444Abbrev.Profile(ID);445void *InsertPos;446if (DebugNamesAbbrev *Existing =447AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {448Value->setAbbrevNumber(Existing->getNumber());449continue;450}451DebugNamesAbbrev *NewAbbrev =452new (Alloc) DebugNamesAbbrev(std::move(Abbrev));453AbbreviationsVector.push_back(NewAbbrev);454NewAbbrev->setNumber(AbbreviationsVector.size());455AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);456Value->setAbbrevNumber(NewAbbrev->getNumber());457}458}459}460}461462void Dwarf5AccelTableWriter::emitCUList() const {463for (const auto &CU : enumerate(CompUnits)) {464Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));465if (std::holds_alternative<MCSymbol *>(CU.value()))466Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));467else468Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));469}470}471472void Dwarf5AccelTableWriter::emitTUList() const {473for (const auto &TU : enumerate(TypeUnits)) {474Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));475if (std::holds_alternative<MCSymbol *>(TU.value()))476Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));477else if (IsSplitDwarf)478Asm->emitInt64(std::get<uint64_t>(TU.value()));479else480Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));481}482}483484void Dwarf5AccelTableWriter::emitBuckets() const {485uint32_t Index = 1;486for (const auto &Bucket : enumerate(Contents.getBuckets())) {487Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));488Asm->emitInt32(Bucket.value().empty() ? 0 : Index);489Index += Bucket.value().size();490}491}492493void Dwarf5AccelTableWriter::emitStringOffsets() const {494for (const auto &Bucket : enumerate(Contents.getBuckets())) {495for (auto *Hash : Bucket.value()) {496DwarfStringPoolEntryRef String = Hash->Name;497Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +498": " + String.getString());499Asm->emitDwarfStringOffset(String);500}501}502}503504void Dwarf5AccelTableWriter::emitAbbrevs() const {505Asm->OutStreamer->emitLabel(AbbrevStart);506for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {507Asm->OutStreamer->AddComment("Abbrev code");508Asm->emitULEB128(Abbrev->getNumber());509Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));510Asm->emitULEB128(Abbrev->getDieTag());511for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :512Abbrev->getAttributes()) {513Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());514Asm->emitULEB128(AttrEnc.Form,515dwarf::FormEncodingString(AttrEnc.Form).data());516}517Asm->emitULEB128(0, "End of abbrev");518Asm->emitULEB128(0, "End of abbrev");519}520Asm->emitULEB128(0, "End of abbrev list");521Asm->OutStreamer->emitLabel(AbbrevEnd);522}523524void Dwarf5AccelTableWriter::emitEntry(525const DWARF5AccelTableData &Entry,526const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,527DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) {528unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;529assert(AbbrevIndex < AbbreviationsVector.size() &&530"Entry abbrev index is outside of abbreviations vector range.");531DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];532std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =533getIndexForEntry(Entry);534std::optional<OffsetAndUnitID> MaybeParentOffset =535Entry.getParentDieOffsetAndUnitID();536auto EntrySymbolIt =537DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());538assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());539MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();540541// Emit the label for this Entry, so that IDX_parents may refer to it.542// Note: a DIE may have multiple accelerator Entries; this check avoids543// creating/emitting multiple labels for the same DIE.544if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)545Asm->OutStreamer->emitLabel(EntrySymbol);546547Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");548549for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :550Abbrev->getAttributes()) {551Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));552switch (AttrEnc.Index) {553case dwarf::DW_IDX_compile_unit:554case dwarf::DW_IDX_type_unit: {555DIEInteger ID(EntryRet->Index);556ID.emitValue(Asm, AttrEnc.Form);557break;558}559case dwarf::DW_IDX_die_offset:560assert(AttrEnc.Form == dwarf::DW_FORM_ref4);561Asm->emitInt32(Entry.getDieOffset());562break;563case dwarf::DW_IDX_parent: {564if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)565break;566auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);567assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());568Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);569break;570}571default:572llvm_unreachable("Unexpected index attribute!");573}574}575}576577void Dwarf5AccelTableWriter::emitData() {578DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;579580for (OffsetAndUnitID Offset : IndexedOffsets)581DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});582583Asm->OutStreamer->emitLabel(EntryPool);584DenseSet<MCSymbol *> EmittedAccelEntrySymbols;585for (auto &Bucket : Contents.getBuckets()) {586for (auto *Hash : Bucket) {587// Remember to emit the label for our offset.588Asm->OutStreamer->emitLabel(Hash->Sym);589for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())590emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);591Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());592Asm->emitInt8(0);593}594}595}596597Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(598AsmPrinter *Asm, const AccelTableBase &Contents,599ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,600ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,601llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(602const DWARF5AccelTableData &)>603getIndexForEntry,604bool IsSplitDwarf)605: AccelTableWriter(Asm, Contents, false),606Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),607IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),608Contents.getUniqueNameCount()),609CompUnits(CompUnits), TypeUnits(TypeUnits),610getIndexForEntry(std::move(getIndexForEntry)),611IsSplitDwarf(IsSplitDwarf) {612613for (auto &Bucket : Contents.getBuckets())614for (auto *Hash : Bucket)615for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())616IndexedOffsets.insert(Value->getDieOffsetAndUnitID());617618populateAbbrevsMap();619}620621void Dwarf5AccelTableWriter::emit() {622Header.emit(*this);623emitCUList();624emitTUList();625emitBuckets();626emitHashes();627emitStringOffsets();628emitOffsets(EntryPool);629emitAbbrevs();630emitData();631Asm->OutStreamer->emitValueToAlignment(Align(4), 0);632Asm->OutStreamer->emitLabel(ContributionEnd);633}634635void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,636StringRef Prefix, const MCSymbol *SecBegin,637ArrayRef<AppleAccelTableData::Atom> Atoms) {638Contents.finalize(Asm, Prefix);639AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();640}641642void llvm::emitDWARF5AccelTable(643AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,644ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {645TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();646std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;647std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;648SmallVector<unsigned, 1> CUIndex(CUs.size());649DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());650int CUCount = 0;651int TUCount = 0;652for (const auto &CU : enumerate(CUs)) {653switch (CU.value()->getCUNode()->getNameTableKind()) {654case DICompileUnit::DebugNameTableKind::Default:655case DICompileUnit::DebugNameTableKind::Apple:656break;657default:658continue;659}660CUIndex[CU.index()] = CUCount++;661assert(CU.index() == CU.value()->getUniqueID());662const DwarfCompileUnit *MainCU =663DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();664CompUnits.push_back(MainCU->getLabelBegin());665}666667for (const auto &TU : TUSymbols) {668TUIndex[TU.UniqueID] = TUCount++;669if (DD.useSplitDwarf())670TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));671else672TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));673}674675if (CompUnits.empty())676return;677678Asm->OutStreamer->switchSection(679Asm->getObjFileLowering().getDwarfDebugNamesSection());680681Contents.finalize(Asm, "names");682dwarf::Form CUIndexForm =683DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);684dwarf::Form TUIndexForm =685DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);686Dwarf5AccelTableWriter(687Asm, Contents, CompUnits, TypeUnits,688[&](const DWARF5AccelTableData &Entry)689-> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {690if (Entry.isTU())691return {{TUIndex[Entry.getUnitID()],692{dwarf::DW_IDX_type_unit, TUIndexForm}}};693if (CUIndex.size() > 1)694return {{CUIndex[Entry.getUnitID()],695{dwarf::DW_IDX_compile_unit, CUIndexForm}}};696return std::nullopt;697},698DD.useSplitDwarf())699.emit();700}701702void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {703TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});704}705706void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {707TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});708}709710void llvm::emitDWARF5AccelTable(711AsmPrinter *Asm, DWARF5AccelTable &Contents,712ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,713llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(714const DWARF5AccelTableData &)>715getIndexForEntry) {716std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;717Contents.finalize(Asm, "names");718Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)719.emit();720}721722void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {723assert(Die.getDebugSectionOffset() <= UINT32_MAX &&724"The section offset exceeds the limit.");725Asm->emitInt32(Die.getDebugSectionOffset());726}727728void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {729assert(Die.getDebugSectionOffset() <= UINT32_MAX &&730"The section offset exceeds the limit.");731Asm->emitInt32(Die.getDebugSectionOffset());732Asm->emitInt16(Die.getTag());733Asm->emitInt8(0);734}735736void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {737Asm->emitInt32(Offset);738}739740void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {741Asm->emitInt32(Offset);742Asm->emitInt16(Tag);743Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation744: 0);745Asm->emitInt32(QualifiedNameHash);746}747748constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];749constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];750constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];751constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];752753#ifndef NDEBUG754void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {755OS << "Magic: " << format("0x%x", Magic) << "\n"756<< "Version: " << Version << "\n"757<< "Hash Function: " << HashFunction << "\n"758<< "Bucket Count: " << BucketCount << "\n"759<< "Header Data Length: " << HeaderDataLength << "\n";760}761762void AppleAccelTableData::Atom::print(raw_ostream &OS) const {763OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"764<< "Form: " << dwarf::FormEncodingString(Form) << "\n";765}766767void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {768OS << "DIE Offset Base: " << DieOffsetBase << "\n";769for (auto Atom : Atoms)770Atom.print(OS);771}772773void AppleAccelTableWriter::print(raw_ostream &OS) const {774Header.print(OS);775HeaderData.print(OS);776Contents.print(OS);777SecBegin->print(OS, nullptr);778}779780void AccelTableBase::HashData::print(raw_ostream &OS) const {781OS << "Name: " << Name.getString() << "\n";782OS << " Hash Value: " << format("0x%x", HashValue) << "\n";783OS << " Symbol: ";784if (Sym)785OS << *Sym;786else787OS << "<none>";788OS << "\n";789for (auto *Value : Values)790Value->print(OS);791}792793void AccelTableBase::print(raw_ostream &OS) const {794// Print Content.795OS << "Entries: \n";796for (const auto &[Name, Data] : Entries) {797OS << "Name: " << Name << "\n";798for (auto *V : Data.Values)799V->print(OS);800}801802OS << "Buckets and Hashes: \n";803for (const auto &Bucket : Buckets)804for (const auto &Hash : Bucket)805Hash->print(OS);806807OS << "Data: \n";808for (const auto &E : Entries)809E.second.print(OS);810}811812void DWARF5AccelTableData::print(raw_ostream &OS) const {813OS << " Offset: " << getDieOffset() << "\n";814OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";815}816817void AppleAccelTableOffsetData::print(raw_ostream &OS) const {818OS << " Offset: " << Die.getOffset() << "\n";819}820821void AppleAccelTableTypeData::print(raw_ostream &OS) const {822OS << " Offset: " << Die.getOffset() << "\n";823OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";824}825826void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {827OS << " Static Offset: " << Offset << "\n";828}829830void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {831OS << " Static Offset: " << Offset << "\n";832OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";833OS << " Tag: " << dwarf::TagString(Tag) << "\n";834OS << " ObjCClassIsImplementation: "835<< (ObjCClassIsImplementation ? "true" : "false");836OS << "\n";837}838#endif839840841