10b57cec5SDimitry Andric //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains support for writing accelerator tables. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/CodeGen/AccelTable.h" 140b57cec5SDimitry Andric #include "DwarfCompileUnit.h" 155f757f3fSDimitry Andric #include "DwarfUnit.h" 167a6dacacSDimitry Andric #include "llvm/ADT/DenseSet.h" 170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 180b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 190b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/DIE.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 230b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 250b57cec5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h" 260b57cec5SDimitry Andric #include <algorithm> 270b57cec5SDimitry Andric #include <cstddef> 280b57cec5SDimitry Andric #include <cstdint> 290b57cec5SDimitry Andric #include <limits> 300b57cec5SDimitry Andric #include <vector> 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric using namespace llvm; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric void AccelTableBase::computeBucketCount() { 35*0fca6ea1SDimitry Andric SmallVector<uint32_t, 0> Uniques; 360b57cec5SDimitry Andric Uniques.reserve(Entries.size()); 370b57cec5SDimitry Andric for (const auto &E : Entries) 380b57cec5SDimitry Andric Uniques.push_back(E.second.HashValue); 39*0fca6ea1SDimitry Andric llvm::sort(Uniques); 40*0fca6ea1SDimitry Andric UniqueHashCount = llvm::unique(Uniques) - Uniques.begin(); 41*0fca6ea1SDimitry Andric BucketCount = dwarf::getDebugNamesBucketCount(UniqueHashCount); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) { 450b57cec5SDimitry Andric // Create the individual hash data outputs. 460b57cec5SDimitry Andric for (auto &E : Entries) { 470b57cec5SDimitry Andric // Unique the entries. 480b57cec5SDimitry Andric llvm::stable_sort(E.second.Values, 490b57cec5SDimitry Andric [](const AccelTableData *A, const AccelTableData *B) { 500b57cec5SDimitry Andric return *A < *B; 510b57cec5SDimitry Andric }); 52*0fca6ea1SDimitry Andric E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end()); 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric // Figure out how many buckets we need, then compute the bucket contents and 560b57cec5SDimitry Andric // the final ordering. The hashes and offsets can be emitted by walking these 570b57cec5SDimitry Andric // data structures. We add temporary symbols to the data so they can be 580b57cec5SDimitry Andric // referenced when emitting the offsets. 590b57cec5SDimitry Andric computeBucketCount(); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric // Compute bucket contents and final ordering. 620b57cec5SDimitry Andric Buckets.resize(BucketCount); 630b57cec5SDimitry Andric for (auto &E : Entries) { 640b57cec5SDimitry Andric uint32_t Bucket = E.second.HashValue % BucketCount; 650b57cec5SDimitry Andric Buckets[Bucket].push_back(&E.second); 660b57cec5SDimitry Andric E.second.Sym = Asm->createTempSymbol(Prefix); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Sort the contents of the buckets by hash value so that hash collisions end 700b57cec5SDimitry Andric // up together. Stable sort makes testing easier and doesn't cost much more. 710b57cec5SDimitry Andric for (auto &Bucket : Buckets) 720b57cec5SDimitry Andric llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) { 730b57cec5SDimitry Andric return LHS->HashValue < RHS->HashValue; 740b57cec5SDimitry Andric }); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric namespace { 780b57cec5SDimitry Andric /// Base class for writing out Accelerator tables. It holds the common 790b57cec5SDimitry Andric /// functionality for the two Accelerator table types. 800b57cec5SDimitry Andric class AccelTableWriter { 810b57cec5SDimitry Andric protected: 820b57cec5SDimitry Andric AsmPrinter *const Asm; ///< Destination. 830b57cec5SDimitry Andric const AccelTableBase &Contents; ///< Data to emit. 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric /// Controls whether to emit duplicate hash and offset table entries for names 860b57cec5SDimitry Andric /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5 870b57cec5SDimitry Andric /// tables do. 880b57cec5SDimitry Andric const bool SkipIdenticalHashes; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric void emitHashes() const; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric /// Emit offsets to lists of entries with identical names. The offsets are 930b57cec5SDimitry Andric /// relative to the Base argument. 940b57cec5SDimitry Andric void emitOffsets(const MCSymbol *Base) const; 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric public: 970b57cec5SDimitry Andric AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 980b57cec5SDimitry Andric bool SkipIdenticalHashes) 990b57cec5SDimitry Andric : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) { 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric }; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric class AppleAccelTableWriter : public AccelTableWriter { 1040b57cec5SDimitry Andric using Atom = AppleAccelTableData::Atom; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// The fixed header of an Apple Accelerator Table. 1070b57cec5SDimitry Andric struct Header { 1080b57cec5SDimitry Andric uint32_t Magic = MagicHash; 1090b57cec5SDimitry Andric uint16_t Version = 1; 1100b57cec5SDimitry Andric uint16_t HashFunction = dwarf::DW_hash_function_djb; 1110b57cec5SDimitry Andric uint32_t BucketCount; 1120b57cec5SDimitry Andric uint32_t HashCount; 1130b57cec5SDimitry Andric uint32_t HeaderDataLength; 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric /// 'HASH' magic value to detect endianness. 1160b57cec5SDimitry Andric static const uint32_t MagicHash = 0x48415348; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength) 1190b57cec5SDimitry Andric : BucketCount(BucketCount), HashCount(UniqueHashCount), 1200b57cec5SDimitry Andric HeaderDataLength(DataLength) {} 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric void emit(AsmPrinter *Asm) const; 1230b57cec5SDimitry Andric #ifndef NDEBUG 1240b57cec5SDimitry Andric void print(raw_ostream &OS) const; 1250b57cec5SDimitry Andric void dump() const { print(dbgs()); } 1260b57cec5SDimitry Andric #endif 1270b57cec5SDimitry Andric }; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric /// The HeaderData describes the structure of an Apple accelerator table 1300b57cec5SDimitry Andric /// through a list of Atoms. 1310b57cec5SDimitry Andric struct HeaderData { 1320b57cec5SDimitry Andric /// In the case of data that is referenced via DW_FORM_ref_* the offset 1330b57cec5SDimitry Andric /// base is used to describe the offset for all forms in the list of atoms. 1340b57cec5SDimitry Andric uint32_t DieOffsetBase; 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric const SmallVector<Atom, 4> Atoms; 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0) 1390b57cec5SDimitry Andric : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {} 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric void emit(AsmPrinter *Asm) const; 1420b57cec5SDimitry Andric #ifndef NDEBUG 1430b57cec5SDimitry Andric void print(raw_ostream &OS) const; 1440b57cec5SDimitry Andric void dump() const { print(dbgs()); } 1450b57cec5SDimitry Andric #endif 1460b57cec5SDimitry Andric }; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric Header Header; 1490b57cec5SDimitry Andric HeaderData HeaderData; 1500b57cec5SDimitry Andric const MCSymbol *SecBegin; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric void emitBuckets() const; 1530b57cec5SDimitry Andric void emitData() const; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric public: 1560b57cec5SDimitry Andric AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 1570b57cec5SDimitry Andric ArrayRef<Atom> Atoms, const MCSymbol *SecBegin) 1580b57cec5SDimitry Andric : AccelTableWriter(Asm, Contents, true), 1590b57cec5SDimitry Andric Header(Contents.getBucketCount(), Contents.getUniqueHashCount(), 1600b57cec5SDimitry Andric 8 + (Atoms.size() * 4)), 1610b57cec5SDimitry Andric HeaderData(Atoms), SecBegin(SecBegin) {} 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric void emit() const; 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric #ifndef NDEBUG 1660b57cec5SDimitry Andric void print(raw_ostream &OS) const; 1670b57cec5SDimitry Andric void dump() const { print(dbgs()); } 1680b57cec5SDimitry Andric #endif 1690b57cec5SDimitry Andric }; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /// Class responsible for emitting a DWARF v5 Accelerator Table. The only 1720b57cec5SDimitry Andric /// public function is emit(), which performs the actual emission. 1730b57cec5SDimitry Andric /// 1741db9f3b2SDimitry Andric /// A callback abstracts the logic to provide a CU index for a given entry. 1750b57cec5SDimitry Andric class Dwarf5AccelTableWriter : public AccelTableWriter { 1760b57cec5SDimitry Andric struct Header { 1770b57cec5SDimitry Andric uint16_t Version = 5; 1780b57cec5SDimitry Andric uint16_t Padding = 0; 1790b57cec5SDimitry Andric uint32_t CompUnitCount; 1800b57cec5SDimitry Andric uint32_t LocalTypeUnitCount = 0; 1810b57cec5SDimitry Andric uint32_t ForeignTypeUnitCount = 0; 18206c3fb27SDimitry Andric uint32_t BucketCount = 0; 18306c3fb27SDimitry Andric uint32_t NameCount = 0; 1840b57cec5SDimitry Andric uint32_t AbbrevTableSize = 0; 1850b57cec5SDimitry Andric uint32_t AugmentationStringSize = sizeof(AugmentationString); 1860b57cec5SDimitry Andric char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; 1870b57cec5SDimitry Andric 1885f757f3fSDimitry Andric Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount, 1895f757f3fSDimitry Andric uint32_t ForeignTypeUnitCount, uint32_t BucketCount, 1905f757f3fSDimitry Andric uint32_t NameCount) 1915f757f3fSDimitry Andric : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount), 1925f757f3fSDimitry Andric ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount), 1930b57cec5SDimitry Andric NameCount(NameCount) {} 1940b57cec5SDimitry Andric 195fe6060f1SDimitry Andric void emit(Dwarf5AccelTableWriter &Ctx); 1960b57cec5SDimitry Andric }; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric Header Header; 199*0fca6ea1SDimitry Andric /// FoldingSet that uniques the abbreviations. 200*0fca6ea1SDimitry Andric FoldingSet<DebugNamesAbbrev> AbbreviationsSet; 201*0fca6ea1SDimitry Andric /// Vector containing DebugNames abbreviations for iteration in order. 202*0fca6ea1SDimitry Andric SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector; 203*0fca6ea1SDimitry Andric /// The bump allocator to use when creating DIEAbbrev objects in the uniqued 204*0fca6ea1SDimitry Andric /// storage container. 205*0fca6ea1SDimitry Andric BumpPtrAllocator Alloc; 2065f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits; 2075f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits; 2085f757f3fSDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>( 2091db9f3b2SDimitry Andric const DWARF5AccelTableData &)> 2105f757f3fSDimitry Andric getIndexForEntry; 211fe6060f1SDimitry Andric MCSymbol *ContributionEnd = nullptr; 2120b57cec5SDimitry Andric MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); 2130b57cec5SDimitry Andric MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); 2140b57cec5SDimitry Andric MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); 2155f757f3fSDimitry Andric // Indicates if this module is built with Split Dwarf enabled. 2165f757f3fSDimitry Andric bool IsSplitDwarf = false; 2177a6dacacSDimitry Andric /// Stores the DIE offsets which are indexed by this table. 2187a6dacacSDimitry Andric DenseSet<OffsetAndUnitID> IndexedOffsets; 2190b57cec5SDimitry Andric 2205f757f3fSDimitry Andric void populateAbbrevsMap(); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric void emitCUList() const; 2235f757f3fSDimitry Andric void emitTUList() const; 2240b57cec5SDimitry Andric void emitBuckets() const; 2250b57cec5SDimitry Andric void emitStringOffsets() const; 2260b57cec5SDimitry Andric void emitAbbrevs() const; 2277a6dacacSDimitry Andric void emitEntry( 2287a6dacacSDimitry Andric const DWARF5AccelTableData &Entry, 2297a6dacacSDimitry Andric const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel, 230*0fca6ea1SDimitry Andric DenseSet<MCSymbol *> &EmittedAccelEntrySymbols); 2317a6dacacSDimitry Andric void emitData(); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric public: 2340b57cec5SDimitry Andric Dwarf5AccelTableWriter( 2350b57cec5SDimitry Andric AsmPrinter *Asm, const AccelTableBase &Contents, 2365f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits, 2375f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits, 2381db9f3b2SDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>( 2391db9f3b2SDimitry Andric const DWARF5AccelTableData &)> 2405f757f3fSDimitry Andric getIndexForEntry, 2415f757f3fSDimitry Andric bool IsSplitDwarf); 242*0fca6ea1SDimitry Andric ~Dwarf5AccelTableWriter() { 243*0fca6ea1SDimitry Andric for (DebugNamesAbbrev *Abbrev : AbbreviationsVector) 244*0fca6ea1SDimitry Andric Abbrev->~DebugNamesAbbrev(); 245*0fca6ea1SDimitry Andric } 246fe6060f1SDimitry Andric void emit(); 2470b57cec5SDimitry Andric }; 2480b57cec5SDimitry Andric } // namespace 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric void AccelTableWriter::emitHashes() const { 2510b57cec5SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 2520b57cec5SDimitry Andric unsigned BucketIdx = 0; 253fcaf7f86SDimitry Andric for (const auto &Bucket : Contents.getBuckets()) { 254fcaf7f86SDimitry Andric for (const auto &Hash : Bucket) { 2550b57cec5SDimitry Andric uint32_t HashValue = Hash->HashValue; 2560b57cec5SDimitry Andric if (SkipIdenticalHashes && PrevHash == HashValue) 2570b57cec5SDimitry Andric continue; 2580b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx)); 2590b57cec5SDimitry Andric Asm->emitInt32(HashValue); 2600b57cec5SDimitry Andric PrevHash = HashValue; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric BucketIdx++; 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric void AccelTableWriter::emitOffsets(const MCSymbol *Base) const { 2670b57cec5SDimitry Andric const auto &Buckets = Contents.getBuckets(); 2680b57cec5SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 2690b57cec5SDimitry Andric for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 2700b57cec5SDimitry Andric for (auto *Hash : Buckets[i]) { 2710b57cec5SDimitry Andric uint32_t HashValue = Hash->HashValue; 2720b57cec5SDimitry Andric if (SkipIdenticalHashes && PrevHash == HashValue) 2730b57cec5SDimitry Andric continue; 2740b57cec5SDimitry Andric PrevHash = HashValue; 2750b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); 276e8d8bef9SDimitry Andric Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize()); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const { 2820b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header Magic"); 2830b57cec5SDimitry Andric Asm->emitInt32(Magic); 2840b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header Version"); 2850b57cec5SDimitry Andric Asm->emitInt16(Version); 2860b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header Hash Function"); 2870b57cec5SDimitry Andric Asm->emitInt16(HashFunction); 2880b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header Bucket Count"); 2890b57cec5SDimitry Andric Asm->emitInt32(BucketCount); 2900b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header Hash Count"); 2910b57cec5SDimitry Andric Asm->emitInt32(HashCount); 2920b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header Data Length"); 2930b57cec5SDimitry Andric Asm->emitInt32(HeaderDataLength); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const { 2970b57cec5SDimitry Andric Asm->OutStreamer->AddComment("HeaderData Die Offset Base"); 2980b57cec5SDimitry Andric Asm->emitInt32(DieOffsetBase); 2990b57cec5SDimitry Andric Asm->OutStreamer->AddComment("HeaderData Atom Count"); 3000b57cec5SDimitry Andric Asm->emitInt32(Atoms.size()); 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric for (const Atom &A : Atoms) { 3030b57cec5SDimitry Andric Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type)); 3040b57cec5SDimitry Andric Asm->emitInt16(A.Type); 3050b57cec5SDimitry Andric Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form)); 3060b57cec5SDimitry Andric Asm->emitInt16(A.Form); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric void AppleAccelTableWriter::emitBuckets() const { 3110b57cec5SDimitry Andric const auto &Buckets = Contents.getBuckets(); 3120b57cec5SDimitry Andric unsigned index = 0; 3130b57cec5SDimitry Andric for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 3140b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Bucket " + Twine(i)); 3150b57cec5SDimitry Andric if (!Buckets[i].empty()) 3160b57cec5SDimitry Andric Asm->emitInt32(index); 3170b57cec5SDimitry Andric else 3180b57cec5SDimitry Andric Asm->emitInt32(std::numeric_limits<uint32_t>::max()); 3190b57cec5SDimitry Andric // Buckets point in the list of hashes, not to the data. Do not increment 3200b57cec5SDimitry Andric // the index multiple times in case of hash collisions. 3210b57cec5SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 3220b57cec5SDimitry Andric for (auto *HD : Buckets[i]) { 3230b57cec5SDimitry Andric uint32_t HashValue = HD->HashValue; 3240b57cec5SDimitry Andric if (PrevHash != HashValue) 3250b57cec5SDimitry Andric ++index; 3260b57cec5SDimitry Andric PrevHash = HashValue; 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric void AppleAccelTableWriter::emitData() const { 3320b57cec5SDimitry Andric const auto &Buckets = Contents.getBuckets(); 333fe6060f1SDimitry Andric for (const AccelTableBase::HashList &Bucket : Buckets) { 3340b57cec5SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 335fcaf7f86SDimitry Andric for (const auto &Hash : Bucket) { 3360b57cec5SDimitry Andric // Terminate the previous entry if there is no hash collision with the 3370b57cec5SDimitry Andric // current one. 3380b57cec5SDimitry Andric if (PrevHash != std::numeric_limits<uint64_t>::max() && 3390b57cec5SDimitry Andric PrevHash != Hash->HashValue) 3400b57cec5SDimitry Andric Asm->emitInt32(0); 3410b57cec5SDimitry Andric // Remember to emit the label for our offset. 3425ffd83dbSDimitry Andric Asm->OutStreamer->emitLabel(Hash->Sym); 3430b57cec5SDimitry Andric Asm->OutStreamer->AddComment(Hash->Name.getString()); 3440b57cec5SDimitry Andric Asm->emitDwarfStringOffset(Hash->Name); 3450b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Num DIEs"); 3460b57cec5SDimitry Andric Asm->emitInt32(Hash->Values.size()); 3471db9f3b2SDimitry Andric for (const auto *V : Hash->getValues<const AppleAccelTableData *>()) 3481db9f3b2SDimitry Andric V->emit(Asm); 3490b57cec5SDimitry Andric PrevHash = Hash->HashValue; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric // Emit the final end marker for the bucket. 352fe6060f1SDimitry Andric if (!Bucket.empty()) 3530b57cec5SDimitry Andric Asm->emitInt32(0); 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric void AppleAccelTableWriter::emit() const { 3580b57cec5SDimitry Andric Header.emit(Asm); 3590b57cec5SDimitry Andric HeaderData.emit(Asm); 3600b57cec5SDimitry Andric emitBuckets(); 3610b57cec5SDimitry Andric emitHashes(); 3620b57cec5SDimitry Andric emitOffsets(SecBegin); 3630b57cec5SDimitry Andric emitData(); 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric 3665f757f3fSDimitry Andric DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die, 3675f757f3fSDimitry Andric const uint32_t UnitID, 3685f757f3fSDimitry Andric const bool IsTU) 369*0fca6ea1SDimitry Andric : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU), 370*0fca6ea1SDimitry Andric UnitID(UnitID) {} 3715f757f3fSDimitry Andric 3721db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) { 3730b57cec5SDimitry Andric assert(CompUnitCount > 0 && "Index must have at least one CU."); 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric AsmPrinter *Asm = Ctx.Asm; 376fe6060f1SDimitry Andric Ctx.ContributionEnd = 377fe6060f1SDimitry Andric Asm->emitDwarfUnitLength("names", "Header: unit length"); 3780b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: version"); 3790b57cec5SDimitry Andric Asm->emitInt16(Version); 3800b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: padding"); 3810b57cec5SDimitry Andric Asm->emitInt16(Padding); 3820b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: compilation unit count"); 3830b57cec5SDimitry Andric Asm->emitInt32(CompUnitCount); 3840b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: local type unit count"); 3850b57cec5SDimitry Andric Asm->emitInt32(LocalTypeUnitCount); 3860b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: foreign type unit count"); 3870b57cec5SDimitry Andric Asm->emitInt32(ForeignTypeUnitCount); 3880b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: bucket count"); 3890b57cec5SDimitry Andric Asm->emitInt32(BucketCount); 3900b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: name count"); 3910b57cec5SDimitry Andric Asm->emitInt32(NameCount); 3920b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: abbreviation table size"); 3935ffd83dbSDimitry Andric Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t)); 3940b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: augmentation string size"); 3950b57cec5SDimitry Andric assert(AugmentationStringSize % 4 == 0); 3960b57cec5SDimitry Andric Asm->emitInt32(AugmentationStringSize); 3970b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Header: augmentation string"); 3985ffd83dbSDimitry Andric Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize}); 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric 4017a6dacacSDimitry Andric std::optional<uint64_t> 4027a6dacacSDimitry Andric DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) { 4037a6dacacSDimitry Andric if (auto *Parent = Die.getParent(); 4047a6dacacSDimitry Andric Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration)) 4057a6dacacSDimitry Andric return Parent->getOffset(); 4067a6dacacSDimitry Andric return {}; 4077a6dacacSDimitry Andric } 4087a6dacacSDimitry Andric 4097a6dacacSDimitry Andric static std::optional<dwarf::Form> 4107a6dacacSDimitry Andric getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets, 4117a6dacacSDimitry Andric std::optional<OffsetAndUnitID> ParentOffset) { 4127a6dacacSDimitry Andric // No parent information 4137a6dacacSDimitry Andric if (!ParentOffset) 4147a6dacacSDimitry Andric return std::nullopt; 4157a6dacacSDimitry Andric // Parent is indexed by this table. 4167a6dacacSDimitry Andric if (IndexedOffsets.contains(*ParentOffset)) 4177a6dacacSDimitry Andric return dwarf::Form::DW_FORM_ref4; 4187a6dacacSDimitry Andric // Parent is not indexed by this table. 4197a6dacacSDimitry Andric return dwarf::Form::DW_FORM_flag_present; 4207a6dacacSDimitry Andric } 4217a6dacacSDimitry Andric 422*0fca6ea1SDimitry Andric void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const { 423*0fca6ea1SDimitry Andric ID.AddInteger(DieTag); 424*0fca6ea1SDimitry Andric for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) { 425*0fca6ea1SDimitry Andric ID.AddInteger(Enc.Index); 426*0fca6ea1SDimitry Andric ID.AddInteger(Enc.Form); 427*0fca6ea1SDimitry Andric } 428*0fca6ea1SDimitry Andric } 429*0fca6ea1SDimitry Andric 4301db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::populateAbbrevsMap() { 4310b57cec5SDimitry Andric for (auto &Bucket : Contents.getBuckets()) { 4320b57cec5SDimitry Andric for (auto *Hash : Bucket) { 4331db9f3b2SDimitry Andric for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) { 4345f757f3fSDimitry Andric std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet = 4351db9f3b2SDimitry Andric getIndexForEntry(*Value); 4367a6dacacSDimitry Andric std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent( 4377a6dacacSDimitry Andric IndexedOffsets, Value->getParentDieOffsetAndUnitID()); 438*0fca6ea1SDimitry Andric DebugNamesAbbrev Abbrev(Value->getDieTag()); 4395f757f3fSDimitry Andric if (EntryRet) 440*0fca6ea1SDimitry Andric Abbrev.addAttribute(EntryRet->Encoding); 441*0fca6ea1SDimitry Andric Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); 4427a6dacacSDimitry Andric if (MaybeParentForm) 443*0fca6ea1SDimitry Andric Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm}); 444*0fca6ea1SDimitry Andric FoldingSetNodeID ID; 445*0fca6ea1SDimitry Andric Abbrev.Profile(ID); 446*0fca6ea1SDimitry Andric void *InsertPos; 447*0fca6ea1SDimitry Andric if (DebugNamesAbbrev *Existing = 448*0fca6ea1SDimitry Andric AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) { 449*0fca6ea1SDimitry Andric Value->setAbbrevNumber(Existing->getNumber()); 450*0fca6ea1SDimitry Andric continue; 4515f757f3fSDimitry Andric } 452*0fca6ea1SDimitry Andric DebugNamesAbbrev *NewAbbrev = 453*0fca6ea1SDimitry Andric new (Alloc) DebugNamesAbbrev(std::move(Abbrev)); 454*0fca6ea1SDimitry Andric AbbreviationsVector.push_back(NewAbbrev); 455*0fca6ea1SDimitry Andric NewAbbrev->setNumber(AbbreviationsVector.size()); 456*0fca6ea1SDimitry Andric AbbreviationsSet.InsertNode(NewAbbrev, InsertPos); 457*0fca6ea1SDimitry Andric Value->setAbbrevNumber(NewAbbrev->getNumber()); 4585f757f3fSDimitry Andric } 4595f757f3fSDimitry Andric } 4605f757f3fSDimitry Andric } 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4631db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emitCUList() const { 4640b57cec5SDimitry Andric for (const auto &CU : enumerate(CompUnits)) { 4650b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index())); 4665f757f3fSDimitry Andric if (std::holds_alternative<MCSymbol *>(CU.value())) 4675f757f3fSDimitry Andric Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value())); 4685f757f3fSDimitry Andric else 4695f757f3fSDimitry Andric Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value())); 4705f757f3fSDimitry Andric } 4715f757f3fSDimitry Andric } 4725f757f3fSDimitry Andric 4731db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emitTUList() const { 4745f757f3fSDimitry Andric for (const auto &TU : enumerate(TypeUnits)) { 4755f757f3fSDimitry Andric Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index())); 4765f757f3fSDimitry Andric if (std::holds_alternative<MCSymbol *>(TU.value())) 4775f757f3fSDimitry Andric Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value())); 4785f757f3fSDimitry Andric else if (IsSplitDwarf) 4795f757f3fSDimitry Andric Asm->emitInt64(std::get<uint64_t>(TU.value())); 4805f757f3fSDimitry Andric else 4815f757f3fSDimitry Andric Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value())); 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4851db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emitBuckets() const { 4860b57cec5SDimitry Andric uint32_t Index = 1; 4870b57cec5SDimitry Andric for (const auto &Bucket : enumerate(Contents.getBuckets())) { 4880b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); 4890b57cec5SDimitry Andric Asm->emitInt32(Bucket.value().empty() ? 0 : Index); 4900b57cec5SDimitry Andric Index += Bucket.value().size(); 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4941db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emitStringOffsets() const { 4950b57cec5SDimitry Andric for (const auto &Bucket : enumerate(Contents.getBuckets())) { 4960b57cec5SDimitry Andric for (auto *Hash : Bucket.value()) { 4970b57cec5SDimitry Andric DwarfStringPoolEntryRef String = Hash->Name; 4980b57cec5SDimitry Andric Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + 4990b57cec5SDimitry Andric ": " + String.getString()); 5000b57cec5SDimitry Andric Asm->emitDwarfStringOffset(String); 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric 5051db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emitAbbrevs() const { 5065ffd83dbSDimitry Andric Asm->OutStreamer->emitLabel(AbbrevStart); 507*0fca6ea1SDimitry Andric for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) { 5080b57cec5SDimitry Andric Asm->OutStreamer->AddComment("Abbrev code"); 509*0fca6ea1SDimitry Andric Asm->emitULEB128(Abbrev->getNumber()); 510*0fca6ea1SDimitry Andric Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag())); 511*0fca6ea1SDimitry Andric Asm->emitULEB128(Abbrev->getDieTag()); 512*0fca6ea1SDimitry Andric for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc : 513*0fca6ea1SDimitry Andric Abbrev->getAttributes()) { 5145ffd83dbSDimitry Andric Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); 5155ffd83dbSDimitry Andric Asm->emitULEB128(AttrEnc.Form, 5160b57cec5SDimitry Andric dwarf::FormEncodingString(AttrEnc.Form).data()); 5170b57cec5SDimitry Andric } 5185ffd83dbSDimitry Andric Asm->emitULEB128(0, "End of abbrev"); 5195ffd83dbSDimitry Andric Asm->emitULEB128(0, "End of abbrev"); 5200b57cec5SDimitry Andric } 5215ffd83dbSDimitry Andric Asm->emitULEB128(0, "End of abbrev list"); 5225ffd83dbSDimitry Andric Asm->OutStreamer->emitLabel(AbbrevEnd); 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5251db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emitEntry( 5267a6dacacSDimitry Andric const DWARF5AccelTableData &Entry, 5277a6dacacSDimitry Andric const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel, 528*0fca6ea1SDimitry Andric DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) { 529*0fca6ea1SDimitry Andric unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1; 530*0fca6ea1SDimitry Andric assert(AbbrevIndex < AbbreviationsVector.size() && 531*0fca6ea1SDimitry Andric "Entry abbrev index is outside of abbreviations vector range."); 532*0fca6ea1SDimitry Andric DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex]; 5335f757f3fSDimitry Andric std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet = 5345f757f3fSDimitry Andric getIndexForEntry(Entry); 5357a6dacacSDimitry Andric std::optional<OffsetAndUnitID> MaybeParentOffset = 5367a6dacacSDimitry Andric Entry.getParentDieOffsetAndUnitID(); 5377a6dacacSDimitry Andric auto EntrySymbolIt = 5387a6dacacSDimitry Andric DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID()); 5397a6dacacSDimitry Andric assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end()); 5407a6dacacSDimitry Andric MCSymbol *EntrySymbol = EntrySymbolIt->getSecond(); 5417a6dacacSDimitry Andric 5427a6dacacSDimitry Andric // Emit the label for this Entry, so that IDX_parents may refer to it. 5437a6dacacSDimitry Andric // Note: a DIE may have multiple accelerator Entries; this check avoids 5447a6dacacSDimitry Andric // creating/emitting multiple labels for the same DIE. 5457a6dacacSDimitry Andric if (EmittedAccelEntrySymbols.insert(EntrySymbol).second) 5467a6dacacSDimitry Andric Asm->OutStreamer->emitLabel(EntrySymbol); 5477a6dacacSDimitry Andric 548*0fca6ea1SDimitry Andric Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code"); 5495f757f3fSDimitry Andric 550*0fca6ea1SDimitry Andric for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc : 551*0fca6ea1SDimitry Andric Abbrev->getAttributes()) { 5520b57cec5SDimitry Andric Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); 5530b57cec5SDimitry Andric switch (AttrEnc.Index) { 5545f757f3fSDimitry Andric case dwarf::DW_IDX_compile_unit: 5555f757f3fSDimitry Andric case dwarf::DW_IDX_type_unit: { 5565f757f3fSDimitry Andric DIEInteger ID(EntryRet->Index); 5575ffd83dbSDimitry Andric ID.emitValue(Asm, AttrEnc.Form); 5580b57cec5SDimitry Andric break; 5590b57cec5SDimitry Andric } 5600b57cec5SDimitry Andric case dwarf::DW_IDX_die_offset: 5610b57cec5SDimitry Andric assert(AttrEnc.Form == dwarf::DW_FORM_ref4); 5620b57cec5SDimitry Andric Asm->emitInt32(Entry.getDieOffset()); 5630b57cec5SDimitry Andric break; 5647a6dacacSDimitry Andric case dwarf::DW_IDX_parent: { 5657a6dacacSDimitry Andric if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present) 5667a6dacacSDimitry Andric break; 5677a6dacacSDimitry Andric auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset); 5687a6dacacSDimitry Andric assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end()); 5697a6dacacSDimitry Andric Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4); 5707a6dacacSDimitry Andric break; 5717a6dacacSDimitry Andric } 5720b57cec5SDimitry Andric default: 5730b57cec5SDimitry Andric llvm_unreachable("Unexpected index attribute!"); 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric } 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric 5787a6dacacSDimitry Andric void Dwarf5AccelTableWriter::emitData() { 5797a6dacacSDimitry Andric DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel; 5807a6dacacSDimitry Andric 5817a6dacacSDimitry Andric for (OffsetAndUnitID Offset : IndexedOffsets) 5827a6dacacSDimitry Andric DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")}); 5837a6dacacSDimitry Andric 5845ffd83dbSDimitry Andric Asm->OutStreamer->emitLabel(EntryPool); 5857a6dacacSDimitry Andric DenseSet<MCSymbol *> EmittedAccelEntrySymbols; 5860b57cec5SDimitry Andric for (auto &Bucket : Contents.getBuckets()) { 5870b57cec5SDimitry Andric for (auto *Hash : Bucket) { 5880b57cec5SDimitry Andric // Remember to emit the label for our offset. 5895ffd83dbSDimitry Andric Asm->OutStreamer->emitLabel(Hash->Sym); 5907a6dacacSDimitry Andric for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>()) 5917a6dacacSDimitry Andric emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols); 5920b57cec5SDimitry Andric Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); 593e8d8bef9SDimitry Andric Asm->emitInt8(0); 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric } 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5981db9f3b2SDimitry Andric Dwarf5AccelTableWriter::Dwarf5AccelTableWriter( 5990b57cec5SDimitry Andric AsmPrinter *Asm, const AccelTableBase &Contents, 6005f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits, 6015f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits, 6021db9f3b2SDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>( 6031db9f3b2SDimitry Andric const DWARF5AccelTableData &)> 6045f757f3fSDimitry Andric getIndexForEntry, 6055f757f3fSDimitry Andric bool IsSplitDwarf) 6060b57cec5SDimitry Andric : AccelTableWriter(Asm, Contents, false), 6075f757f3fSDimitry Andric Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(), 6085f757f3fSDimitry Andric IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(), 6090b57cec5SDimitry Andric Contents.getUniqueNameCount()), 6105f757f3fSDimitry Andric CompUnits(CompUnits), TypeUnits(TypeUnits), 6115f757f3fSDimitry Andric getIndexForEntry(std::move(getIndexForEntry)), 6125f757f3fSDimitry Andric IsSplitDwarf(IsSplitDwarf) { 6137a6dacacSDimitry Andric 6147a6dacacSDimitry Andric for (auto &Bucket : Contents.getBuckets()) 6157a6dacacSDimitry Andric for (auto *Hash : Bucket) 6167a6dacacSDimitry Andric for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) 6177a6dacacSDimitry Andric IndexedOffsets.insert(Value->getDieOffsetAndUnitID()); 6187a6dacacSDimitry Andric 6195f757f3fSDimitry Andric populateAbbrevsMap(); 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6221db9f3b2SDimitry Andric void Dwarf5AccelTableWriter::emit() { 6230b57cec5SDimitry Andric Header.emit(*this); 6240b57cec5SDimitry Andric emitCUList(); 6255f757f3fSDimitry Andric emitTUList(); 6260b57cec5SDimitry Andric emitBuckets(); 6270b57cec5SDimitry Andric emitHashes(); 6280b57cec5SDimitry Andric emitStringOffsets(); 6290b57cec5SDimitry Andric emitOffsets(EntryPool); 6300b57cec5SDimitry Andric emitAbbrevs(); 6310b57cec5SDimitry Andric emitData(); 632bdd1243dSDimitry Andric Asm->OutStreamer->emitValueToAlignment(Align(4), 0); 6335ffd83dbSDimitry Andric Asm->OutStreamer->emitLabel(ContributionEnd); 6340b57cec5SDimitry Andric } 6350b57cec5SDimitry Andric 6360b57cec5SDimitry Andric void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, 6370b57cec5SDimitry Andric StringRef Prefix, const MCSymbol *SecBegin, 6380b57cec5SDimitry Andric ArrayRef<AppleAccelTableData::Atom> Atoms) { 6390b57cec5SDimitry Andric Contents.finalize(Asm, Prefix); 6400b57cec5SDimitry Andric AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit(); 6410b57cec5SDimitry Andric } 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric void llvm::emitDWARF5AccelTable( 6445f757f3fSDimitry Andric AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD, 6455f757f3fSDimitry Andric ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { 6465f757f3fSDimitry Andric TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols(); 6475f757f3fSDimitry Andric std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits; 6485f757f3fSDimitry Andric std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits; 6490b57cec5SDimitry Andric SmallVector<unsigned, 1> CUIndex(CUs.size()); 6505f757f3fSDimitry Andric DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size()); 6515f757f3fSDimitry Andric int CUCount = 0; 6525f757f3fSDimitry Andric int TUCount = 0; 6530b57cec5SDimitry Andric for (const auto &CU : enumerate(CUs)) { 65406c3fb27SDimitry Andric switch (CU.value()->getCUNode()->getNameTableKind()) { 65506c3fb27SDimitry Andric case DICompileUnit::DebugNameTableKind::Default: 65606c3fb27SDimitry Andric case DICompileUnit::DebugNameTableKind::Apple: 65706c3fb27SDimitry Andric break; 65806c3fb27SDimitry Andric default: 6590b57cec5SDimitry Andric continue; 66006c3fb27SDimitry Andric } 6615f757f3fSDimitry Andric CUIndex[CU.index()] = CUCount++; 6620b57cec5SDimitry Andric assert(CU.index() == CU.value()->getUniqueID()); 6630b57cec5SDimitry Andric const DwarfCompileUnit *MainCU = 6640b57cec5SDimitry Andric DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get(); 6650b57cec5SDimitry Andric CompUnits.push_back(MainCU->getLabelBegin()); 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric 6685f757f3fSDimitry Andric for (const auto &TU : TUSymbols) { 6695f757f3fSDimitry Andric TUIndex[TU.UniqueID] = TUCount++; 6705f757f3fSDimitry Andric if (DD.useSplitDwarf()) 6715f757f3fSDimitry Andric TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature)); 6725f757f3fSDimitry Andric else 6735f757f3fSDimitry Andric TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature)); 6745f757f3fSDimitry Andric } 6755f757f3fSDimitry Andric 6760b57cec5SDimitry Andric if (CompUnits.empty()) 6770b57cec5SDimitry Andric return; 6780b57cec5SDimitry Andric 67981ad6265SDimitry Andric Asm->OutStreamer->switchSection( 6800b57cec5SDimitry Andric Asm->getObjFileLowering().getDwarfDebugNamesSection()); 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric Contents.finalize(Asm, "names"); 6835f757f3fSDimitry Andric dwarf::Form CUIndexForm = 6845f757f3fSDimitry Andric DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1); 6855f757f3fSDimitry Andric dwarf::Form TUIndexForm = 6865f757f3fSDimitry Andric DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1); 6871db9f3b2SDimitry Andric Dwarf5AccelTableWriter( 6885f757f3fSDimitry Andric Asm, Contents, CompUnits, TypeUnits, 6895f757f3fSDimitry Andric [&](const DWARF5AccelTableData &Entry) 6905f757f3fSDimitry Andric -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> { 6915f757f3fSDimitry Andric if (Entry.isTU()) 6925f757f3fSDimitry Andric return {{TUIndex[Entry.getUnitID()], 6935f757f3fSDimitry Andric {dwarf::DW_IDX_type_unit, TUIndexForm}}}; 6945f757f3fSDimitry Andric if (CUIndex.size() > 1) 6955f757f3fSDimitry Andric return {{CUIndex[Entry.getUnitID()], 6965f757f3fSDimitry Andric {dwarf::DW_IDX_compile_unit, CUIndexForm}}}; 6975f757f3fSDimitry Andric return std::nullopt; 6985f757f3fSDimitry Andric }, 6995f757f3fSDimitry Andric DD.useSplitDwarf()) 7000b57cec5SDimitry Andric .emit(); 7010b57cec5SDimitry Andric } 7020b57cec5SDimitry Andric 7035f757f3fSDimitry Andric void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) { 7045f757f3fSDimitry Andric TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()}); 7055f757f3fSDimitry Andric } 7065f757f3fSDimitry Andric 7075f757f3fSDimitry Andric void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) { 7085f757f3fSDimitry Andric TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()}); 7095f757f3fSDimitry Andric } 7105f757f3fSDimitry Andric 7110b57cec5SDimitry Andric void llvm::emitDWARF5AccelTable( 7125f757f3fSDimitry Andric AsmPrinter *Asm, DWARF5AccelTable &Contents, 7135f757f3fSDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs, 7145f757f3fSDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>( 7155f757f3fSDimitry Andric const DWARF5AccelTableData &)> 7165f757f3fSDimitry Andric getIndexForEntry) { 7175f757f3fSDimitry Andric std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits; 7180b57cec5SDimitry Andric Contents.finalize(Asm, "names"); 7191db9f3b2SDimitry Andric Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false) 7200b57cec5SDimitry Andric .emit(); 7210b57cec5SDimitry Andric } 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { 724e8d8bef9SDimitry Andric assert(Die.getDebugSectionOffset() <= UINT32_MAX && 725e8d8bef9SDimitry Andric "The section offset exceeds the limit."); 7260b57cec5SDimitry Andric Asm->emitInt32(Die.getDebugSectionOffset()); 7270b57cec5SDimitry Andric } 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { 730e8d8bef9SDimitry Andric assert(Die.getDebugSectionOffset() <= UINT32_MAX && 731e8d8bef9SDimitry Andric "The section offset exceeds the limit."); 7320b57cec5SDimitry Andric Asm->emitInt32(Die.getDebugSectionOffset()); 7330b57cec5SDimitry Andric Asm->emitInt16(Die.getTag()); 7340b57cec5SDimitry Andric Asm->emitInt8(0); 7350b57cec5SDimitry Andric } 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { 7380b57cec5SDimitry Andric Asm->emitInt32(Offset); 7390b57cec5SDimitry Andric } 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { 7420b57cec5SDimitry Andric Asm->emitInt32(Offset); 7430b57cec5SDimitry Andric Asm->emitInt16(Tag); 7440b57cec5SDimitry Andric Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation 7450b57cec5SDimitry Andric : 0); 7460b57cec5SDimitry Andric Asm->emitInt32(QualifiedNameHash); 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[]; 7500b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[]; 7510b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[]; 7520b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[]; 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric #ifndef NDEBUG 7550b57cec5SDimitry Andric void AppleAccelTableWriter::Header::print(raw_ostream &OS) const { 7560b57cec5SDimitry Andric OS << "Magic: " << format("0x%x", Magic) << "\n" 7570b57cec5SDimitry Andric << "Version: " << Version << "\n" 7580b57cec5SDimitry Andric << "Hash Function: " << HashFunction << "\n" 7590b57cec5SDimitry Andric << "Bucket Count: " << BucketCount << "\n" 7600b57cec5SDimitry Andric << "Header Data Length: " << HeaderDataLength << "\n"; 7610b57cec5SDimitry Andric } 7620b57cec5SDimitry Andric 7630b57cec5SDimitry Andric void AppleAccelTableData::Atom::print(raw_ostream &OS) const { 7640b57cec5SDimitry Andric OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" 7650b57cec5SDimitry Andric << "Form: " << dwarf::FormEncodingString(Form) << "\n"; 7660b57cec5SDimitry Andric } 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const { 7690b57cec5SDimitry Andric OS << "DIE Offset Base: " << DieOffsetBase << "\n"; 7700b57cec5SDimitry Andric for (auto Atom : Atoms) 7710b57cec5SDimitry Andric Atom.print(OS); 7720b57cec5SDimitry Andric } 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric void AppleAccelTableWriter::print(raw_ostream &OS) const { 7750b57cec5SDimitry Andric Header.print(OS); 7760b57cec5SDimitry Andric HeaderData.print(OS); 7770b57cec5SDimitry Andric Contents.print(OS); 7780b57cec5SDimitry Andric SecBegin->print(OS, nullptr); 7790b57cec5SDimitry Andric } 7800b57cec5SDimitry Andric 7810b57cec5SDimitry Andric void AccelTableBase::HashData::print(raw_ostream &OS) const { 7820b57cec5SDimitry Andric OS << "Name: " << Name.getString() << "\n"; 7830b57cec5SDimitry Andric OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; 7840b57cec5SDimitry Andric OS << " Symbol: "; 7850b57cec5SDimitry Andric if (Sym) 7860b57cec5SDimitry Andric OS << *Sym; 7870b57cec5SDimitry Andric else 7880b57cec5SDimitry Andric OS << "<none>"; 7890b57cec5SDimitry Andric OS << "\n"; 7900b57cec5SDimitry Andric for (auto *Value : Values) 7910b57cec5SDimitry Andric Value->print(OS); 7920b57cec5SDimitry Andric } 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric void AccelTableBase::print(raw_ostream &OS) const { 7950b57cec5SDimitry Andric // Print Content. 7960b57cec5SDimitry Andric OS << "Entries: \n"; 79706c3fb27SDimitry Andric for (const auto &[Name, Data] : Entries) { 79806c3fb27SDimitry Andric OS << "Name: " << Name << "\n"; 79906c3fb27SDimitry Andric for (auto *V : Data.Values) 8000b57cec5SDimitry Andric V->print(OS); 8010b57cec5SDimitry Andric } 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric OS << "Buckets and Hashes: \n"; 804fcaf7f86SDimitry Andric for (const auto &Bucket : Buckets) 805fcaf7f86SDimitry Andric for (const auto &Hash : Bucket) 8060b57cec5SDimitry Andric Hash->print(OS); 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric OS << "Data: \n"; 809fcaf7f86SDimitry Andric for (const auto &E : Entries) 8100b57cec5SDimitry Andric E.second.print(OS); 8110b57cec5SDimitry Andric } 8120b57cec5SDimitry Andric 8130b57cec5SDimitry Andric void DWARF5AccelTableData::print(raw_ostream &OS) const { 8140b57cec5SDimitry Andric OS << " Offset: " << getDieOffset() << "\n"; 8150b57cec5SDimitry Andric OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n"; 8160b57cec5SDimitry Andric } 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric void AppleAccelTableOffsetData::print(raw_ostream &OS) const { 8190b57cec5SDimitry Andric OS << " Offset: " << Die.getOffset() << "\n"; 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric void AppleAccelTableTypeData::print(raw_ostream &OS) const { 8230b57cec5SDimitry Andric OS << " Offset: " << Die.getOffset() << "\n"; 8240b57cec5SDimitry Andric OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; 8250b57cec5SDimitry Andric } 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const { 8280b57cec5SDimitry Andric OS << " Static Offset: " << Offset << "\n"; 8290b57cec5SDimitry Andric } 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const { 8320b57cec5SDimitry Andric OS << " Static Offset: " << Offset << "\n"; 8330b57cec5SDimitry Andric OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; 8340b57cec5SDimitry Andric OS << " Tag: " << dwarf::TagString(Tag) << "\n"; 8350b57cec5SDimitry Andric OS << " ObjCClassIsImplementation: " 8360b57cec5SDimitry Andric << (ObjCClassIsImplementation ? "true" : "false"); 8370b57cec5SDimitry Andric OS << "\n"; 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric #endif 840