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