xref: /llvm-project/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp (revision a78d13d0786bc81058ee9aaa7d1c854ee19cee48)
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 
255   void emit();
256 };
257 } // namespace
258 
259 void AccelTableWriter::emitHashes() const {
260   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
261   unsigned BucketIdx = 0;
262   for (const auto &Bucket : Contents.getBuckets()) {
263     for (const auto &Hash : Bucket) {
264       uint32_t HashValue = Hash->HashValue;
265       if (SkipIdenticalHashes && PrevHash == HashValue)
266         continue;
267       Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
268       Asm->emitInt32(HashValue);
269       PrevHash = HashValue;
270     }
271     BucketIdx++;
272   }
273 }
274 
275 void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
276   const auto &Buckets = Contents.getBuckets();
277   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
278   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
279     for (auto *Hash : Buckets[i]) {
280       uint32_t HashValue = Hash->HashValue;
281       if (SkipIdenticalHashes && PrevHash == HashValue)
282         continue;
283       PrevHash = HashValue;
284       Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
285       Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
286     }
287   }
288 }
289 
290 void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
291   Asm->OutStreamer->AddComment("Header Magic");
292   Asm->emitInt32(Magic);
293   Asm->OutStreamer->AddComment("Header Version");
294   Asm->emitInt16(Version);
295   Asm->OutStreamer->AddComment("Header Hash Function");
296   Asm->emitInt16(HashFunction);
297   Asm->OutStreamer->AddComment("Header Bucket Count");
298   Asm->emitInt32(BucketCount);
299   Asm->OutStreamer->AddComment("Header Hash Count");
300   Asm->emitInt32(HashCount);
301   Asm->OutStreamer->AddComment("Header Data Length");
302   Asm->emitInt32(HeaderDataLength);
303 }
304 
305 void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
306   Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
307   Asm->emitInt32(DieOffsetBase);
308   Asm->OutStreamer->AddComment("HeaderData Atom Count");
309   Asm->emitInt32(Atoms.size());
310 
311   for (const Atom &A : Atoms) {
312     Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
313     Asm->emitInt16(A.Type);
314     Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
315     Asm->emitInt16(A.Form);
316   }
317 }
318 
319 void AppleAccelTableWriter::emitBuckets() const {
320   const auto &Buckets = Contents.getBuckets();
321   unsigned index = 0;
322   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
323     Asm->OutStreamer->AddComment("Bucket " + Twine(i));
324     if (!Buckets[i].empty())
325       Asm->emitInt32(index);
326     else
327       Asm->emitInt32(std::numeric_limits<uint32_t>::max());
328     // Buckets point in the list of hashes, not to the data. Do not increment
329     // the index multiple times in case of hash collisions.
330     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
331     for (auto *HD : Buckets[i]) {
332       uint32_t HashValue = HD->HashValue;
333       if (PrevHash != HashValue)
334         ++index;
335       PrevHash = HashValue;
336     }
337   }
338 }
339 
340 void AppleAccelTableWriter::emitData() const {
341   const auto &Buckets = Contents.getBuckets();
342   for (const AccelTableBase::HashList &Bucket : Buckets) {
343     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
344     for (const auto &Hash : Bucket) {
345       // Terminate the previous entry if there is no hash collision with the
346       // current one.
347       if (PrevHash != std::numeric_limits<uint64_t>::max() &&
348           PrevHash != Hash->HashValue)
349         Asm->emitInt32(0);
350       // Remember to emit the label for our offset.
351       Asm->OutStreamer->emitLabel(Hash->Sym);
352       Asm->OutStreamer->AddComment(Hash->Name.getString());
353       Asm->emitDwarfStringOffset(Hash->Name);
354       Asm->OutStreamer->AddComment("Num DIEs");
355       Asm->emitInt32(Hash->Values.size());
356       for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
357         V->emit(Asm);
358       PrevHash = Hash->HashValue;
359     }
360     // Emit the final end marker for the bucket.
361     if (!Bucket.empty())
362       Asm->emitInt32(0);
363   }
364 }
365 
366 void AppleAccelTableWriter::emit() const {
367   Header.emit(Asm);
368   HeaderData.emit(Asm);
369   emitBuckets();
370   emitHashes();
371   emitOffsets(SecBegin);
372   emitData();
373 }
374 
375 DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
376                                            const uint32_t UnitID,
377                                            const bool IsTU)
378     : OffsetVal(&Die), DieTag(Die.getTag()), IsTU(IsTU), UnitID(UnitID) {}
379 
380 void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
381   assert(CompUnitCount > 0 && "Index must have at least one CU.");
382 
383   AsmPrinter *Asm = Ctx.Asm;
384   Ctx.ContributionEnd =
385       Asm->emitDwarfUnitLength("names", "Header: unit length");
386   Asm->OutStreamer->AddComment("Header: version");
387   Asm->emitInt16(Version);
388   Asm->OutStreamer->AddComment("Header: padding");
389   Asm->emitInt16(Padding);
390   Asm->OutStreamer->AddComment("Header: compilation unit count");
391   Asm->emitInt32(CompUnitCount);
392   Asm->OutStreamer->AddComment("Header: local type unit count");
393   Asm->emitInt32(LocalTypeUnitCount);
394   Asm->OutStreamer->AddComment("Header: foreign type unit count");
395   Asm->emitInt32(ForeignTypeUnitCount);
396   Asm->OutStreamer->AddComment("Header: bucket count");
397   Asm->emitInt32(BucketCount);
398   Asm->OutStreamer->AddComment("Header: name count");
399   Asm->emitInt32(NameCount);
400   Asm->OutStreamer->AddComment("Header: abbreviation table size");
401   Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
402   Asm->OutStreamer->AddComment("Header: augmentation string size");
403   assert(AugmentationStringSize % 4 == 0);
404   Asm->emitInt32(AugmentationStringSize);
405   Asm->OutStreamer->AddComment("Header: augmentation string");
406   Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
407 }
408 
409 std::optional<uint64_t>
410 DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
411   if (auto *Parent = Die.getParent();
412       Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
413     return Parent->getOffset();
414   return {};
415 }
416 
417 static std::optional<dwarf::Form>
418 getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
419                     std::optional<OffsetAndUnitID> ParentOffset) {
420   // No parent information
421   if (!ParentOffset)
422     return std::nullopt;
423   // Parent is indexed by this table.
424   if (IndexedOffsets.contains(*ParentOffset))
425     return dwarf::Form::DW_FORM_ref4;
426   // Parent is not indexed by this table.
427   return dwarf::Form::DW_FORM_flag_present;
428 }
429 
430 void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const {
431   ID.AddInteger(DieTag);
432   for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
433     ID.AddInteger(Enc.Index);
434     ID.AddInteger(Enc.Form);
435   }
436 }
437 
438 void Dwarf5AccelTableWriter::populateAbbrevsMap() {
439   for (auto &Bucket : Contents.getBuckets()) {
440     for (auto *Hash : Bucket) {
441       for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
442         std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
443             getIndexForEntry(*Value);
444         std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
445             IndexedOffsets, Value->getParentDieOffsetAndUnitID());
446         DebugNamesAbbrev Abbrev(Value->getDieTag());
447         if (EntryRet)
448           Abbrev.addAttribute(EntryRet->Encoding);
449         Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
450         if (MaybeParentForm)
451           Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
452         FoldingSetNodeID ID;
453         Abbrev.Profile(ID);
454         void *InsertPos;
455         if (DebugNamesAbbrev *Existing =
456                 AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
457           Value->setAbbrevNumber(Existing->getNumber());
458           continue;
459         }
460         DebugNamesAbbrev *NewAbbrev =
461             new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
462         AbbreviationsVector.push_back(NewAbbrev);
463         NewAbbrev->setNumber(AbbreviationsVector.size());
464         AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);
465         Value->setAbbrevNumber(NewAbbrev->getNumber());
466       }
467     }
468   }
469 }
470 
471 void Dwarf5AccelTableWriter::emitCUList() const {
472   for (const auto &CU : enumerate(CompUnits)) {
473     Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
474     if (std::holds_alternative<MCSymbol *>(CU.value()))
475       Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
476     else
477       Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
478   }
479 }
480 
481 void Dwarf5AccelTableWriter::emitTUList() const {
482   for (const auto &TU : enumerate(TypeUnits)) {
483     Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
484     if (std::holds_alternative<MCSymbol *>(TU.value()))
485       Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
486     else if (IsSplitDwarf)
487       Asm->emitInt64(std::get<uint64_t>(TU.value()));
488     else
489       Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
490   }
491 }
492 
493 void Dwarf5AccelTableWriter::emitBuckets() const {
494   uint32_t Index = 1;
495   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
496     Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
497     Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
498     Index += Bucket.value().size();
499   }
500 }
501 
502 void Dwarf5AccelTableWriter::emitStringOffsets() const {
503   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
504     for (auto *Hash : Bucket.value()) {
505       DwarfStringPoolEntryRef String = Hash->Name;
506       Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
507                                    ": " + String.getString());
508       Asm->emitDwarfStringOffset(String);
509     }
510   }
511 }
512 
513 void Dwarf5AccelTableWriter::emitAbbrevs() const {
514   Asm->OutStreamer->emitLabel(AbbrevStart);
515   for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
516     Asm->OutStreamer->AddComment("Abbrev code");
517     Asm->emitULEB128(Abbrev->getNumber());
518     Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
519     Asm->emitULEB128(Abbrev->getDieTag());
520     for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
521          Abbrev->getAttributes()) {
522       Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
523       Asm->emitULEB128(AttrEnc.Form,
524                        dwarf::FormEncodingString(AttrEnc.Form).data());
525     }
526     Asm->emitULEB128(0, "End of abbrev");
527     Asm->emitULEB128(0, "End of abbrev");
528   }
529   Asm->emitULEB128(0, "End of abbrev list");
530   Asm->OutStreamer->emitLabel(AbbrevEnd);
531 }
532 
533 void Dwarf5AccelTableWriter::emitEntry(
534     const DWARF5AccelTableData &Entry,
535     const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
536     DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) {
537   unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
538   assert(AbbrevIndex < AbbreviationsVector.size() &&
539          "Entry abbrev index is outside of abbreviations vector range.");
540   DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
541   std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
542       getIndexForEntry(Entry);
543   std::optional<OffsetAndUnitID> MaybeParentOffset =
544       Entry.getParentDieOffsetAndUnitID();
545   auto EntrySymbolIt =
546       DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
547   assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
548   MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
549 
550   // Emit the label for this Entry, so that IDX_parents may refer to it.
551   // Note: a DIE may have multiple accelerator Entries; this check avoids
552   // creating/emitting multiple labels for the same DIE.
553   if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
554     Asm->OutStreamer->emitLabel(EntrySymbol);
555 
556   Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
557 
558   for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
559        Abbrev->getAttributes()) {
560     Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
561     switch (AttrEnc.Index) {
562     case dwarf::DW_IDX_compile_unit:
563     case dwarf::DW_IDX_type_unit: {
564       DIEInteger ID(EntryRet->Index);
565       ID.emitValue(Asm, AttrEnc.Form);
566       break;
567     }
568     case dwarf::DW_IDX_die_offset:
569       assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
570       Asm->emitInt32(Entry.getDieOffset());
571       break;
572     case dwarf::DW_IDX_parent: {
573       if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
574         break;
575       auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
576       assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
577       Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
578       break;
579     }
580     default:
581       llvm_unreachable("Unexpected index attribute!");
582     }
583   }
584 }
585 
586 void Dwarf5AccelTableWriter::emitData() {
587   DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
588 
589   for (OffsetAndUnitID Offset : IndexedOffsets)
590     DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
591 
592   Asm->OutStreamer->emitLabel(EntryPool);
593   DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
594   for (auto &Bucket : Contents.getBuckets()) {
595     for (auto *Hash : Bucket) {
596       // Remember to emit the label for our offset.
597       Asm->OutStreamer->emitLabel(Hash->Sym);
598       for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
599         emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
600       Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
601       Asm->emitInt8(0);
602     }
603   }
604 }
605 
606 Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
607     AsmPrinter *Asm, const AccelTableBase &Contents,
608     ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
609     ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
610     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
611         const DWARF5AccelTableData &)>
612         getIndexForEntry,
613     bool IsSplitDwarf)
614     : AccelTableWriter(Asm, Contents, false),
615       Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
616              IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
617              Contents.getUniqueNameCount()),
618       CompUnits(CompUnits), TypeUnits(TypeUnits),
619       getIndexForEntry(std::move(getIndexForEntry)),
620       IsSplitDwarf(IsSplitDwarf) {
621 
622   for (auto &Bucket : Contents.getBuckets())
623     for (auto *Hash : Bucket)
624       for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
625         IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
626 
627   populateAbbrevsMap();
628 }
629 
630 void Dwarf5AccelTableWriter::emit() {
631   Header.emit(*this);
632   emitCUList();
633   emitTUList();
634   emitBuckets();
635   emitHashes();
636   emitStringOffsets();
637   emitOffsets(EntryPool);
638   emitAbbrevs();
639   emitData();
640   Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
641   Asm->OutStreamer->emitLabel(ContributionEnd);
642 }
643 
644 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
645                                    StringRef Prefix, const MCSymbol *SecBegin,
646                                    ArrayRef<AppleAccelTableData::Atom> Atoms) {
647   Contents.finalize(Asm, Prefix);
648   AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
649 }
650 
651 void llvm::emitDWARF5AccelTable(
652     AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
653     ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
654   TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
655   std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
656   std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
657   SmallVector<unsigned, 1> CUIndex(CUs.size());
658   DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
659   int CUCount = 0;
660   int TUCount = 0;
661   for (const auto &CU : enumerate(CUs)) {
662     switch (CU.value()->getCUNode()->getNameTableKind()) {
663     case DICompileUnit::DebugNameTableKind::Default:
664     case DICompileUnit::DebugNameTableKind::Apple:
665       break;
666     default:
667       continue;
668     }
669     CUIndex[CU.index()] = CUCount++;
670     assert(CU.index() == CU.value()->getUniqueID());
671     const DwarfCompileUnit *MainCU =
672         DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
673     CompUnits.push_back(MainCU->getLabelBegin());
674   }
675 
676   for (const auto &TU : TUSymbols) {
677     TUIndex[TU.UniqueID] = TUCount++;
678     if (DD.useSplitDwarf())
679       TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
680     else
681       TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
682   }
683 
684   if (CompUnits.empty())
685     return;
686 
687   Asm->OutStreamer->switchSection(
688       Asm->getObjFileLowering().getDwarfDebugNamesSection());
689 
690   Contents.finalize(Asm, "names");
691   dwarf::Form CUIndexForm =
692       DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
693   dwarf::Form TUIndexForm =
694       DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
695   Dwarf5AccelTableWriter(
696       Asm, Contents, CompUnits, TypeUnits,
697       [&](const DWARF5AccelTableData &Entry)
698           -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
699         if (Entry.isTU())
700           return {{TUIndex[Entry.getUnitID()],
701                    {dwarf::DW_IDX_type_unit, TUIndexForm}}};
702         if (CUIndex.size() > 1)
703           return {{CUIndex[Entry.getUnitID()],
704                    {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
705         return std::nullopt;
706       },
707       DD.useSplitDwarf())
708       .emit();
709 }
710 
711 void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
712   TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
713 }
714 
715 void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
716   TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
717 }
718 
719 void llvm::emitDWARF5AccelTable(
720     AsmPrinter *Asm, DWARF5AccelTable &Contents,
721     ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
722     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
723         const DWARF5AccelTableData &)>
724         getIndexForEntry) {
725   std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
726   Contents.finalize(Asm, "names");
727   Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
728       .emit();
729 }
730 
731 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
732   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
733          "The section offset exceeds the limit.");
734   Asm->emitInt32(Die.getDebugSectionOffset());
735 }
736 
737 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
738   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
739          "The section offset exceeds the limit.");
740   Asm->emitInt32(Die.getDebugSectionOffset());
741   Asm->emitInt16(Die.getTag());
742   Asm->emitInt8(0);
743 }
744 
745 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
746   Asm->emitInt32(Offset);
747 }
748 
749 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
750   Asm->emitInt32(Offset);
751   Asm->emitInt16(Tag);
752   Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
753                                           : 0);
754   Asm->emitInt32(QualifiedNameHash);
755 }
756 
757 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
758 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
759 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
760 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
761 
762 #ifndef NDEBUG
763 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
764   OS << "Magic: " << format("0x%x", Magic) << "\n"
765      << "Version: " << Version << "\n"
766      << "Hash Function: " << HashFunction << "\n"
767      << "Bucket Count: " << BucketCount << "\n"
768      << "Header Data Length: " << HeaderDataLength << "\n";
769 }
770 
771 void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
772   OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
773      << "Form: " << dwarf::FormEncodingString(Form) << "\n";
774 }
775 
776 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
777   OS << "DIE Offset Base: " << DieOffsetBase << "\n";
778   for (auto Atom : Atoms)
779     Atom.print(OS);
780 }
781 
782 void AppleAccelTableWriter::print(raw_ostream &OS) const {
783   Header.print(OS);
784   HeaderData.print(OS);
785   Contents.print(OS);
786   SecBegin->print(OS, nullptr);
787 }
788 
789 void AccelTableBase::HashData::print(raw_ostream &OS) const {
790   OS << "Name: " << Name.getString() << "\n";
791   OS << "  Hash Value: " << format("0x%x", HashValue) << "\n";
792   OS << "  Symbol: ";
793   if (Sym)
794     OS << *Sym;
795   else
796     OS << "<none>";
797   OS << "\n";
798   for (auto *Value : Values)
799     Value->print(OS);
800 }
801 
802 void AccelTableBase::print(raw_ostream &OS) const {
803   // Print Content.
804   OS << "Entries: \n";
805   for (const auto &[Name, Data] : Entries) {
806     OS << "Name: " << Name << "\n";
807     for (auto *V : Data.Values)
808       V->print(OS);
809   }
810 
811   OS << "Buckets and Hashes: \n";
812   for (const auto &Bucket : Buckets)
813     for (const auto &Hash : Bucket)
814       Hash->print(OS);
815 
816   OS << "Data: \n";
817   for (const auto &E : Entries)
818     E.second.print(OS);
819 }
820 
821 void DWARF5AccelTableData::print(raw_ostream &OS) const {
822   OS << "  Offset: " << getDieOffset() << "\n";
823   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
824 }
825 
826 void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
827   OS << "  Offset: " << Die.getOffset() << "\n";
828 }
829 
830 void AppleAccelTableTypeData::print(raw_ostream &OS) const {
831   OS << "  Offset: " << Die.getOffset() << "\n";
832   OS << "  Tag: " << dwarf::TagString(Die.getTag()) << "\n";
833 }
834 
835 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
836   OS << "  Static Offset: " << Offset << "\n";
837 }
838 
839 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
840   OS << "  Static Offset: " << Offset << "\n";
841   OS << "  QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
842   OS << "  Tag: " << dwarf::TagString(Tag) << "\n";
843   OS << "  ObjCClassIsImplementation: "
844      << (ObjCClassIsImplementation ? "true" : "false");
845   OS << "\n";
846 }
847 #endif
848