xref: /src/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1eb11fae6SDimitry Andric //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
2eb11fae6SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6eb11fae6SDimitry Andric //
7eb11fae6SDimitry Andric //===----------------------------------------------------------------------===//
8eb11fae6SDimitry Andric //
9eb11fae6SDimitry Andric // This file contains support for writing accelerator tables.
10eb11fae6SDimitry Andric //
11eb11fae6SDimitry Andric //===----------------------------------------------------------------------===//
12eb11fae6SDimitry Andric 
13eb11fae6SDimitry Andric #include "llvm/CodeGen/AccelTable.h"
14eb11fae6SDimitry Andric #include "DwarfCompileUnit.h"
15b1c73532SDimitry Andric #include "DwarfUnit.h"
164df029ccSDimitry Andric #include "llvm/ADT/DenseSet.h"
17eb11fae6SDimitry Andric #include "llvm/ADT/STLExtras.h"
18eb11fae6SDimitry Andric #include "llvm/ADT/Twine.h"
19eb11fae6SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
20eb11fae6SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
21eb11fae6SDimitry Andric #include "llvm/CodeGen/DIE.h"
22eb11fae6SDimitry Andric #include "llvm/MC/MCStreamer.h"
23eb11fae6SDimitry Andric #include "llvm/MC/MCSymbol.h"
24eb11fae6SDimitry Andric #include "llvm/Support/raw_ostream.h"
25d8e91e46SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
26eb11fae6SDimitry Andric #include <algorithm>
27eb11fae6SDimitry Andric #include <cstddef>
28eb11fae6SDimitry Andric #include <cstdint>
29eb11fae6SDimitry Andric #include <limits>
30eb11fae6SDimitry Andric #include <vector>
31eb11fae6SDimitry Andric 
32eb11fae6SDimitry Andric using namespace llvm;
33eb11fae6SDimitry Andric 
computeBucketCount()34eb11fae6SDimitry Andric void AccelTableBase::computeBucketCount() {
35ac9a064cSDimitry Andric   SmallVector<uint32_t, 0> Uniques;
36eb11fae6SDimitry Andric   Uniques.reserve(Entries.size());
37eb11fae6SDimitry Andric   for (const auto &E : Entries)
38eb11fae6SDimitry Andric     Uniques.push_back(E.second.HashValue);
39ac9a064cSDimitry Andric   llvm::sort(Uniques);
40ac9a064cSDimitry Andric   UniqueHashCount = llvm::unique(Uniques) - Uniques.begin();
41ac9a064cSDimitry Andric   BucketCount = dwarf::getDebugNamesBucketCount(UniqueHashCount);
42eb11fae6SDimitry Andric }
43eb11fae6SDimitry Andric 
finalize(AsmPrinter * Asm,StringRef Prefix)44eb11fae6SDimitry Andric void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
45eb11fae6SDimitry Andric   // Create the individual hash data outputs.
46eb11fae6SDimitry Andric   for (auto &E : Entries) {
47eb11fae6SDimitry Andric     // Unique the entries.
48e6d15924SDimitry Andric     llvm::stable_sort(E.second.Values,
49eb11fae6SDimitry Andric                       [](const AccelTableData *A, const AccelTableData *B) {
50eb11fae6SDimitry Andric                         return *A < *B;
51eb11fae6SDimitry Andric                       });
52ac9a064cSDimitry Andric     E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end());
53eb11fae6SDimitry Andric   }
54eb11fae6SDimitry Andric 
55eb11fae6SDimitry Andric   // Figure out how many buckets we need, then compute the bucket contents and
56eb11fae6SDimitry Andric   // the final ordering. The hashes and offsets can be emitted by walking these
57eb11fae6SDimitry Andric   // data structures. We add temporary symbols to the data so they can be
58eb11fae6SDimitry Andric   // referenced when emitting the offsets.
59eb11fae6SDimitry Andric   computeBucketCount();
60eb11fae6SDimitry Andric 
61eb11fae6SDimitry Andric   // Compute bucket contents and final ordering.
62eb11fae6SDimitry Andric   Buckets.resize(BucketCount);
63eb11fae6SDimitry Andric   for (auto &E : Entries) {
64eb11fae6SDimitry Andric     uint32_t Bucket = E.second.HashValue % BucketCount;
65eb11fae6SDimitry Andric     Buckets[Bucket].push_back(&E.second);
66eb11fae6SDimitry Andric     E.second.Sym = Asm->createTempSymbol(Prefix);
67eb11fae6SDimitry Andric   }
68eb11fae6SDimitry Andric 
69eb11fae6SDimitry Andric   // Sort the contents of the buckets by hash value so that hash collisions end
70eb11fae6SDimitry Andric   // up together. Stable sort makes testing easier and doesn't cost much more.
71eb11fae6SDimitry Andric   for (auto &Bucket : Buckets)
72e6d15924SDimitry Andric     llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
73eb11fae6SDimitry Andric       return LHS->HashValue < RHS->HashValue;
74eb11fae6SDimitry Andric     });
75eb11fae6SDimitry Andric }
76eb11fae6SDimitry Andric 
77eb11fae6SDimitry Andric namespace {
78eb11fae6SDimitry Andric /// Base class for writing out Accelerator tables. It holds the common
79eb11fae6SDimitry Andric /// functionality for the two Accelerator table types.
80eb11fae6SDimitry Andric class AccelTableWriter {
81eb11fae6SDimitry Andric protected:
82eb11fae6SDimitry Andric   AsmPrinter *const Asm;          ///< Destination.
83eb11fae6SDimitry Andric   const AccelTableBase &Contents; ///< Data to emit.
84eb11fae6SDimitry Andric 
85eb11fae6SDimitry Andric   /// Controls whether to emit duplicate hash and offset table entries for names
86eb11fae6SDimitry Andric   /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
87eb11fae6SDimitry Andric   /// tables do.
88eb11fae6SDimitry Andric   const bool SkipIdenticalHashes;
89eb11fae6SDimitry Andric 
90eb11fae6SDimitry Andric   void emitHashes() const;
91eb11fae6SDimitry Andric 
92eb11fae6SDimitry Andric   /// Emit offsets to lists of entries with identical names. The offsets are
93eb11fae6SDimitry Andric   /// relative to the Base argument.
94eb11fae6SDimitry Andric   void emitOffsets(const MCSymbol *Base) const;
95eb11fae6SDimitry Andric 
96eb11fae6SDimitry Andric public:
AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,bool SkipIdenticalHashes)97eb11fae6SDimitry Andric   AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
98eb11fae6SDimitry Andric                    bool SkipIdenticalHashes)
99eb11fae6SDimitry Andric       : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
100eb11fae6SDimitry Andric   }
101eb11fae6SDimitry Andric };
102eb11fae6SDimitry Andric 
103eb11fae6SDimitry Andric class AppleAccelTableWriter : public AccelTableWriter {
104eb11fae6SDimitry Andric   using Atom = AppleAccelTableData::Atom;
105eb11fae6SDimitry Andric 
106eb11fae6SDimitry Andric   /// The fixed header of an Apple Accelerator Table.
107eb11fae6SDimitry Andric   struct Header {
108eb11fae6SDimitry Andric     uint32_t Magic = MagicHash;
109eb11fae6SDimitry Andric     uint16_t Version = 1;
110eb11fae6SDimitry Andric     uint16_t HashFunction = dwarf::DW_hash_function_djb;
111eb11fae6SDimitry Andric     uint32_t BucketCount;
112eb11fae6SDimitry Andric     uint32_t HashCount;
113eb11fae6SDimitry Andric     uint32_t HeaderDataLength;
114eb11fae6SDimitry Andric 
115eb11fae6SDimitry Andric     /// 'HASH' magic value to detect endianness.
116eb11fae6SDimitry Andric     static const uint32_t MagicHash = 0x48415348;
117eb11fae6SDimitry Andric 
Header__anon9fd034dd0311::AppleAccelTableWriter::Header118eb11fae6SDimitry Andric     Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
119eb11fae6SDimitry Andric         : BucketCount(BucketCount), HashCount(UniqueHashCount),
120eb11fae6SDimitry Andric           HeaderDataLength(DataLength) {}
121eb11fae6SDimitry Andric 
122eb11fae6SDimitry Andric     void emit(AsmPrinter *Asm) const;
123eb11fae6SDimitry Andric #ifndef NDEBUG
124eb11fae6SDimitry Andric     void print(raw_ostream &OS) const;
dump__anon9fd034dd0311::AppleAccelTableWriter::Header125eb11fae6SDimitry Andric     void dump() const { print(dbgs()); }
126eb11fae6SDimitry Andric #endif
127eb11fae6SDimitry Andric   };
128eb11fae6SDimitry Andric 
129eb11fae6SDimitry Andric   /// The HeaderData describes the structure of an Apple accelerator table
130eb11fae6SDimitry Andric   /// through a list of Atoms.
131eb11fae6SDimitry Andric   struct HeaderData {
132eb11fae6SDimitry Andric     /// In the case of data that is referenced via DW_FORM_ref_* the offset
133eb11fae6SDimitry Andric     /// base is used to describe the offset for all forms in the list of atoms.
134eb11fae6SDimitry Andric     uint32_t DieOffsetBase;
135eb11fae6SDimitry Andric 
136eb11fae6SDimitry Andric     const SmallVector<Atom, 4> Atoms;
137eb11fae6SDimitry Andric 
HeaderData__anon9fd034dd0311::AppleAccelTableWriter::HeaderData138eb11fae6SDimitry Andric     HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
139eb11fae6SDimitry Andric         : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
140eb11fae6SDimitry Andric 
141eb11fae6SDimitry Andric     void emit(AsmPrinter *Asm) const;
142eb11fae6SDimitry Andric #ifndef NDEBUG
143eb11fae6SDimitry Andric     void print(raw_ostream &OS) const;
dump__anon9fd034dd0311::AppleAccelTableWriter::HeaderData144eb11fae6SDimitry Andric     void dump() const { print(dbgs()); }
145eb11fae6SDimitry Andric #endif
146eb11fae6SDimitry Andric   };
147eb11fae6SDimitry Andric 
148eb11fae6SDimitry Andric   Header Header;
149eb11fae6SDimitry Andric   HeaderData HeaderData;
150eb11fae6SDimitry Andric   const MCSymbol *SecBegin;
151eb11fae6SDimitry Andric 
152eb11fae6SDimitry Andric   void emitBuckets() const;
153eb11fae6SDimitry Andric   void emitData() const;
154eb11fae6SDimitry Andric 
155eb11fae6SDimitry Andric public:
AppleAccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<Atom> Atoms,const MCSymbol * SecBegin)156eb11fae6SDimitry Andric   AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
157eb11fae6SDimitry Andric                         ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
158eb11fae6SDimitry Andric       : AccelTableWriter(Asm, Contents, true),
159eb11fae6SDimitry Andric         Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
160eb11fae6SDimitry Andric                8 + (Atoms.size() * 4)),
161eb11fae6SDimitry Andric         HeaderData(Atoms), SecBegin(SecBegin) {}
162eb11fae6SDimitry Andric 
163eb11fae6SDimitry Andric   void emit() const;
164eb11fae6SDimitry Andric 
165eb11fae6SDimitry Andric #ifndef NDEBUG
166eb11fae6SDimitry Andric   void print(raw_ostream &OS) const;
dump() const167eb11fae6SDimitry Andric   void dump() const { print(dbgs()); }
168eb11fae6SDimitry Andric #endif
169eb11fae6SDimitry Andric };
170eb11fae6SDimitry Andric 
171eb11fae6SDimitry Andric /// Class responsible for emitting a DWARF v5 Accelerator Table. The only
172eb11fae6SDimitry Andric /// public function is emit(), which performs the actual emission.
173eb11fae6SDimitry Andric ///
174aca2e42cSDimitry Andric /// A callback abstracts the logic to provide a CU index for a given entry.
175eb11fae6SDimitry Andric class Dwarf5AccelTableWriter : public AccelTableWriter {
176eb11fae6SDimitry Andric   struct Header {
177eb11fae6SDimitry Andric     uint16_t Version = 5;
178eb11fae6SDimitry Andric     uint16_t Padding = 0;
179eb11fae6SDimitry Andric     uint32_t CompUnitCount;
180eb11fae6SDimitry Andric     uint32_t LocalTypeUnitCount = 0;
181eb11fae6SDimitry Andric     uint32_t ForeignTypeUnitCount = 0;
1827fa27ce4SDimitry Andric     uint32_t BucketCount = 0;
1837fa27ce4SDimitry Andric     uint32_t NameCount = 0;
184eb11fae6SDimitry Andric     uint32_t AbbrevTableSize = 0;
185eb11fae6SDimitry Andric     uint32_t AugmentationStringSize = sizeof(AugmentationString);
186eb11fae6SDimitry Andric     char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
187eb11fae6SDimitry Andric 
Header__anon9fd034dd0311::Dwarf5AccelTableWriter::Header188b1c73532SDimitry Andric     Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
189b1c73532SDimitry Andric            uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
190b1c73532SDimitry Andric            uint32_t NameCount)
191b1c73532SDimitry Andric         : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
192b1c73532SDimitry Andric           ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
193eb11fae6SDimitry Andric           NameCount(NameCount) {}
194eb11fae6SDimitry Andric 
195344a3780SDimitry Andric     void emit(Dwarf5AccelTableWriter &Ctx);
196eb11fae6SDimitry Andric   };
197eb11fae6SDimitry Andric 
198eb11fae6SDimitry Andric   Header Header;
199ac9a064cSDimitry Andric   /// FoldingSet that uniques the abbreviations.
200ac9a064cSDimitry Andric   FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
201ac9a064cSDimitry Andric   /// Vector containing DebugNames abbreviations for iteration in order.
202ac9a064cSDimitry Andric   SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
203ac9a064cSDimitry Andric   /// The bump allocator to use when creating DIEAbbrev objects in the uniqued
204ac9a064cSDimitry Andric   /// storage container.
205ac9a064cSDimitry Andric   BumpPtrAllocator Alloc;
206b1c73532SDimitry Andric   ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
207b1c73532SDimitry Andric   ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
208b1c73532SDimitry Andric   llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
209aca2e42cSDimitry Andric       const DWARF5AccelTableData &)>
210b1c73532SDimitry Andric       getIndexForEntry;
211344a3780SDimitry Andric   MCSymbol *ContributionEnd = nullptr;
212eb11fae6SDimitry Andric   MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
213eb11fae6SDimitry Andric   MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
214eb11fae6SDimitry Andric   MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
215b1c73532SDimitry Andric   // Indicates if this module is built with Split Dwarf enabled.
216b1c73532SDimitry Andric   bool IsSplitDwarf = false;
2174df029ccSDimitry Andric   /// Stores the DIE offsets which are indexed by this table.
2184df029ccSDimitry Andric   DenseSet<OffsetAndUnitID> IndexedOffsets;
219eb11fae6SDimitry Andric 
220b1c73532SDimitry Andric   void populateAbbrevsMap();
221eb11fae6SDimitry Andric 
222eb11fae6SDimitry Andric   void emitCUList() const;
223b1c73532SDimitry Andric   void emitTUList() const;
224eb11fae6SDimitry Andric   void emitBuckets() const;
225eb11fae6SDimitry Andric   void emitStringOffsets() const;
226eb11fae6SDimitry Andric   void emitAbbrevs() const;
2274df029ccSDimitry Andric   void emitEntry(
2284df029ccSDimitry Andric       const DWARF5AccelTableData &Entry,
2294df029ccSDimitry Andric       const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
230ac9a064cSDimitry Andric       DenseSet<MCSymbol *> &EmittedAccelEntrySymbols);
2314df029ccSDimitry Andric   void emitData();
232eb11fae6SDimitry Andric 
233eb11fae6SDimitry Andric public:
234eb11fae6SDimitry Andric   Dwarf5AccelTableWriter(
235eb11fae6SDimitry Andric       AsmPrinter *Asm, const AccelTableBase &Contents,
236b1c73532SDimitry Andric       ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
237b1c73532SDimitry Andric       ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
238aca2e42cSDimitry Andric       llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
239aca2e42cSDimitry Andric           const DWARF5AccelTableData &)>
240b1c73532SDimitry Andric           getIndexForEntry,
241b1c73532SDimitry Andric       bool IsSplitDwarf);
~Dwarf5AccelTableWriter()242ac9a064cSDimitry Andric   ~Dwarf5AccelTableWriter() {
243ac9a064cSDimitry Andric     for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
244ac9a064cSDimitry Andric       Abbrev->~DebugNamesAbbrev();
245ac9a064cSDimitry Andric   }
246344a3780SDimitry Andric   void emit();
247eb11fae6SDimitry Andric };
248eb11fae6SDimitry Andric } // namespace
249eb11fae6SDimitry Andric 
emitHashes() const250eb11fae6SDimitry Andric void AccelTableWriter::emitHashes() const {
251eb11fae6SDimitry Andric   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
252eb11fae6SDimitry Andric   unsigned BucketIdx = 0;
2534b4fe385SDimitry Andric   for (const auto &Bucket : Contents.getBuckets()) {
2544b4fe385SDimitry Andric     for (const auto &Hash : Bucket) {
255eb11fae6SDimitry Andric       uint32_t HashValue = Hash->HashValue;
256eb11fae6SDimitry Andric       if (SkipIdenticalHashes && PrevHash == HashValue)
257eb11fae6SDimitry Andric         continue;
258eb11fae6SDimitry Andric       Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
259eb11fae6SDimitry Andric       Asm->emitInt32(HashValue);
260eb11fae6SDimitry Andric       PrevHash = HashValue;
261eb11fae6SDimitry Andric     }
262eb11fae6SDimitry Andric     BucketIdx++;
263eb11fae6SDimitry Andric   }
264eb11fae6SDimitry Andric }
265eb11fae6SDimitry Andric 
emitOffsets(const MCSymbol * Base) const266eb11fae6SDimitry Andric void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
267eb11fae6SDimitry Andric   const auto &Buckets = Contents.getBuckets();
268eb11fae6SDimitry Andric   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
269eb11fae6SDimitry Andric   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
270eb11fae6SDimitry Andric     for (auto *Hash : Buckets[i]) {
271eb11fae6SDimitry Andric       uint32_t HashValue = Hash->HashValue;
272eb11fae6SDimitry Andric       if (SkipIdenticalHashes && PrevHash == HashValue)
273eb11fae6SDimitry Andric         continue;
274eb11fae6SDimitry Andric       PrevHash = HashValue;
275eb11fae6SDimitry Andric       Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
276b60736ecSDimitry Andric       Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
277eb11fae6SDimitry Andric     }
278eb11fae6SDimitry Andric   }
279eb11fae6SDimitry Andric }
280eb11fae6SDimitry Andric 
emit(AsmPrinter * Asm) const281eb11fae6SDimitry Andric void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
282eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header Magic");
283eb11fae6SDimitry Andric   Asm->emitInt32(Magic);
284eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header Version");
285eb11fae6SDimitry Andric   Asm->emitInt16(Version);
286eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header Hash Function");
287eb11fae6SDimitry Andric   Asm->emitInt16(HashFunction);
288eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header Bucket Count");
289eb11fae6SDimitry Andric   Asm->emitInt32(BucketCount);
290eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header Hash Count");
291eb11fae6SDimitry Andric   Asm->emitInt32(HashCount);
292eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header Data Length");
293eb11fae6SDimitry Andric   Asm->emitInt32(HeaderDataLength);
294eb11fae6SDimitry Andric }
295eb11fae6SDimitry Andric 
emit(AsmPrinter * Asm) const296eb11fae6SDimitry Andric void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
297eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
298eb11fae6SDimitry Andric   Asm->emitInt32(DieOffsetBase);
299eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("HeaderData Atom Count");
300eb11fae6SDimitry Andric   Asm->emitInt32(Atoms.size());
301eb11fae6SDimitry Andric 
302eb11fae6SDimitry Andric   for (const Atom &A : Atoms) {
303eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
304eb11fae6SDimitry Andric     Asm->emitInt16(A.Type);
305eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
306eb11fae6SDimitry Andric     Asm->emitInt16(A.Form);
307eb11fae6SDimitry Andric   }
308eb11fae6SDimitry Andric }
309eb11fae6SDimitry Andric 
emitBuckets() const310eb11fae6SDimitry Andric void AppleAccelTableWriter::emitBuckets() const {
311eb11fae6SDimitry Andric   const auto &Buckets = Contents.getBuckets();
312eb11fae6SDimitry Andric   unsigned index = 0;
313eb11fae6SDimitry Andric   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
314eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment("Bucket " + Twine(i));
315eb11fae6SDimitry Andric     if (!Buckets[i].empty())
316eb11fae6SDimitry Andric       Asm->emitInt32(index);
317eb11fae6SDimitry Andric     else
318eb11fae6SDimitry Andric       Asm->emitInt32(std::numeric_limits<uint32_t>::max());
319eb11fae6SDimitry Andric     // Buckets point in the list of hashes, not to the data. Do not increment
320eb11fae6SDimitry Andric     // the index multiple times in case of hash collisions.
321eb11fae6SDimitry Andric     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
322eb11fae6SDimitry Andric     for (auto *HD : Buckets[i]) {
323eb11fae6SDimitry Andric       uint32_t HashValue = HD->HashValue;
324eb11fae6SDimitry Andric       if (PrevHash != HashValue)
325eb11fae6SDimitry Andric         ++index;
326eb11fae6SDimitry Andric       PrevHash = HashValue;
327eb11fae6SDimitry Andric     }
328eb11fae6SDimitry Andric   }
329eb11fae6SDimitry Andric }
330eb11fae6SDimitry Andric 
emitData() const331eb11fae6SDimitry Andric void AppleAccelTableWriter::emitData() const {
332eb11fae6SDimitry Andric   const auto &Buckets = Contents.getBuckets();
333344a3780SDimitry Andric   for (const AccelTableBase::HashList &Bucket : Buckets) {
334eb11fae6SDimitry Andric     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
3354b4fe385SDimitry Andric     for (const auto &Hash : Bucket) {
336eb11fae6SDimitry Andric       // Terminate the previous entry if there is no hash collision with the
337eb11fae6SDimitry Andric       // current one.
338eb11fae6SDimitry Andric       if (PrevHash != std::numeric_limits<uint64_t>::max() &&
339eb11fae6SDimitry Andric           PrevHash != Hash->HashValue)
340eb11fae6SDimitry Andric         Asm->emitInt32(0);
341eb11fae6SDimitry Andric       // Remember to emit the label for our offset.
342cfca06d7SDimitry Andric       Asm->OutStreamer->emitLabel(Hash->Sym);
343eb11fae6SDimitry Andric       Asm->OutStreamer->AddComment(Hash->Name.getString());
344eb11fae6SDimitry Andric       Asm->emitDwarfStringOffset(Hash->Name);
345eb11fae6SDimitry Andric       Asm->OutStreamer->AddComment("Num DIEs");
346eb11fae6SDimitry Andric       Asm->emitInt32(Hash->Values.size());
347aca2e42cSDimitry Andric       for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
348aca2e42cSDimitry Andric         V->emit(Asm);
349eb11fae6SDimitry Andric       PrevHash = Hash->HashValue;
350eb11fae6SDimitry Andric     }
351eb11fae6SDimitry Andric     // Emit the final end marker for the bucket.
352344a3780SDimitry Andric     if (!Bucket.empty())
353eb11fae6SDimitry Andric       Asm->emitInt32(0);
354eb11fae6SDimitry Andric   }
355eb11fae6SDimitry Andric }
356eb11fae6SDimitry Andric 
emit() const357eb11fae6SDimitry Andric void AppleAccelTableWriter::emit() const {
358eb11fae6SDimitry Andric   Header.emit(Asm);
359eb11fae6SDimitry Andric   HeaderData.emit(Asm);
360eb11fae6SDimitry Andric   emitBuckets();
361eb11fae6SDimitry Andric   emitHashes();
362eb11fae6SDimitry Andric   emitOffsets(SecBegin);
363eb11fae6SDimitry Andric   emitData();
364eb11fae6SDimitry Andric }
365eb11fae6SDimitry Andric 
DWARF5AccelTableData(const DIE & Die,const uint32_t UnitID,const bool IsTU)366b1c73532SDimitry Andric DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
367b1c73532SDimitry Andric                                            const uint32_t UnitID,
368b1c73532SDimitry Andric                                            const bool IsTU)
369ac9a064cSDimitry Andric     : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
370ac9a064cSDimitry Andric       UnitID(UnitID) {}
371b1c73532SDimitry Andric 
emit(Dwarf5AccelTableWriter & Ctx)372aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
373eb11fae6SDimitry Andric   assert(CompUnitCount > 0 && "Index must have at least one CU.");
374eb11fae6SDimitry Andric 
375eb11fae6SDimitry Andric   AsmPrinter *Asm = Ctx.Asm;
376344a3780SDimitry Andric   Ctx.ContributionEnd =
377344a3780SDimitry Andric       Asm->emitDwarfUnitLength("names", "Header: unit length");
378eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: version");
379eb11fae6SDimitry Andric   Asm->emitInt16(Version);
380eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: padding");
381eb11fae6SDimitry Andric   Asm->emitInt16(Padding);
382eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: compilation unit count");
383eb11fae6SDimitry Andric   Asm->emitInt32(CompUnitCount);
384eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: local type unit count");
385eb11fae6SDimitry Andric   Asm->emitInt32(LocalTypeUnitCount);
386eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: foreign type unit count");
387eb11fae6SDimitry Andric   Asm->emitInt32(ForeignTypeUnitCount);
388eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: bucket count");
389eb11fae6SDimitry Andric   Asm->emitInt32(BucketCount);
390eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: name count");
391eb11fae6SDimitry Andric   Asm->emitInt32(NameCount);
392eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: abbreviation table size");
393cfca06d7SDimitry Andric   Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
394eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: augmentation string size");
395eb11fae6SDimitry Andric   assert(AugmentationStringSize % 4 == 0);
396eb11fae6SDimitry Andric   Asm->emitInt32(AugmentationStringSize);
397eb11fae6SDimitry Andric   Asm->OutStreamer->AddComment("Header: augmentation string");
398cfca06d7SDimitry Andric   Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
399eb11fae6SDimitry Andric }
400eb11fae6SDimitry Andric 
4014df029ccSDimitry Andric std::optional<uint64_t>
getDefiningParentDieOffset(const DIE & Die)4024df029ccSDimitry Andric DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
4034df029ccSDimitry Andric   if (auto *Parent = Die.getParent();
4044df029ccSDimitry Andric       Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
4054df029ccSDimitry Andric     return Parent->getOffset();
4064df029ccSDimitry Andric   return {};
4074df029ccSDimitry Andric }
4084df029ccSDimitry Andric 
4094df029ccSDimitry Andric static std::optional<dwarf::Form>
getFormForIdxParent(const DenseSet<OffsetAndUnitID> & IndexedOffsets,std::optional<OffsetAndUnitID> ParentOffset)4104df029ccSDimitry Andric getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
4114df029ccSDimitry Andric                     std::optional<OffsetAndUnitID> ParentOffset) {
4124df029ccSDimitry Andric   // No parent information
4134df029ccSDimitry Andric   if (!ParentOffset)
4144df029ccSDimitry Andric     return std::nullopt;
4154df029ccSDimitry Andric   // Parent is indexed by this table.
4164df029ccSDimitry Andric   if (IndexedOffsets.contains(*ParentOffset))
4174df029ccSDimitry Andric     return dwarf::Form::DW_FORM_ref4;
4184df029ccSDimitry Andric   // Parent is not indexed by this table.
4194df029ccSDimitry Andric   return dwarf::Form::DW_FORM_flag_present;
4204df029ccSDimitry Andric }
4214df029ccSDimitry Andric 
Profile(FoldingSetNodeID & ID) const422ac9a064cSDimitry Andric void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const {
423ac9a064cSDimitry Andric   ID.AddInteger(DieTag);
424ac9a064cSDimitry Andric   for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
425ac9a064cSDimitry Andric     ID.AddInteger(Enc.Index);
426ac9a064cSDimitry Andric     ID.AddInteger(Enc.Form);
427ac9a064cSDimitry Andric   }
428ac9a064cSDimitry Andric }
429ac9a064cSDimitry Andric 
populateAbbrevsMap()430aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::populateAbbrevsMap() {
431eb11fae6SDimitry Andric   for (auto &Bucket : Contents.getBuckets()) {
432eb11fae6SDimitry Andric     for (auto *Hash : Bucket) {
433aca2e42cSDimitry Andric       for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
434b1c73532SDimitry Andric         std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
435aca2e42cSDimitry Andric             getIndexForEntry(*Value);
4364df029ccSDimitry Andric         std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
4374df029ccSDimitry Andric             IndexedOffsets, Value->getParentDieOffsetAndUnitID());
438ac9a064cSDimitry Andric         DebugNamesAbbrev Abbrev(Value->getDieTag());
439b1c73532SDimitry Andric         if (EntryRet)
440ac9a064cSDimitry Andric           Abbrev.addAttribute(EntryRet->Encoding);
441ac9a064cSDimitry Andric         Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
4424df029ccSDimitry Andric         if (MaybeParentForm)
443ac9a064cSDimitry Andric           Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
444ac9a064cSDimitry Andric         FoldingSetNodeID ID;
445ac9a064cSDimitry Andric         Abbrev.Profile(ID);
446ac9a064cSDimitry Andric         void *InsertPos;
447ac9a064cSDimitry Andric         if (DebugNamesAbbrev *Existing =
448ac9a064cSDimitry Andric                 AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
449ac9a064cSDimitry Andric           Value->setAbbrevNumber(Existing->getNumber());
450ac9a064cSDimitry Andric           continue;
451b1c73532SDimitry Andric         }
452ac9a064cSDimitry Andric         DebugNamesAbbrev *NewAbbrev =
453ac9a064cSDimitry Andric             new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
454ac9a064cSDimitry Andric         AbbreviationsVector.push_back(NewAbbrev);
455ac9a064cSDimitry Andric         NewAbbrev->setNumber(AbbreviationsVector.size());
456ac9a064cSDimitry Andric         AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);
457ac9a064cSDimitry Andric         Value->setAbbrevNumber(NewAbbrev->getNumber());
458b1c73532SDimitry Andric       }
459b1c73532SDimitry Andric     }
460b1c73532SDimitry Andric   }
461eb11fae6SDimitry Andric }
462eb11fae6SDimitry Andric 
emitCUList() const463aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitCUList() const {
464eb11fae6SDimitry Andric   for (const auto &CU : enumerate(CompUnits)) {
465eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
466b1c73532SDimitry Andric     if (std::holds_alternative<MCSymbol *>(CU.value()))
467b1c73532SDimitry Andric       Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
468b1c73532SDimitry Andric     else
469b1c73532SDimitry Andric       Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
470b1c73532SDimitry Andric   }
471b1c73532SDimitry Andric }
472b1c73532SDimitry Andric 
emitTUList() const473aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitTUList() const {
474b1c73532SDimitry Andric   for (const auto &TU : enumerate(TypeUnits)) {
475b1c73532SDimitry Andric     Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
476b1c73532SDimitry Andric     if (std::holds_alternative<MCSymbol *>(TU.value()))
477b1c73532SDimitry Andric       Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
478b1c73532SDimitry Andric     else if (IsSplitDwarf)
479b1c73532SDimitry Andric       Asm->emitInt64(std::get<uint64_t>(TU.value()));
480b1c73532SDimitry Andric     else
481b1c73532SDimitry Andric       Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
482eb11fae6SDimitry Andric   }
483eb11fae6SDimitry Andric }
484eb11fae6SDimitry Andric 
emitBuckets() const485aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitBuckets() const {
486eb11fae6SDimitry Andric   uint32_t Index = 1;
487eb11fae6SDimitry Andric   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
488eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
489eb11fae6SDimitry Andric     Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
490eb11fae6SDimitry Andric     Index += Bucket.value().size();
491eb11fae6SDimitry Andric   }
492eb11fae6SDimitry Andric }
493eb11fae6SDimitry Andric 
emitStringOffsets() const494aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitStringOffsets() const {
495eb11fae6SDimitry Andric   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
496eb11fae6SDimitry Andric     for (auto *Hash : Bucket.value()) {
497eb11fae6SDimitry Andric       DwarfStringPoolEntryRef String = Hash->Name;
498eb11fae6SDimitry Andric       Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
499eb11fae6SDimitry Andric                                    ": " + String.getString());
500eb11fae6SDimitry Andric       Asm->emitDwarfStringOffset(String);
501eb11fae6SDimitry Andric     }
502eb11fae6SDimitry Andric   }
503eb11fae6SDimitry Andric }
504eb11fae6SDimitry Andric 
emitAbbrevs() const505aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitAbbrevs() const {
506cfca06d7SDimitry Andric   Asm->OutStreamer->emitLabel(AbbrevStart);
507ac9a064cSDimitry Andric   for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
508eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment("Abbrev code");
509ac9a064cSDimitry Andric     Asm->emitULEB128(Abbrev->getNumber());
510ac9a064cSDimitry Andric     Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
511ac9a064cSDimitry Andric     Asm->emitULEB128(Abbrev->getDieTag());
512ac9a064cSDimitry Andric     for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
513ac9a064cSDimitry Andric          Abbrev->getAttributes()) {
514cfca06d7SDimitry Andric       Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
515cfca06d7SDimitry Andric       Asm->emitULEB128(AttrEnc.Form,
516eb11fae6SDimitry Andric                        dwarf::FormEncodingString(AttrEnc.Form).data());
517eb11fae6SDimitry Andric     }
518cfca06d7SDimitry Andric     Asm->emitULEB128(0, "End of abbrev");
519cfca06d7SDimitry Andric     Asm->emitULEB128(0, "End of abbrev");
520eb11fae6SDimitry Andric   }
521cfca06d7SDimitry Andric   Asm->emitULEB128(0, "End of abbrev list");
522cfca06d7SDimitry Andric   Asm->OutStreamer->emitLabel(AbbrevEnd);
523eb11fae6SDimitry Andric }
524eb11fae6SDimitry Andric 
emitEntry(const DWARF5AccelTableData & Entry,const DenseMap<OffsetAndUnitID,MCSymbol * > & DIEOffsetToAccelEntryLabel,DenseSet<MCSymbol * > & EmittedAccelEntrySymbols)525aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitEntry(
5264df029ccSDimitry Andric     const DWARF5AccelTableData &Entry,
5274df029ccSDimitry Andric     const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
528ac9a064cSDimitry Andric     DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) {
529ac9a064cSDimitry Andric   unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
530ac9a064cSDimitry Andric   assert(AbbrevIndex < AbbreviationsVector.size() &&
531ac9a064cSDimitry Andric          "Entry abbrev index is outside of abbreviations vector range.");
532ac9a064cSDimitry Andric   DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
533b1c73532SDimitry Andric   std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
534b1c73532SDimitry Andric       getIndexForEntry(Entry);
5354df029ccSDimitry Andric   std::optional<OffsetAndUnitID> MaybeParentOffset =
5364df029ccSDimitry Andric       Entry.getParentDieOffsetAndUnitID();
5374df029ccSDimitry Andric   auto EntrySymbolIt =
5384df029ccSDimitry Andric       DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
5394df029ccSDimitry Andric   assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
5404df029ccSDimitry Andric   MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
5414df029ccSDimitry Andric 
5424df029ccSDimitry Andric   // Emit the label for this Entry, so that IDX_parents may refer to it.
5434df029ccSDimitry Andric   // Note: a DIE may have multiple accelerator Entries; this check avoids
5444df029ccSDimitry Andric   // creating/emitting multiple labels for the same DIE.
5454df029ccSDimitry Andric   if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
5464df029ccSDimitry Andric     Asm->OutStreamer->emitLabel(EntrySymbol);
5474df029ccSDimitry Andric 
548ac9a064cSDimitry Andric   Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
549b1c73532SDimitry Andric 
550ac9a064cSDimitry Andric   for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
551ac9a064cSDimitry Andric        Abbrev->getAttributes()) {
552eb11fae6SDimitry Andric     Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
553eb11fae6SDimitry Andric     switch (AttrEnc.Index) {
554b1c73532SDimitry Andric     case dwarf::DW_IDX_compile_unit:
555b1c73532SDimitry Andric     case dwarf::DW_IDX_type_unit: {
556b1c73532SDimitry Andric       DIEInteger ID(EntryRet->Index);
557cfca06d7SDimitry Andric       ID.emitValue(Asm, AttrEnc.Form);
558eb11fae6SDimitry Andric       break;
559eb11fae6SDimitry Andric     }
560eb11fae6SDimitry Andric     case dwarf::DW_IDX_die_offset:
561eb11fae6SDimitry Andric       assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
562eb11fae6SDimitry Andric       Asm->emitInt32(Entry.getDieOffset());
563eb11fae6SDimitry Andric       break;
5644df029ccSDimitry Andric     case dwarf::DW_IDX_parent: {
5654df029ccSDimitry Andric       if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
5664df029ccSDimitry Andric         break;
5674df029ccSDimitry Andric       auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
5684df029ccSDimitry Andric       assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
5694df029ccSDimitry Andric       Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
5704df029ccSDimitry Andric       break;
5714df029ccSDimitry Andric     }
572eb11fae6SDimitry Andric     default:
573eb11fae6SDimitry Andric       llvm_unreachable("Unexpected index attribute!");
574eb11fae6SDimitry Andric     }
575eb11fae6SDimitry Andric   }
576eb11fae6SDimitry Andric }
577eb11fae6SDimitry Andric 
emitData()5784df029ccSDimitry Andric void Dwarf5AccelTableWriter::emitData() {
5794df029ccSDimitry Andric   DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
5804df029ccSDimitry Andric 
5814df029ccSDimitry Andric   for (OffsetAndUnitID Offset : IndexedOffsets)
5824df029ccSDimitry Andric     DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
5834df029ccSDimitry Andric 
584cfca06d7SDimitry Andric   Asm->OutStreamer->emitLabel(EntryPool);
5854df029ccSDimitry Andric   DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
586eb11fae6SDimitry Andric   for (auto &Bucket : Contents.getBuckets()) {
587eb11fae6SDimitry Andric     for (auto *Hash : Bucket) {
588eb11fae6SDimitry Andric       // Remember to emit the label for our offset.
589cfca06d7SDimitry Andric       Asm->OutStreamer->emitLabel(Hash->Sym);
5904df029ccSDimitry Andric       for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
5914df029ccSDimitry Andric         emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
592eb11fae6SDimitry Andric       Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
593b60736ecSDimitry Andric       Asm->emitInt8(0);
594eb11fae6SDimitry Andric     }
595eb11fae6SDimitry Andric   }
596eb11fae6SDimitry Andric }
597eb11fae6SDimitry 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)598aca2e42cSDimitry Andric Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
599eb11fae6SDimitry Andric     AsmPrinter *Asm, const AccelTableBase &Contents,
600b1c73532SDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
601b1c73532SDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
602aca2e42cSDimitry Andric     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
603aca2e42cSDimitry Andric         const DWARF5AccelTableData &)>
604b1c73532SDimitry Andric         getIndexForEntry,
605b1c73532SDimitry Andric     bool IsSplitDwarf)
606eb11fae6SDimitry Andric     : AccelTableWriter(Asm, Contents, false),
607b1c73532SDimitry Andric       Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
608b1c73532SDimitry Andric              IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
609eb11fae6SDimitry Andric              Contents.getUniqueNameCount()),
610b1c73532SDimitry Andric       CompUnits(CompUnits), TypeUnits(TypeUnits),
611b1c73532SDimitry Andric       getIndexForEntry(std::move(getIndexForEntry)),
612b1c73532SDimitry Andric       IsSplitDwarf(IsSplitDwarf) {
6134df029ccSDimitry Andric 
6144df029ccSDimitry Andric   for (auto &Bucket : Contents.getBuckets())
6154df029ccSDimitry Andric     for (auto *Hash : Bucket)
6164df029ccSDimitry Andric       for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
6174df029ccSDimitry Andric         IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
6184df029ccSDimitry Andric 
619b1c73532SDimitry Andric   populateAbbrevsMap();
620eb11fae6SDimitry Andric }
621eb11fae6SDimitry Andric 
emit()622aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emit() {
623eb11fae6SDimitry Andric   Header.emit(*this);
624eb11fae6SDimitry Andric   emitCUList();
625b1c73532SDimitry Andric   emitTUList();
626eb11fae6SDimitry Andric   emitBuckets();
627eb11fae6SDimitry Andric   emitHashes();
628eb11fae6SDimitry Andric   emitStringOffsets();
629eb11fae6SDimitry Andric   emitOffsets(EntryPool);
630eb11fae6SDimitry Andric   emitAbbrevs();
631eb11fae6SDimitry Andric   emitData();
632e3b55780SDimitry Andric   Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
633cfca06d7SDimitry Andric   Asm->OutStreamer->emitLabel(ContributionEnd);
634eb11fae6SDimitry Andric }
635eb11fae6SDimitry Andric 
emitAppleAccelTableImpl(AsmPrinter * Asm,AccelTableBase & Contents,StringRef Prefix,const MCSymbol * SecBegin,ArrayRef<AppleAccelTableData::Atom> Atoms)636eb11fae6SDimitry Andric void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
637eb11fae6SDimitry Andric                                    StringRef Prefix, const MCSymbol *SecBegin,
638eb11fae6SDimitry Andric                                    ArrayRef<AppleAccelTableData::Atom> Atoms) {
639eb11fae6SDimitry Andric   Contents.finalize(Asm, Prefix);
640eb11fae6SDimitry Andric   AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
641eb11fae6SDimitry Andric }
642eb11fae6SDimitry Andric 
emitDWARF5AccelTable(AsmPrinter * Asm,DWARF5AccelTable & Contents,const DwarfDebug & DD,ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs)643eb11fae6SDimitry Andric void llvm::emitDWARF5AccelTable(
644b1c73532SDimitry Andric     AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
645b1c73532SDimitry Andric     ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
646b1c73532SDimitry Andric   TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
647b1c73532SDimitry Andric   std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
648b1c73532SDimitry Andric   std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
649d8e91e46SDimitry Andric   SmallVector<unsigned, 1> CUIndex(CUs.size());
650b1c73532SDimitry Andric   DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
651b1c73532SDimitry Andric   int CUCount = 0;
652b1c73532SDimitry Andric   int TUCount = 0;
653eb11fae6SDimitry Andric   for (const auto &CU : enumerate(CUs)) {
6547fa27ce4SDimitry Andric     switch (CU.value()->getCUNode()->getNameTableKind()) {
6557fa27ce4SDimitry Andric     case DICompileUnit::DebugNameTableKind::Default:
6567fa27ce4SDimitry Andric     case DICompileUnit::DebugNameTableKind::Apple:
6577fa27ce4SDimitry Andric       break;
6587fa27ce4SDimitry Andric     default:
659d8e91e46SDimitry Andric       continue;
6607fa27ce4SDimitry Andric     }
661b1c73532SDimitry Andric     CUIndex[CU.index()] = CUCount++;
662eb11fae6SDimitry Andric     assert(CU.index() == CU.value()->getUniqueID());
663eb11fae6SDimitry Andric     const DwarfCompileUnit *MainCU =
664eb11fae6SDimitry Andric         DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
665eb11fae6SDimitry Andric     CompUnits.push_back(MainCU->getLabelBegin());
666eb11fae6SDimitry Andric   }
667eb11fae6SDimitry Andric 
668b1c73532SDimitry Andric   for (const auto &TU : TUSymbols) {
669b1c73532SDimitry Andric     TUIndex[TU.UniqueID] = TUCount++;
670b1c73532SDimitry Andric     if (DD.useSplitDwarf())
671b1c73532SDimitry Andric       TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
672b1c73532SDimitry Andric     else
673b1c73532SDimitry Andric       TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
674b1c73532SDimitry Andric   }
675b1c73532SDimitry Andric 
676d8e91e46SDimitry Andric   if (CompUnits.empty())
677d8e91e46SDimitry Andric     return;
678d8e91e46SDimitry Andric 
679145449b1SDimitry Andric   Asm->OutStreamer->switchSection(
680d8e91e46SDimitry Andric       Asm->getObjFileLowering().getDwarfDebugNamesSection());
681d8e91e46SDimitry Andric 
682eb11fae6SDimitry Andric   Contents.finalize(Asm, "names");
683b1c73532SDimitry Andric   dwarf::Form CUIndexForm =
684b1c73532SDimitry Andric       DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
685b1c73532SDimitry Andric   dwarf::Form TUIndexForm =
686b1c73532SDimitry Andric       DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
687aca2e42cSDimitry Andric   Dwarf5AccelTableWriter(
688b1c73532SDimitry Andric       Asm, Contents, CompUnits, TypeUnits,
689b1c73532SDimitry Andric       [&](const DWARF5AccelTableData &Entry)
690b1c73532SDimitry Andric           -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
691b1c73532SDimitry Andric         if (Entry.isTU())
692b1c73532SDimitry Andric           return {{TUIndex[Entry.getUnitID()],
693b1c73532SDimitry Andric                    {dwarf::DW_IDX_type_unit, TUIndexForm}}};
694b1c73532SDimitry Andric         if (CUIndex.size() > 1)
695b1c73532SDimitry Andric           return {{CUIndex[Entry.getUnitID()],
696b1c73532SDimitry Andric                    {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
697b1c73532SDimitry Andric         return std::nullopt;
698b1c73532SDimitry Andric       },
699b1c73532SDimitry Andric       DD.useSplitDwarf())
700eb11fae6SDimitry Andric       .emit();
701eb11fae6SDimitry Andric }
702eb11fae6SDimitry Andric 
addTypeUnitSymbol(DwarfTypeUnit & U)703b1c73532SDimitry Andric void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
704b1c73532SDimitry Andric   TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
705b1c73532SDimitry Andric }
706b1c73532SDimitry Andric 
addTypeUnitSignature(DwarfTypeUnit & U)707b1c73532SDimitry Andric void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
708b1c73532SDimitry Andric   TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
709b1c73532SDimitry Andric }
710b1c73532SDimitry Andric 
emitDWARF5AccelTable(AsmPrinter * Asm,DWARF5AccelTable & Contents,ArrayRef<std::variant<MCSymbol *,uint64_t>> CUs,llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding> (const DWARF5AccelTableData &)> getIndexForEntry)711eb11fae6SDimitry Andric void llvm::emitDWARF5AccelTable(
712b1c73532SDimitry Andric     AsmPrinter *Asm, DWARF5AccelTable &Contents,
713b1c73532SDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
714b1c73532SDimitry Andric     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
715b1c73532SDimitry Andric         const DWARF5AccelTableData &)>
716b1c73532SDimitry Andric         getIndexForEntry) {
717b1c73532SDimitry Andric   std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
718eb11fae6SDimitry Andric   Contents.finalize(Asm, "names");
719aca2e42cSDimitry Andric   Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
720eb11fae6SDimitry Andric       .emit();
721eb11fae6SDimitry Andric }
722eb11fae6SDimitry Andric 
emit(AsmPrinter * Asm) const723eb11fae6SDimitry Andric void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
724b60736ecSDimitry Andric   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
725b60736ecSDimitry Andric          "The section offset exceeds the limit.");
726eb11fae6SDimitry Andric   Asm->emitInt32(Die.getDebugSectionOffset());
727eb11fae6SDimitry Andric }
728eb11fae6SDimitry Andric 
emit(AsmPrinter * Asm) const729eb11fae6SDimitry Andric void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
730b60736ecSDimitry Andric   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
731b60736ecSDimitry Andric          "The section offset exceeds the limit.");
732eb11fae6SDimitry Andric   Asm->emitInt32(Die.getDebugSectionOffset());
733eb11fae6SDimitry Andric   Asm->emitInt16(Die.getTag());
734eb11fae6SDimitry Andric   Asm->emitInt8(0);
735eb11fae6SDimitry Andric }
736eb11fae6SDimitry Andric 
emit(AsmPrinter * Asm) const737eb11fae6SDimitry Andric void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
738eb11fae6SDimitry Andric   Asm->emitInt32(Offset);
739eb11fae6SDimitry Andric }
740eb11fae6SDimitry Andric 
emit(AsmPrinter * Asm) const741eb11fae6SDimitry Andric void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
742eb11fae6SDimitry Andric   Asm->emitInt32(Offset);
743eb11fae6SDimitry Andric   Asm->emitInt16(Tag);
744eb11fae6SDimitry Andric   Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
745eb11fae6SDimitry Andric                                           : 0);
746eb11fae6SDimitry Andric   Asm->emitInt32(QualifiedNameHash);
747eb11fae6SDimitry Andric }
748eb11fae6SDimitry Andric 
749eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
750eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
751eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
752eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
753eb11fae6SDimitry Andric 
754eb11fae6SDimitry Andric #ifndef NDEBUG
print(raw_ostream & OS) const755eb11fae6SDimitry Andric void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
756eb11fae6SDimitry Andric   OS << "Magic: " << format("0x%x", Magic) << "\n"
757eb11fae6SDimitry Andric      << "Version: " << Version << "\n"
758eb11fae6SDimitry Andric      << "Hash Function: " << HashFunction << "\n"
759eb11fae6SDimitry Andric      << "Bucket Count: " << BucketCount << "\n"
760eb11fae6SDimitry Andric      << "Header Data Length: " << HeaderDataLength << "\n";
761eb11fae6SDimitry Andric }
762eb11fae6SDimitry Andric 
print(raw_ostream & OS) const763eb11fae6SDimitry Andric void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
764eb11fae6SDimitry Andric   OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
765eb11fae6SDimitry Andric      << "Form: " << dwarf::FormEncodingString(Form) << "\n";
766eb11fae6SDimitry Andric }
767eb11fae6SDimitry Andric 
print(raw_ostream & OS) const768eb11fae6SDimitry Andric void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
769eb11fae6SDimitry Andric   OS << "DIE Offset Base: " << DieOffsetBase << "\n";
770eb11fae6SDimitry Andric   for (auto Atom : Atoms)
771eb11fae6SDimitry Andric     Atom.print(OS);
772eb11fae6SDimitry Andric }
773eb11fae6SDimitry Andric 
print(raw_ostream & OS) const774eb11fae6SDimitry Andric void AppleAccelTableWriter::print(raw_ostream &OS) const {
775eb11fae6SDimitry Andric   Header.print(OS);
776eb11fae6SDimitry Andric   HeaderData.print(OS);
777eb11fae6SDimitry Andric   Contents.print(OS);
778eb11fae6SDimitry Andric   SecBegin->print(OS, nullptr);
779eb11fae6SDimitry Andric }
780eb11fae6SDimitry Andric 
print(raw_ostream & OS) const781eb11fae6SDimitry Andric void AccelTableBase::HashData::print(raw_ostream &OS) const {
782eb11fae6SDimitry Andric   OS << "Name: " << Name.getString() << "\n";
783eb11fae6SDimitry Andric   OS << "  Hash Value: " << format("0x%x", HashValue) << "\n";
784eb11fae6SDimitry Andric   OS << "  Symbol: ";
785eb11fae6SDimitry Andric   if (Sym)
786eb11fae6SDimitry Andric     OS << *Sym;
787eb11fae6SDimitry Andric   else
788eb11fae6SDimitry Andric     OS << "<none>";
789eb11fae6SDimitry Andric   OS << "\n";
790eb11fae6SDimitry Andric   for (auto *Value : Values)
791eb11fae6SDimitry Andric     Value->print(OS);
792eb11fae6SDimitry Andric }
793eb11fae6SDimitry Andric 
print(raw_ostream & OS) const794eb11fae6SDimitry Andric void AccelTableBase::print(raw_ostream &OS) const {
795eb11fae6SDimitry Andric   // Print Content.
796eb11fae6SDimitry Andric   OS << "Entries: \n";
7977fa27ce4SDimitry Andric   for (const auto &[Name, Data] : Entries) {
7987fa27ce4SDimitry Andric     OS << "Name: " << Name << "\n";
7997fa27ce4SDimitry Andric     for (auto *V : Data.Values)
800eb11fae6SDimitry Andric       V->print(OS);
801eb11fae6SDimitry Andric   }
802eb11fae6SDimitry Andric 
803eb11fae6SDimitry Andric   OS << "Buckets and Hashes: \n";
8044b4fe385SDimitry Andric   for (const auto &Bucket : Buckets)
8054b4fe385SDimitry Andric     for (const auto &Hash : Bucket)
806eb11fae6SDimitry Andric       Hash->print(OS);
807eb11fae6SDimitry Andric 
808eb11fae6SDimitry Andric   OS << "Data: \n";
8094b4fe385SDimitry Andric   for (const auto &E : Entries)
810eb11fae6SDimitry Andric     E.second.print(OS);
811eb11fae6SDimitry Andric }
812eb11fae6SDimitry Andric 
print(raw_ostream & OS) const813eb11fae6SDimitry Andric void DWARF5AccelTableData::print(raw_ostream &OS) const {
814eb11fae6SDimitry Andric   OS << "  Offset: " << getDieOffset() << "\n";
815eb11fae6SDimitry Andric   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
816eb11fae6SDimitry Andric }
817eb11fae6SDimitry Andric 
print(raw_ostream & OS) const818eb11fae6SDimitry Andric void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
819eb11fae6SDimitry Andric   OS << "  Offset: " << Die.getOffset() << "\n";
820eb11fae6SDimitry Andric }
821eb11fae6SDimitry Andric 
print(raw_ostream & OS) const822eb11fae6SDimitry Andric void AppleAccelTableTypeData::print(raw_ostream &OS) const {
823eb11fae6SDimitry Andric   OS << "  Offset: " << Die.getOffset() << "\n";
824eb11fae6SDimitry Andric   OS << "  Tag: " << dwarf::TagString(Die.getTag()) << "\n";
825eb11fae6SDimitry Andric }
826eb11fae6SDimitry Andric 
print(raw_ostream & OS) const827eb11fae6SDimitry Andric void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
828eb11fae6SDimitry Andric   OS << "  Static Offset: " << Offset << "\n";
829eb11fae6SDimitry Andric }
830eb11fae6SDimitry Andric 
print(raw_ostream & OS) const831eb11fae6SDimitry Andric void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
832eb11fae6SDimitry Andric   OS << "  Static Offset: " << Offset << "\n";
833eb11fae6SDimitry Andric   OS << "  QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
834eb11fae6SDimitry Andric   OS << "  Tag: " << dwarf::TagString(Tag) << "\n";
835eb11fae6SDimitry Andric   OS << "  ObjCClassIsImplementation: "
836eb11fae6SDimitry Andric      << (ObjCClassIsImplementation ? "true" : "false");
837eb11fae6SDimitry Andric   OS << "\n";
838eb11fae6SDimitry Andric }
839eb11fae6SDimitry Andric #endif
840