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