xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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