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"
15c9157d92SDimitry Andric #include "DwarfUnit.h"
16*a58f00eaSDimitry 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 
computeBucketCount()340b57cec5SDimitry Andric void AccelTableBase::computeBucketCount() {
350b57cec5SDimitry Andric   // First get the number of unique hashes.
360b57cec5SDimitry Andric   std::vector<uint32_t> Uniques;
370b57cec5SDimitry Andric   Uniques.reserve(Entries.size());
380b57cec5SDimitry Andric   for (const auto &E : Entries)
390b57cec5SDimitry Andric     Uniques.push_back(E.second.HashValue);
400b57cec5SDimitry Andric   array_pod_sort(Uniques.begin(), Uniques.end());
410b57cec5SDimitry Andric   std::vector<uint32_t>::iterator P =
420b57cec5SDimitry Andric       std::unique(Uniques.begin(), Uniques.end());
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   UniqueHashCount = std::distance(Uniques.begin(), P);
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   if (UniqueHashCount > 1024)
470b57cec5SDimitry Andric     BucketCount = UniqueHashCount / 4;
480b57cec5SDimitry Andric   else if (UniqueHashCount > 16)
490b57cec5SDimitry Andric     BucketCount = UniqueHashCount / 2;
500b57cec5SDimitry Andric   else
510b57cec5SDimitry Andric     BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
finalize(AsmPrinter * Asm,StringRef Prefix)540b57cec5SDimitry Andric void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
550b57cec5SDimitry Andric   // Create the individual hash data outputs.
560b57cec5SDimitry Andric   for (auto &E : Entries) {
570b57cec5SDimitry Andric     // Unique the entries.
580b57cec5SDimitry Andric     llvm::stable_sort(E.second.Values,
590b57cec5SDimitry Andric                       [](const AccelTableData *A, const AccelTableData *B) {
600b57cec5SDimitry Andric                         return *A < *B;
610b57cec5SDimitry Andric                       });
620b57cec5SDimitry Andric     E.second.Values.erase(
630b57cec5SDimitry Andric         std::unique(E.second.Values.begin(), E.second.Values.end()),
640b57cec5SDimitry Andric         E.second.Values.end());
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   // Figure out how many buckets we need, then compute the bucket contents and
680b57cec5SDimitry Andric   // the final ordering. The hashes and offsets can be emitted by walking these
690b57cec5SDimitry Andric   // data structures. We add temporary symbols to the data so they can be
700b57cec5SDimitry Andric   // referenced when emitting the offsets.
710b57cec5SDimitry Andric   computeBucketCount();
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   // Compute bucket contents and final ordering.
740b57cec5SDimitry Andric   Buckets.resize(BucketCount);
750b57cec5SDimitry Andric   for (auto &E : Entries) {
760b57cec5SDimitry Andric     uint32_t Bucket = E.second.HashValue % BucketCount;
770b57cec5SDimitry Andric     Buckets[Bucket].push_back(&E.second);
780b57cec5SDimitry Andric     E.second.Sym = Asm->createTempSymbol(Prefix);
790b57cec5SDimitry Andric   }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   // Sort the contents of the buckets by hash value so that hash collisions end
820b57cec5SDimitry Andric   // up together. Stable sort makes testing easier and doesn't cost much more.
830b57cec5SDimitry Andric   for (auto &Bucket : Buckets)
840b57cec5SDimitry Andric     llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
850b57cec5SDimitry Andric       return LHS->HashValue < RHS->HashValue;
860b57cec5SDimitry Andric     });
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric namespace {
900b57cec5SDimitry Andric /// Base class for writing out Accelerator tables. It holds the common
910b57cec5SDimitry Andric /// functionality for the two Accelerator table types.
920b57cec5SDimitry Andric class AccelTableWriter {
930b57cec5SDimitry Andric protected:
940b57cec5SDimitry Andric   AsmPrinter *const Asm;          ///< Destination.
950b57cec5SDimitry Andric   const AccelTableBase &Contents; ///< Data to emit.
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   /// Controls whether to emit duplicate hash and offset table entries for names
980b57cec5SDimitry Andric   /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
990b57cec5SDimitry Andric   /// tables do.
1000b57cec5SDimitry Andric   const bool SkipIdenticalHashes;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   void emitHashes() const;
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   /// Emit offsets to lists of entries with identical names. The offsets are
1050b57cec5SDimitry Andric   /// relative to the Base argument.
1060b57cec5SDimitry Andric   void emitOffsets(const MCSymbol *Base) const;
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric public:
AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,bool SkipIdenticalHashes)1090b57cec5SDimitry Andric   AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
1100b57cec5SDimitry Andric                    bool SkipIdenticalHashes)
1110b57cec5SDimitry Andric       : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
1120b57cec5SDimitry Andric   }
1130b57cec5SDimitry Andric };
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric class AppleAccelTableWriter : public AccelTableWriter {
1160b57cec5SDimitry Andric   using Atom = AppleAccelTableData::Atom;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   /// The fixed header of an Apple Accelerator Table.
1190b57cec5SDimitry Andric   struct Header {
1200b57cec5SDimitry Andric     uint32_t Magic = MagicHash;
1210b57cec5SDimitry Andric     uint16_t Version = 1;
1220b57cec5SDimitry Andric     uint16_t HashFunction = dwarf::DW_hash_function_djb;
1230b57cec5SDimitry Andric     uint32_t BucketCount;
1240b57cec5SDimitry Andric     uint32_t HashCount;
1250b57cec5SDimitry Andric     uint32_t HeaderDataLength;
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric     /// 'HASH' magic value to detect endianness.
1280b57cec5SDimitry Andric     static const uint32_t MagicHash = 0x48415348;
1290b57cec5SDimitry Andric 
Header__anon5311ae9e0311::AppleAccelTableWriter::Header1300b57cec5SDimitry Andric     Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
1310b57cec5SDimitry Andric         : BucketCount(BucketCount), HashCount(UniqueHashCount),
1320b57cec5SDimitry Andric           HeaderDataLength(DataLength) {}
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     void emit(AsmPrinter *Asm) const;
1350b57cec5SDimitry Andric #ifndef NDEBUG
1360b57cec5SDimitry Andric     void print(raw_ostream &OS) const;
dump__anon5311ae9e0311::AppleAccelTableWriter::Header1370b57cec5SDimitry Andric     void dump() const { print(dbgs()); }
1380b57cec5SDimitry Andric #endif
1390b57cec5SDimitry Andric   };
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   /// The HeaderData describes the structure of an Apple accelerator table
1420b57cec5SDimitry Andric   /// through a list of Atoms.
1430b57cec5SDimitry Andric   struct HeaderData {
1440b57cec5SDimitry Andric     /// In the case of data that is referenced via DW_FORM_ref_* the offset
1450b57cec5SDimitry Andric     /// base is used to describe the offset for all forms in the list of atoms.
1460b57cec5SDimitry Andric     uint32_t DieOffsetBase;
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric     const SmallVector<Atom, 4> Atoms;
1490b57cec5SDimitry Andric 
HeaderData__anon5311ae9e0311::AppleAccelTableWriter::HeaderData1500b57cec5SDimitry Andric     HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
1510b57cec5SDimitry Andric         : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric     void emit(AsmPrinter *Asm) const;
1540b57cec5SDimitry Andric #ifndef NDEBUG
1550b57cec5SDimitry Andric     void print(raw_ostream &OS) const;
dump__anon5311ae9e0311::AppleAccelTableWriter::HeaderData1560b57cec5SDimitry Andric     void dump() const { print(dbgs()); }
1570b57cec5SDimitry Andric #endif
1580b57cec5SDimitry Andric   };
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   Header Header;
1610b57cec5SDimitry Andric   HeaderData HeaderData;
1620b57cec5SDimitry Andric   const MCSymbol *SecBegin;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   void emitBuckets() const;
1650b57cec5SDimitry Andric   void emitData() const;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric public:
AppleAccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<Atom> Atoms,const MCSymbol * SecBegin)1680b57cec5SDimitry Andric   AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
1690b57cec5SDimitry Andric                         ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
1700b57cec5SDimitry Andric       : AccelTableWriter(Asm, Contents, true),
1710b57cec5SDimitry Andric         Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
1720b57cec5SDimitry Andric                8 + (Atoms.size() * 4)),
1730b57cec5SDimitry Andric         HeaderData(Atoms), SecBegin(SecBegin) {}
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   void emit() const;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric #ifndef NDEBUG
1780b57cec5SDimitry Andric   void print(raw_ostream &OS) const;
dump() const1790b57cec5SDimitry Andric   void dump() const { print(dbgs()); }
1800b57cec5SDimitry Andric #endif
1810b57cec5SDimitry Andric };
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric /// Class responsible for emitting a DWARF v5 Accelerator Table. The only
1840b57cec5SDimitry Andric /// public function is emit(), which performs the actual emission.
1850b57cec5SDimitry Andric ///
186cdc20ff6SDimitry Andric /// A callback abstracts the logic to provide a CU index for a given entry.
1870b57cec5SDimitry Andric class Dwarf5AccelTableWriter : public AccelTableWriter {
1880b57cec5SDimitry Andric   struct Header {
1890b57cec5SDimitry Andric     uint16_t Version = 5;
1900b57cec5SDimitry Andric     uint16_t Padding = 0;
1910b57cec5SDimitry Andric     uint32_t CompUnitCount;
1920b57cec5SDimitry Andric     uint32_t LocalTypeUnitCount = 0;
1930b57cec5SDimitry Andric     uint32_t ForeignTypeUnitCount = 0;
194fe013be4SDimitry Andric     uint32_t BucketCount = 0;
195fe013be4SDimitry Andric     uint32_t NameCount = 0;
1960b57cec5SDimitry Andric     uint32_t AbbrevTableSize = 0;
1970b57cec5SDimitry Andric     uint32_t AugmentationStringSize = sizeof(AugmentationString);
1980b57cec5SDimitry Andric     char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
1990b57cec5SDimitry Andric 
Header__anon5311ae9e0311::Dwarf5AccelTableWriter::Header200c9157d92SDimitry Andric     Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
201c9157d92SDimitry Andric            uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
202c9157d92SDimitry Andric            uint32_t NameCount)
203c9157d92SDimitry Andric         : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
204c9157d92SDimitry Andric           ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
2050b57cec5SDimitry Andric           NameCount(NameCount) {}
2060b57cec5SDimitry Andric 
207fe6060f1SDimitry Andric     void emit(Dwarf5AccelTableWriter &Ctx);
2080b57cec5SDimitry Andric   };
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   Header Header;
211*a58f00eaSDimitry Andric   DenseMap<uint32_t, SmallVector<DWARF5AccelTableData::AttributeEncoding, 3>>
212c9157d92SDimitry Andric       Abbreviations;
213c9157d92SDimitry Andric   ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
214c9157d92SDimitry Andric   ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
215c9157d92SDimitry Andric   llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
216cdc20ff6SDimitry Andric       const DWARF5AccelTableData &)>
217c9157d92SDimitry Andric       getIndexForEntry;
218fe6060f1SDimitry Andric   MCSymbol *ContributionEnd = nullptr;
2190b57cec5SDimitry Andric   MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
2200b57cec5SDimitry Andric   MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
2210b57cec5SDimitry Andric   MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
222c9157d92SDimitry Andric   // Indicates if this module is built with Split Dwarf enabled.
223c9157d92SDimitry Andric   bool IsSplitDwarf = false;
224*a58f00eaSDimitry Andric   /// Stores the DIE offsets which are indexed by this table.
225*a58f00eaSDimitry Andric   DenseSet<OffsetAndUnitID> IndexedOffsets;
2260b57cec5SDimitry Andric 
227c9157d92SDimitry Andric   void populateAbbrevsMap();
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   void emitCUList() const;
230c9157d92SDimitry Andric   void emitTUList() const;
2310b57cec5SDimitry Andric   void emitBuckets() const;
2320b57cec5SDimitry Andric   void emitStringOffsets() const;
2330b57cec5SDimitry Andric   void emitAbbrevs() const;
234*a58f00eaSDimitry Andric   void emitEntry(
235*a58f00eaSDimitry Andric       const DWARF5AccelTableData &Entry,
236*a58f00eaSDimitry Andric       const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
237*a58f00eaSDimitry Andric       DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) const;
238*a58f00eaSDimitry Andric   void emitData();
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric public:
2410b57cec5SDimitry Andric   Dwarf5AccelTableWriter(
2420b57cec5SDimitry Andric       AsmPrinter *Asm, const AccelTableBase &Contents,
243c9157d92SDimitry Andric       ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
244c9157d92SDimitry Andric       ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
245cdc20ff6SDimitry Andric       llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
246cdc20ff6SDimitry Andric           const DWARF5AccelTableData &)>
247c9157d92SDimitry Andric           getIndexForEntry,
248c9157d92SDimitry Andric       bool IsSplitDwarf);
2490b57cec5SDimitry Andric 
250fe6060f1SDimitry Andric   void emit();
2510b57cec5SDimitry Andric };
2520b57cec5SDimitry Andric } // namespace
2530b57cec5SDimitry Andric 
emitHashes() const2540b57cec5SDimitry Andric void AccelTableWriter::emitHashes() const {
2550b57cec5SDimitry Andric   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
2560b57cec5SDimitry Andric   unsigned BucketIdx = 0;
257fcaf7f86SDimitry Andric   for (const auto &Bucket : Contents.getBuckets()) {
258fcaf7f86SDimitry Andric     for (const auto &Hash : Bucket) {
2590b57cec5SDimitry Andric       uint32_t HashValue = Hash->HashValue;
2600b57cec5SDimitry Andric       if (SkipIdenticalHashes && PrevHash == HashValue)
2610b57cec5SDimitry Andric         continue;
2620b57cec5SDimitry Andric       Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
2630b57cec5SDimitry Andric       Asm->emitInt32(HashValue);
2640b57cec5SDimitry Andric       PrevHash = HashValue;
2650b57cec5SDimitry Andric     }
2660b57cec5SDimitry Andric     BucketIdx++;
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric 
emitOffsets(const MCSymbol * Base) const2700b57cec5SDimitry Andric void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
2710b57cec5SDimitry Andric   const auto &Buckets = Contents.getBuckets();
2720b57cec5SDimitry Andric   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
2730b57cec5SDimitry Andric   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
2740b57cec5SDimitry Andric     for (auto *Hash : Buckets[i]) {
2750b57cec5SDimitry Andric       uint32_t HashValue = Hash->HashValue;
2760b57cec5SDimitry Andric       if (SkipIdenticalHashes && PrevHash == HashValue)
2770b57cec5SDimitry Andric         continue;
2780b57cec5SDimitry Andric       PrevHash = HashValue;
2790b57cec5SDimitry Andric       Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
280e8d8bef9SDimitry Andric       Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
2810b57cec5SDimitry Andric     }
2820b57cec5SDimitry Andric   }
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric 
emit(AsmPrinter * Asm) const2850b57cec5SDimitry Andric void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
2860b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header Magic");
2870b57cec5SDimitry Andric   Asm->emitInt32(Magic);
2880b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header Version");
2890b57cec5SDimitry Andric   Asm->emitInt16(Version);
2900b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header Hash Function");
2910b57cec5SDimitry Andric   Asm->emitInt16(HashFunction);
2920b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header Bucket Count");
2930b57cec5SDimitry Andric   Asm->emitInt32(BucketCount);
2940b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header Hash Count");
2950b57cec5SDimitry Andric   Asm->emitInt32(HashCount);
2960b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header Data Length");
2970b57cec5SDimitry Andric   Asm->emitInt32(HeaderDataLength);
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
emit(AsmPrinter * Asm) const3000b57cec5SDimitry Andric void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
3010b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
3020b57cec5SDimitry Andric   Asm->emitInt32(DieOffsetBase);
3030b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("HeaderData Atom Count");
3040b57cec5SDimitry Andric   Asm->emitInt32(Atoms.size());
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   for (const Atom &A : Atoms) {
3070b57cec5SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
3080b57cec5SDimitry Andric     Asm->emitInt16(A.Type);
3090b57cec5SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
3100b57cec5SDimitry Andric     Asm->emitInt16(A.Form);
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric }
3130b57cec5SDimitry Andric 
emitBuckets() const3140b57cec5SDimitry Andric void AppleAccelTableWriter::emitBuckets() const {
3150b57cec5SDimitry Andric   const auto &Buckets = Contents.getBuckets();
3160b57cec5SDimitry Andric   unsigned index = 0;
3170b57cec5SDimitry Andric   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
3180b57cec5SDimitry Andric     Asm->OutStreamer->AddComment("Bucket " + Twine(i));
3190b57cec5SDimitry Andric     if (!Buckets[i].empty())
3200b57cec5SDimitry Andric       Asm->emitInt32(index);
3210b57cec5SDimitry Andric     else
3220b57cec5SDimitry Andric       Asm->emitInt32(std::numeric_limits<uint32_t>::max());
3230b57cec5SDimitry Andric     // Buckets point in the list of hashes, not to the data. Do not increment
3240b57cec5SDimitry Andric     // the index multiple times in case of hash collisions.
3250b57cec5SDimitry Andric     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
3260b57cec5SDimitry Andric     for (auto *HD : Buckets[i]) {
3270b57cec5SDimitry Andric       uint32_t HashValue = HD->HashValue;
3280b57cec5SDimitry Andric       if (PrevHash != HashValue)
3290b57cec5SDimitry Andric         ++index;
3300b57cec5SDimitry Andric       PrevHash = HashValue;
3310b57cec5SDimitry Andric     }
3320b57cec5SDimitry Andric   }
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric 
emitData() const3350b57cec5SDimitry Andric void AppleAccelTableWriter::emitData() const {
3360b57cec5SDimitry Andric   const auto &Buckets = Contents.getBuckets();
337fe6060f1SDimitry Andric   for (const AccelTableBase::HashList &Bucket : Buckets) {
3380b57cec5SDimitry Andric     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
339fcaf7f86SDimitry Andric     for (const auto &Hash : Bucket) {
3400b57cec5SDimitry Andric       // Terminate the previous entry if there is no hash collision with the
3410b57cec5SDimitry Andric       // current one.
3420b57cec5SDimitry Andric       if (PrevHash != std::numeric_limits<uint64_t>::max() &&
3430b57cec5SDimitry Andric           PrevHash != Hash->HashValue)
3440b57cec5SDimitry Andric         Asm->emitInt32(0);
3450b57cec5SDimitry Andric       // Remember to emit the label for our offset.
3465ffd83dbSDimitry Andric       Asm->OutStreamer->emitLabel(Hash->Sym);
3470b57cec5SDimitry Andric       Asm->OutStreamer->AddComment(Hash->Name.getString());
3480b57cec5SDimitry Andric       Asm->emitDwarfStringOffset(Hash->Name);
3490b57cec5SDimitry Andric       Asm->OutStreamer->AddComment("Num DIEs");
3500b57cec5SDimitry Andric       Asm->emitInt32(Hash->Values.size());
351cdc20ff6SDimitry Andric       for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
352cdc20ff6SDimitry Andric         V->emit(Asm);
3530b57cec5SDimitry Andric       PrevHash = Hash->HashValue;
3540b57cec5SDimitry Andric     }
3550b57cec5SDimitry Andric     // Emit the final end marker for the bucket.
356fe6060f1SDimitry Andric     if (!Bucket.empty())
3570b57cec5SDimitry Andric       Asm->emitInt32(0);
3580b57cec5SDimitry Andric   }
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric 
emit() const3610b57cec5SDimitry Andric void AppleAccelTableWriter::emit() const {
3620b57cec5SDimitry Andric   Header.emit(Asm);
3630b57cec5SDimitry Andric   HeaderData.emit(Asm);
3640b57cec5SDimitry Andric   emitBuckets();
3650b57cec5SDimitry Andric   emitHashes();
3660b57cec5SDimitry Andric   emitOffsets(SecBegin);
3670b57cec5SDimitry Andric   emitData();
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
DWARF5AccelTableData(const DIE & Die,const uint32_t UnitID,const bool IsTU)370c9157d92SDimitry Andric DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
371c9157d92SDimitry Andric                                            const uint32_t UnitID,
372c9157d92SDimitry Andric                                            const bool IsTU)
373c9157d92SDimitry Andric     : OffsetVal(&Die), DieTag(Die.getTag()), UnitID(UnitID), IsTU(IsTU) {}
374c9157d92SDimitry Andric 
emit(Dwarf5AccelTableWriter & Ctx)375cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
3760b57cec5SDimitry Andric   assert(CompUnitCount > 0 && "Index must have at least one CU.");
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric   AsmPrinter *Asm = Ctx.Asm;
379fe6060f1SDimitry Andric   Ctx.ContributionEnd =
380fe6060f1SDimitry Andric       Asm->emitDwarfUnitLength("names", "Header: unit length");
3810b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: version");
3820b57cec5SDimitry Andric   Asm->emitInt16(Version);
3830b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: padding");
3840b57cec5SDimitry Andric   Asm->emitInt16(Padding);
3850b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: compilation unit count");
3860b57cec5SDimitry Andric   Asm->emitInt32(CompUnitCount);
3870b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: local type unit count");
3880b57cec5SDimitry Andric   Asm->emitInt32(LocalTypeUnitCount);
3890b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: foreign type unit count");
3900b57cec5SDimitry Andric   Asm->emitInt32(ForeignTypeUnitCount);
3910b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: bucket count");
3920b57cec5SDimitry Andric   Asm->emitInt32(BucketCount);
3930b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: name count");
3940b57cec5SDimitry Andric   Asm->emitInt32(NameCount);
3950b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: abbreviation table size");
3965ffd83dbSDimitry Andric   Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
3970b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: augmentation string size");
3980b57cec5SDimitry Andric   assert(AugmentationStringSize % 4 == 0);
3990b57cec5SDimitry Andric   Asm->emitInt32(AugmentationStringSize);
4000b57cec5SDimitry Andric   Asm->OutStreamer->AddComment("Header: augmentation string");
4015ffd83dbSDimitry Andric   Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
404*a58f00eaSDimitry Andric std::optional<uint64_t>
getDefiningParentDieOffset(const DIE & Die)405*a58f00eaSDimitry Andric DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
406*a58f00eaSDimitry Andric   if (auto *Parent = Die.getParent();
407*a58f00eaSDimitry Andric       Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
408*a58f00eaSDimitry Andric     return Parent->getOffset();
409*a58f00eaSDimitry Andric   return {};
410*a58f00eaSDimitry Andric }
411*a58f00eaSDimitry Andric 
412*a58f00eaSDimitry Andric enum IdxParentEncoding : uint8_t {
413*a58f00eaSDimitry Andric   NoIndexedParent = 0, /// Parent information present but parent isn't indexed.
414*a58f00eaSDimitry Andric   Ref4 = 1,            /// Parent information present and parent is indexed.
415*a58f00eaSDimitry Andric   NoParent = 2,        /// Parent information missing.
416*a58f00eaSDimitry Andric };
417*a58f00eaSDimitry Andric 
418*a58f00eaSDimitry Andric static uint32_t constexpr NumBitsIdxParent = 2;
419*a58f00eaSDimitry Andric 
encodeIdxParent(const std::optional<dwarf::Form> MaybeParentForm)420*a58f00eaSDimitry Andric uint8_t encodeIdxParent(const std::optional<dwarf::Form> MaybeParentForm) {
421*a58f00eaSDimitry Andric   if (!MaybeParentForm)
422*a58f00eaSDimitry Andric     return NoParent;
423*a58f00eaSDimitry Andric   switch (*MaybeParentForm) {
424*a58f00eaSDimitry Andric   case dwarf::Form::DW_FORM_flag_present:
425*a58f00eaSDimitry Andric     return NoIndexedParent;
426*a58f00eaSDimitry Andric   case dwarf::Form::DW_FORM_ref4:
427*a58f00eaSDimitry Andric     return Ref4;
428*a58f00eaSDimitry Andric   default:
429*a58f00eaSDimitry Andric     // This is not crashing on bad input: we should only reach this if the
430*a58f00eaSDimitry Andric     // internal compiler logic is faulty; see getFormForIdxParent.
431*a58f00eaSDimitry Andric     llvm_unreachable("Bad form for IDX_parent");
432*a58f00eaSDimitry Andric   }
433*a58f00eaSDimitry Andric }
434*a58f00eaSDimitry Andric 
435*a58f00eaSDimitry Andric static uint32_t constexpr ParentBitOffset = dwarf::DW_IDX_type_hash;
436*a58f00eaSDimitry Andric static uint32_t constexpr TagBitOffset = ParentBitOffset + NumBitsIdxParent;
getTagFromAbbreviationTag(const uint32_t AbbrvTag)437c9157d92SDimitry Andric static uint32_t getTagFromAbbreviationTag(const uint32_t AbbrvTag) {
438*a58f00eaSDimitry Andric   return AbbrvTag >> TagBitOffset;
439c9157d92SDimitry Andric }
440c9157d92SDimitry Andric 
441c9157d92SDimitry Andric /// Constructs a unique AbbrevTag that captures what a DIE accesses.
442c9157d92SDimitry Andric /// Using this tag we can emit a unique abbreviation for each DIE.
constructAbbreviationTag(const unsigned Tag,const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> & EntryRet,std::optional<dwarf::Form> MaybeParentForm)443c9157d92SDimitry Andric static uint32_t constructAbbreviationTag(
444c9157d92SDimitry Andric     const unsigned Tag,
445*a58f00eaSDimitry Andric     const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> &EntryRet,
446*a58f00eaSDimitry Andric     std::optional<dwarf::Form> MaybeParentForm) {
447c9157d92SDimitry Andric   uint32_t AbbrvTag = 0;
448c9157d92SDimitry Andric   if (EntryRet)
449e710425bSDimitry Andric     AbbrvTag |= 1 << EntryRet->Encoding.Index;
450c9157d92SDimitry Andric   AbbrvTag |= 1 << dwarf::DW_IDX_die_offset;
451*a58f00eaSDimitry Andric   AbbrvTag |= 1 << dwarf::DW_IDX_parent;
452*a58f00eaSDimitry Andric   AbbrvTag |= encodeIdxParent(MaybeParentForm) << ParentBitOffset;
453*a58f00eaSDimitry Andric   AbbrvTag |= Tag << TagBitOffset;
454c9157d92SDimitry Andric   return AbbrvTag;
455c9157d92SDimitry Andric }
456*a58f00eaSDimitry Andric 
457*a58f00eaSDimitry Andric static std::optional<dwarf::Form>
getFormForIdxParent(const DenseSet<OffsetAndUnitID> & IndexedOffsets,std::optional<OffsetAndUnitID> ParentOffset)458*a58f00eaSDimitry Andric getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
459*a58f00eaSDimitry Andric                     std::optional<OffsetAndUnitID> ParentOffset) {
460*a58f00eaSDimitry Andric   // No parent information
461*a58f00eaSDimitry Andric   if (!ParentOffset)
462*a58f00eaSDimitry Andric     return std::nullopt;
463*a58f00eaSDimitry Andric   // Parent is indexed by this table.
464*a58f00eaSDimitry Andric   if (IndexedOffsets.contains(*ParentOffset))
465*a58f00eaSDimitry Andric     return dwarf::Form::DW_FORM_ref4;
466*a58f00eaSDimitry Andric   // Parent is not indexed by this table.
467*a58f00eaSDimitry Andric   return dwarf::Form::DW_FORM_flag_present;
468*a58f00eaSDimitry Andric }
469*a58f00eaSDimitry Andric 
populateAbbrevsMap()470cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::populateAbbrevsMap() {
4710b57cec5SDimitry Andric   for (auto &Bucket : Contents.getBuckets()) {
4720b57cec5SDimitry Andric     for (auto *Hash : Bucket) {
473cdc20ff6SDimitry Andric       for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
474c9157d92SDimitry Andric         std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
475cdc20ff6SDimitry Andric             getIndexForEntry(*Value);
476cdc20ff6SDimitry Andric         unsigned Tag = Value->getDieTag();
477*a58f00eaSDimitry Andric         std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
478*a58f00eaSDimitry Andric             IndexedOffsets, Value->getParentDieOffsetAndUnitID());
479*a58f00eaSDimitry Andric         uint32_t AbbrvTag =
480*a58f00eaSDimitry Andric             constructAbbreviationTag(Tag, EntryRet, MaybeParentForm);
481c9157d92SDimitry Andric         if (Abbreviations.count(AbbrvTag) == 0) {
482*a58f00eaSDimitry Andric           SmallVector<DWARF5AccelTableData::AttributeEncoding, 3> UA;
483c9157d92SDimitry Andric           if (EntryRet)
484e710425bSDimitry Andric             UA.push_back(EntryRet->Encoding);
4850b57cec5SDimitry Andric           UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
486*a58f00eaSDimitry Andric           if (MaybeParentForm)
487*a58f00eaSDimitry Andric             UA.push_back({dwarf::DW_IDX_parent, *MaybeParentForm});
488c9157d92SDimitry Andric           Abbreviations.try_emplace(AbbrvTag, UA);
489c9157d92SDimitry Andric         }
490c9157d92SDimitry Andric       }
491c9157d92SDimitry Andric     }
492c9157d92SDimitry Andric   }
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric 
emitCUList() const495cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emitCUList() const {
4960b57cec5SDimitry Andric   for (const auto &CU : enumerate(CompUnits)) {
4970b57cec5SDimitry Andric     Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
498c9157d92SDimitry Andric     if (std::holds_alternative<MCSymbol *>(CU.value()))
499c9157d92SDimitry Andric       Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
500c9157d92SDimitry Andric     else
501c9157d92SDimitry Andric       Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
502c9157d92SDimitry Andric   }
503c9157d92SDimitry Andric }
504c9157d92SDimitry Andric 
emitTUList() const505cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emitTUList() const {
506c9157d92SDimitry Andric   for (const auto &TU : enumerate(TypeUnits)) {
507c9157d92SDimitry Andric     Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
508c9157d92SDimitry Andric     if (std::holds_alternative<MCSymbol *>(TU.value()))
509c9157d92SDimitry Andric       Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
510c9157d92SDimitry Andric     else if (IsSplitDwarf)
511c9157d92SDimitry Andric       Asm->emitInt64(std::get<uint64_t>(TU.value()));
512c9157d92SDimitry Andric     else
513c9157d92SDimitry Andric       Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
5140b57cec5SDimitry Andric   }
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric 
emitBuckets() const517cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emitBuckets() const {
5180b57cec5SDimitry Andric   uint32_t Index = 1;
5190b57cec5SDimitry Andric   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
5200b57cec5SDimitry Andric     Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
5210b57cec5SDimitry Andric     Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
5220b57cec5SDimitry Andric     Index += Bucket.value().size();
5230b57cec5SDimitry Andric   }
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric 
emitStringOffsets() const526cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emitStringOffsets() const {
5270b57cec5SDimitry Andric   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
5280b57cec5SDimitry Andric     for (auto *Hash : Bucket.value()) {
5290b57cec5SDimitry Andric       DwarfStringPoolEntryRef String = Hash->Name;
5300b57cec5SDimitry Andric       Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
5310b57cec5SDimitry Andric                                    ": " + String.getString());
5320b57cec5SDimitry Andric       Asm->emitDwarfStringOffset(String);
5330b57cec5SDimitry Andric     }
5340b57cec5SDimitry Andric   }
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric 
emitAbbrevs() const537cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emitAbbrevs() const {
5385ffd83dbSDimitry Andric   Asm->OutStreamer->emitLabel(AbbrevStart);
5390b57cec5SDimitry Andric   for (const auto &Abbrev : Abbreviations) {
5400b57cec5SDimitry Andric     Asm->OutStreamer->AddComment("Abbrev code");
541c9157d92SDimitry Andric     uint32_t Tag = getTagFromAbbreviationTag(Abbrev.first);
542c9157d92SDimitry Andric     assert(Tag != 0);
5435ffd83dbSDimitry Andric     Asm->emitULEB128(Abbrev.first);
544c9157d92SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::TagString(Tag));
545c9157d92SDimitry Andric     Asm->emitULEB128(Tag);
5460b57cec5SDimitry Andric     for (const auto &AttrEnc : Abbrev.second) {
5475ffd83dbSDimitry Andric       Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
5485ffd83dbSDimitry Andric       Asm->emitULEB128(AttrEnc.Form,
5490b57cec5SDimitry Andric                        dwarf::FormEncodingString(AttrEnc.Form).data());
5500b57cec5SDimitry Andric     }
5515ffd83dbSDimitry Andric     Asm->emitULEB128(0, "End of abbrev");
5525ffd83dbSDimitry Andric     Asm->emitULEB128(0, "End of abbrev");
5530b57cec5SDimitry Andric   }
5545ffd83dbSDimitry Andric   Asm->emitULEB128(0, "End of abbrev list");
5555ffd83dbSDimitry Andric   Asm->OutStreamer->emitLabel(AbbrevEnd);
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric 
emitEntry(const DWARF5AccelTableData & Entry,const DenseMap<OffsetAndUnitID,MCSymbol * > & DIEOffsetToAccelEntryLabel,DenseSet<MCSymbol * > & EmittedAccelEntrySymbols) const558cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emitEntry(
559*a58f00eaSDimitry Andric     const DWARF5AccelTableData &Entry,
560*a58f00eaSDimitry Andric     const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
561*a58f00eaSDimitry Andric     DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) const {
562c9157d92SDimitry Andric   std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
563c9157d92SDimitry Andric       getIndexForEntry(Entry);
564*a58f00eaSDimitry Andric   std::optional<OffsetAndUnitID> MaybeParentOffset =
565*a58f00eaSDimitry Andric       Entry.getParentDieOffsetAndUnitID();
566*a58f00eaSDimitry Andric   std::optional<dwarf::Form> MaybeParentForm =
567*a58f00eaSDimitry Andric       getFormForIdxParent(IndexedOffsets, MaybeParentOffset);
568*a58f00eaSDimitry Andric   uint32_t AbbrvTag =
569*a58f00eaSDimitry Andric       constructAbbreviationTag(Entry.getDieTag(), EntryRet, MaybeParentForm);
570c9157d92SDimitry Andric   auto AbbrevIt = Abbreviations.find(AbbrvTag);
5710b57cec5SDimitry Andric   assert(AbbrevIt != Abbreviations.end() &&
5720b57cec5SDimitry Andric          "Why wasn't this abbrev generated?");
573c9157d92SDimitry Andric   assert(getTagFromAbbreviationTag(AbbrevIt->first) == Entry.getDieTag() &&
574c9157d92SDimitry Andric          "Invalid Tag");
575*a58f00eaSDimitry Andric 
576*a58f00eaSDimitry Andric   auto EntrySymbolIt =
577*a58f00eaSDimitry Andric       DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
578*a58f00eaSDimitry Andric   assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
579*a58f00eaSDimitry Andric   MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
580*a58f00eaSDimitry Andric 
581*a58f00eaSDimitry Andric   // Emit the label for this Entry, so that IDX_parents may refer to it.
582*a58f00eaSDimitry Andric   // Note: a DIE may have multiple accelerator Entries; this check avoids
583*a58f00eaSDimitry Andric   // creating/emitting multiple labels for the same DIE.
584*a58f00eaSDimitry Andric   if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
585*a58f00eaSDimitry Andric     Asm->OutStreamer->emitLabel(EntrySymbol);
586*a58f00eaSDimitry Andric 
5875ffd83dbSDimitry Andric   Asm->emitULEB128(AbbrevIt->first, "Abbreviation code");
588c9157d92SDimitry Andric 
5890b57cec5SDimitry Andric   for (const auto &AttrEnc : AbbrevIt->second) {
5900b57cec5SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
5910b57cec5SDimitry Andric     switch (AttrEnc.Index) {
592c9157d92SDimitry Andric     case dwarf::DW_IDX_compile_unit:
593c9157d92SDimitry Andric     case dwarf::DW_IDX_type_unit: {
594c9157d92SDimitry Andric       DIEInteger ID(EntryRet->Index);
5955ffd83dbSDimitry Andric       ID.emitValue(Asm, AttrEnc.Form);
5960b57cec5SDimitry Andric       break;
5970b57cec5SDimitry Andric     }
5980b57cec5SDimitry Andric     case dwarf::DW_IDX_die_offset:
5990b57cec5SDimitry Andric       assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
6000b57cec5SDimitry Andric       Asm->emitInt32(Entry.getDieOffset());
6010b57cec5SDimitry Andric       break;
602*a58f00eaSDimitry Andric     case dwarf::DW_IDX_parent: {
603*a58f00eaSDimitry Andric       if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
604*a58f00eaSDimitry Andric         break;
605*a58f00eaSDimitry Andric       auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
606*a58f00eaSDimitry Andric       assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
607*a58f00eaSDimitry Andric       Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
608*a58f00eaSDimitry Andric       break;
609*a58f00eaSDimitry Andric     }
6100b57cec5SDimitry Andric     default:
6110b57cec5SDimitry Andric       llvm_unreachable("Unexpected index attribute!");
6120b57cec5SDimitry Andric     }
6130b57cec5SDimitry Andric   }
6140b57cec5SDimitry Andric }
6150b57cec5SDimitry Andric 
emitData()616*a58f00eaSDimitry Andric void Dwarf5AccelTableWriter::emitData() {
617*a58f00eaSDimitry Andric   DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
618*a58f00eaSDimitry Andric 
619*a58f00eaSDimitry Andric   for (OffsetAndUnitID Offset : IndexedOffsets)
620*a58f00eaSDimitry Andric     DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
621*a58f00eaSDimitry Andric 
6225ffd83dbSDimitry Andric   Asm->OutStreamer->emitLabel(EntryPool);
623*a58f00eaSDimitry Andric   DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
6240b57cec5SDimitry Andric   for (auto &Bucket : Contents.getBuckets()) {
6250b57cec5SDimitry Andric     for (auto *Hash : Bucket) {
6260b57cec5SDimitry Andric       // Remember to emit the label for our offset.
6275ffd83dbSDimitry Andric       Asm->OutStreamer->emitLabel(Hash->Sym);
628*a58f00eaSDimitry Andric       for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
629*a58f00eaSDimitry Andric         emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
6300b57cec5SDimitry Andric       Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
631e8d8bef9SDimitry Andric       Asm->emitInt8(0);
6320b57cec5SDimitry Andric     }
6330b57cec5SDimitry Andric   }
6340b57cec5SDimitry Andric }
6350b57cec5SDimitry Andric 
Dwarf5AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<std::variant<MCSymbol *,uint64_t>> CompUnits,ArrayRef<std::variant<MCSymbol *,uint64_t>> TypeUnits,llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding> (const DWARF5AccelTableData &)> getIndexForEntry,bool IsSplitDwarf)636cdc20ff6SDimitry Andric Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
6370b57cec5SDimitry Andric     AsmPrinter *Asm, const AccelTableBase &Contents,
638c9157d92SDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
639c9157d92SDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
640cdc20ff6SDimitry Andric     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
641cdc20ff6SDimitry Andric         const DWARF5AccelTableData &)>
642c9157d92SDimitry Andric         getIndexForEntry,
643c9157d92SDimitry Andric     bool IsSplitDwarf)
6440b57cec5SDimitry Andric     : AccelTableWriter(Asm, Contents, false),
645c9157d92SDimitry Andric       Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
646c9157d92SDimitry Andric              IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
6470b57cec5SDimitry Andric              Contents.getUniqueNameCount()),
648c9157d92SDimitry Andric       CompUnits(CompUnits), TypeUnits(TypeUnits),
649c9157d92SDimitry Andric       getIndexForEntry(std::move(getIndexForEntry)),
650c9157d92SDimitry Andric       IsSplitDwarf(IsSplitDwarf) {
651*a58f00eaSDimitry Andric 
652*a58f00eaSDimitry Andric   for (auto &Bucket : Contents.getBuckets())
653*a58f00eaSDimitry Andric     for (auto *Hash : Bucket)
654*a58f00eaSDimitry Andric       for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
655*a58f00eaSDimitry Andric         IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
656*a58f00eaSDimitry Andric 
657c9157d92SDimitry Andric   populateAbbrevsMap();
6580b57cec5SDimitry Andric }
6590b57cec5SDimitry Andric 
emit()660cdc20ff6SDimitry Andric void Dwarf5AccelTableWriter::emit() {
6610b57cec5SDimitry Andric   Header.emit(*this);
6620b57cec5SDimitry Andric   emitCUList();
663c9157d92SDimitry Andric   emitTUList();
6640b57cec5SDimitry Andric   emitBuckets();
6650b57cec5SDimitry Andric   emitHashes();
6660b57cec5SDimitry Andric   emitStringOffsets();
6670b57cec5SDimitry Andric   emitOffsets(EntryPool);
6680b57cec5SDimitry Andric   emitAbbrevs();
6690b57cec5SDimitry Andric   emitData();
670bdd1243dSDimitry Andric   Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
6715ffd83dbSDimitry Andric   Asm->OutStreamer->emitLabel(ContributionEnd);
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric 
emitAppleAccelTableImpl(AsmPrinter * Asm,AccelTableBase & Contents,StringRef Prefix,const MCSymbol * SecBegin,ArrayRef<AppleAccelTableData::Atom> Atoms)6740b57cec5SDimitry Andric void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
6750b57cec5SDimitry Andric                                    StringRef Prefix, const MCSymbol *SecBegin,
6760b57cec5SDimitry Andric                                    ArrayRef<AppleAccelTableData::Atom> Atoms) {
6770b57cec5SDimitry Andric   Contents.finalize(Asm, Prefix);
6780b57cec5SDimitry Andric   AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
6790b57cec5SDimitry Andric }
6800b57cec5SDimitry Andric 
emitDWARF5AccelTable(AsmPrinter * Asm,DWARF5AccelTable & Contents,const DwarfDebug & DD,ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs)6810b57cec5SDimitry Andric void llvm::emitDWARF5AccelTable(
682c9157d92SDimitry Andric     AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
683c9157d92SDimitry Andric     ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
684c9157d92SDimitry Andric   TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
685c9157d92SDimitry Andric   std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
686c9157d92SDimitry Andric   std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
6870b57cec5SDimitry Andric   SmallVector<unsigned, 1> CUIndex(CUs.size());
688c9157d92SDimitry Andric   DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
689c9157d92SDimitry Andric   int CUCount = 0;
690c9157d92SDimitry Andric   int TUCount = 0;
6910b57cec5SDimitry Andric   for (const auto &CU : enumerate(CUs)) {
692fe013be4SDimitry Andric     switch (CU.value()->getCUNode()->getNameTableKind()) {
693fe013be4SDimitry Andric     case DICompileUnit::DebugNameTableKind::Default:
694fe013be4SDimitry Andric     case DICompileUnit::DebugNameTableKind::Apple:
695fe013be4SDimitry Andric       break;
696fe013be4SDimitry Andric     default:
6970b57cec5SDimitry Andric       continue;
698fe013be4SDimitry Andric     }
699c9157d92SDimitry Andric     CUIndex[CU.index()] = CUCount++;
7000b57cec5SDimitry Andric     assert(CU.index() == CU.value()->getUniqueID());
7010b57cec5SDimitry Andric     const DwarfCompileUnit *MainCU =
7020b57cec5SDimitry Andric         DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
7030b57cec5SDimitry Andric     CompUnits.push_back(MainCU->getLabelBegin());
7040b57cec5SDimitry Andric   }
7050b57cec5SDimitry Andric 
706c9157d92SDimitry Andric   for (const auto &TU : TUSymbols) {
707c9157d92SDimitry Andric     TUIndex[TU.UniqueID] = TUCount++;
708c9157d92SDimitry Andric     if (DD.useSplitDwarf())
709c9157d92SDimitry Andric       TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
710c9157d92SDimitry Andric     else
711c9157d92SDimitry Andric       TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
712c9157d92SDimitry Andric   }
713c9157d92SDimitry Andric 
7140b57cec5SDimitry Andric   if (CompUnits.empty())
7150b57cec5SDimitry Andric     return;
7160b57cec5SDimitry Andric 
71781ad6265SDimitry Andric   Asm->OutStreamer->switchSection(
7180b57cec5SDimitry Andric       Asm->getObjFileLowering().getDwarfDebugNamesSection());
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   Contents.finalize(Asm, "names");
721c9157d92SDimitry Andric   dwarf::Form CUIndexForm =
722c9157d92SDimitry Andric       DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
723c9157d92SDimitry Andric   dwarf::Form TUIndexForm =
724c9157d92SDimitry Andric       DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
725cdc20ff6SDimitry Andric   Dwarf5AccelTableWriter(
726c9157d92SDimitry Andric       Asm, Contents, CompUnits, TypeUnits,
727c9157d92SDimitry Andric       [&](const DWARF5AccelTableData &Entry)
728c9157d92SDimitry Andric           -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
729c9157d92SDimitry Andric         if (Entry.isTU())
730c9157d92SDimitry Andric           return {{TUIndex[Entry.getUnitID()],
731c9157d92SDimitry Andric                    {dwarf::DW_IDX_type_unit, TUIndexForm}}};
732c9157d92SDimitry Andric         if (CUIndex.size() > 1)
733c9157d92SDimitry Andric           return {{CUIndex[Entry.getUnitID()],
734c9157d92SDimitry Andric                    {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
735c9157d92SDimitry Andric         return std::nullopt;
736c9157d92SDimitry Andric       },
737c9157d92SDimitry Andric       DD.useSplitDwarf())
7380b57cec5SDimitry Andric       .emit();
7390b57cec5SDimitry Andric }
7400b57cec5SDimitry Andric 
addTypeUnitSymbol(DwarfTypeUnit & U)741c9157d92SDimitry Andric void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
742c9157d92SDimitry Andric   TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
743c9157d92SDimitry Andric }
744c9157d92SDimitry Andric 
addTypeUnitSignature(DwarfTypeUnit & U)745c9157d92SDimitry Andric void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
746c9157d92SDimitry Andric   TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
747c9157d92SDimitry Andric }
748c9157d92SDimitry Andric 
emitDWARF5AccelTable(AsmPrinter * Asm,DWARF5AccelTable & Contents,ArrayRef<std::variant<MCSymbol *,uint64_t>> CUs,llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding> (const DWARF5AccelTableData &)> getIndexForEntry)7490b57cec5SDimitry Andric void llvm::emitDWARF5AccelTable(
750c9157d92SDimitry Andric     AsmPrinter *Asm, DWARF5AccelTable &Contents,
751c9157d92SDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
752c9157d92SDimitry Andric     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
753c9157d92SDimitry Andric         const DWARF5AccelTableData &)>
754c9157d92SDimitry Andric         getIndexForEntry) {
755c9157d92SDimitry Andric   std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
7560b57cec5SDimitry Andric   Contents.finalize(Asm, "names");
757cdc20ff6SDimitry Andric   Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
7580b57cec5SDimitry Andric       .emit();
7590b57cec5SDimitry Andric }
7600b57cec5SDimitry Andric 
emit(AsmPrinter * Asm) const7610b57cec5SDimitry Andric void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
762e8d8bef9SDimitry Andric   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
763e8d8bef9SDimitry Andric          "The section offset exceeds the limit.");
7640b57cec5SDimitry Andric   Asm->emitInt32(Die.getDebugSectionOffset());
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric 
emit(AsmPrinter * Asm) const7670b57cec5SDimitry Andric void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
768e8d8bef9SDimitry Andric   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
769e8d8bef9SDimitry Andric          "The section offset exceeds the limit.");
7700b57cec5SDimitry Andric   Asm->emitInt32(Die.getDebugSectionOffset());
7710b57cec5SDimitry Andric   Asm->emitInt16(Die.getTag());
7720b57cec5SDimitry Andric   Asm->emitInt8(0);
7730b57cec5SDimitry Andric }
7740b57cec5SDimitry Andric 
emit(AsmPrinter * Asm) const7750b57cec5SDimitry Andric void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
7760b57cec5SDimitry Andric   Asm->emitInt32(Offset);
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
emit(AsmPrinter * Asm) const7790b57cec5SDimitry Andric void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
7800b57cec5SDimitry Andric   Asm->emitInt32(Offset);
7810b57cec5SDimitry Andric   Asm->emitInt16(Tag);
7820b57cec5SDimitry Andric   Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
7830b57cec5SDimitry Andric                                           : 0);
7840b57cec5SDimitry Andric   Asm->emitInt32(QualifiedNameHash);
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
7880b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
7890b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
7900b57cec5SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric #ifndef NDEBUG
print(raw_ostream & OS) const7930b57cec5SDimitry Andric void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
7940b57cec5SDimitry Andric   OS << "Magic: " << format("0x%x", Magic) << "\n"
7950b57cec5SDimitry Andric      << "Version: " << Version << "\n"
7960b57cec5SDimitry Andric      << "Hash Function: " << HashFunction << "\n"
7970b57cec5SDimitry Andric      << "Bucket Count: " << BucketCount << "\n"
7980b57cec5SDimitry Andric      << "Header Data Length: " << HeaderDataLength << "\n";
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric 
print(raw_ostream & OS) const8010b57cec5SDimitry Andric void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
8020b57cec5SDimitry Andric   OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
8030b57cec5SDimitry Andric      << "Form: " << dwarf::FormEncodingString(Form) << "\n";
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric 
print(raw_ostream & OS) const8060b57cec5SDimitry Andric void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
8070b57cec5SDimitry Andric   OS << "DIE Offset Base: " << DieOffsetBase << "\n";
8080b57cec5SDimitry Andric   for (auto Atom : Atoms)
8090b57cec5SDimitry Andric     Atom.print(OS);
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric 
print(raw_ostream & OS) const8120b57cec5SDimitry Andric void AppleAccelTableWriter::print(raw_ostream &OS) const {
8130b57cec5SDimitry Andric   Header.print(OS);
8140b57cec5SDimitry Andric   HeaderData.print(OS);
8150b57cec5SDimitry Andric   Contents.print(OS);
8160b57cec5SDimitry Andric   SecBegin->print(OS, nullptr);
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
print(raw_ostream & OS) const8190b57cec5SDimitry Andric void AccelTableBase::HashData::print(raw_ostream &OS) const {
8200b57cec5SDimitry Andric   OS << "Name: " << Name.getString() << "\n";
8210b57cec5SDimitry Andric   OS << "  Hash Value: " << format("0x%x", HashValue) << "\n";
8220b57cec5SDimitry Andric   OS << "  Symbol: ";
8230b57cec5SDimitry Andric   if (Sym)
8240b57cec5SDimitry Andric     OS << *Sym;
8250b57cec5SDimitry Andric   else
8260b57cec5SDimitry Andric     OS << "<none>";
8270b57cec5SDimitry Andric   OS << "\n";
8280b57cec5SDimitry Andric   for (auto *Value : Values)
8290b57cec5SDimitry Andric     Value->print(OS);
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric 
print(raw_ostream & OS) const8320b57cec5SDimitry Andric void AccelTableBase::print(raw_ostream &OS) const {
8330b57cec5SDimitry Andric   // Print Content.
8340b57cec5SDimitry Andric   OS << "Entries: \n";
835fe013be4SDimitry Andric   for (const auto &[Name, Data] : Entries) {
836fe013be4SDimitry Andric     OS << "Name: " << Name << "\n";
837fe013be4SDimitry Andric     for (auto *V : Data.Values)
8380b57cec5SDimitry Andric       V->print(OS);
8390b57cec5SDimitry Andric   }
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric   OS << "Buckets and Hashes: \n";
842fcaf7f86SDimitry Andric   for (const auto &Bucket : Buckets)
843fcaf7f86SDimitry Andric     for (const auto &Hash : Bucket)
8440b57cec5SDimitry Andric       Hash->print(OS);
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric   OS << "Data: \n";
847fcaf7f86SDimitry Andric   for (const auto &E : Entries)
8480b57cec5SDimitry Andric     E.second.print(OS);
8490b57cec5SDimitry Andric }
8500b57cec5SDimitry Andric 
print(raw_ostream & OS) const8510b57cec5SDimitry Andric void DWARF5AccelTableData::print(raw_ostream &OS) const {
8520b57cec5SDimitry Andric   OS << "  Offset: " << getDieOffset() << "\n";
8530b57cec5SDimitry Andric   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
8540b57cec5SDimitry Andric }
8550b57cec5SDimitry Andric 
print(raw_ostream & OS) const8560b57cec5SDimitry Andric void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
8570b57cec5SDimitry Andric   OS << "  Offset: " << Die.getOffset() << "\n";
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric 
print(raw_ostream & OS) const8600b57cec5SDimitry Andric void AppleAccelTableTypeData::print(raw_ostream &OS) const {
8610b57cec5SDimitry Andric   OS << "  Offset: " << Die.getOffset() << "\n";
8620b57cec5SDimitry Andric   OS << "  Tag: " << dwarf::TagString(Die.getTag()) << "\n";
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric 
print(raw_ostream & OS) const8650b57cec5SDimitry Andric void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
8660b57cec5SDimitry Andric   OS << "  Static Offset: " << Offset << "\n";
8670b57cec5SDimitry Andric }
8680b57cec5SDimitry Andric 
print(raw_ostream & OS) const8690b57cec5SDimitry Andric void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
8700b57cec5SDimitry Andric   OS << "  Static Offset: " << Offset << "\n";
8710b57cec5SDimitry Andric   OS << "  QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
8720b57cec5SDimitry Andric   OS << "  Tag: " << dwarf::TagString(Tag) << "\n";
8730b57cec5SDimitry Andric   OS << "  ObjCClassIsImplementation: "
8740b57cec5SDimitry Andric      << (ObjCClassIsImplementation ? "true" : "false");
8750b57cec5SDimitry Andric   OS << "\n";
8760b57cec5SDimitry Andric }
8770b57cec5SDimitry Andric #endif
878