• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains support for writing accelerator tables.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/CodeGen/AccelTable.h"
15 #include "DwarfCompileUnit.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringMap.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/MCExpr.h"
23 #include "llvm/MC/MCStreamer.h"
24 #include "llvm/MC/MCSymbol.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include <algorithm>
27 #include <cstddef>
28 #include <cstdint>
29 #include <limits>
30 #include <vector>
31 
32 using namespace llvm;
33 
computeBucketCount()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 
finalize(AsmPrinter * Asm,StringRef Prefix)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     std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
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     std::stable_sort(Bucket.begin(), Bucket.end(),
85                      [](HashData *LHS, HashData *RHS) {
86                        return LHS->HashValue < RHS->HashValue;
87                      });
88 }
89 
90 namespace {
91 /// Base class for writing out Accelerator tables. It holds the common
92 /// functionality for the two Accelerator table types.
93 class AccelTableWriter {
94 protected:
95   AsmPrinter *const Asm;          ///< Destination.
96   const AccelTableBase &Contents; ///< Data to emit.
97 
98   /// Controls whether to emit duplicate hash and offset table entries for names
99   /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
100   /// tables do.
101   const bool SkipIdenticalHashes;
102 
103   void emitHashes() const;
104 
105   /// Emit offsets to lists of entries with identical names. The offsets are
106   /// relative to the Base argument.
107   void emitOffsets(const MCSymbol *Base) const;
108 
109 public:
AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,bool SkipIdenticalHashes)110   AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
111                    bool SkipIdenticalHashes)
112       : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
113   }
114 };
115 
116 class AppleAccelTableWriter : public AccelTableWriter {
117   using Atom = AppleAccelTableData::Atom;
118 
119   /// The fixed header of an Apple Accelerator Table.
120   struct Header {
121     uint32_t Magic = MagicHash;
122     uint16_t Version = 1;
123     uint16_t HashFunction = dwarf::DW_hash_function_djb;
124     uint32_t BucketCount;
125     uint32_t HashCount;
126     uint32_t HeaderDataLength;
127 
128     /// 'HASH' magic value to detect endianness.
129     static const uint32_t MagicHash = 0x48415348;
130 
Header__anon41ef894b0311::AppleAccelTableWriter::Header131     Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
132         : BucketCount(BucketCount), HashCount(UniqueHashCount),
133           HeaderDataLength(DataLength) {}
134 
135     void emit(AsmPrinter *Asm) const;
136 #ifndef NDEBUG
137     void print(raw_ostream &OS) const;
dump__anon41ef894b0311::AppleAccelTableWriter::Header138     void dump() const { print(dbgs()); }
139 #endif
140   };
141 
142   /// The HeaderData describes the structure of an Apple accelerator table
143   /// through a list of Atoms.
144   struct HeaderData {
145     /// In the case of data that is referenced via DW_FORM_ref_* the offset
146     /// base is used to describe the offset for all forms in the list of atoms.
147     uint32_t DieOffsetBase;
148 
149     const SmallVector<Atom, 4> Atoms;
150 
HeaderData__anon41ef894b0311::AppleAccelTableWriter::HeaderData151     HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
152         : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
153 
154     void emit(AsmPrinter *Asm) const;
155 #ifndef NDEBUG
156     void print(raw_ostream &OS) const;
dump__anon41ef894b0311::AppleAccelTableWriter::HeaderData157     void dump() const { print(dbgs()); }
158 #endif
159   };
160 
161   Header Header;
162   HeaderData HeaderData;
163   const MCSymbol *SecBegin;
164 
165   void emitBuckets() const;
166   void emitData() const;
167 
168 public:
AppleAccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<Atom> Atoms,const MCSymbol * SecBegin)169   AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
170                         ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
171       : AccelTableWriter(Asm, Contents, true),
172         Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
173                8 + (Atoms.size() * 4)),
174         HeaderData(Atoms), SecBegin(SecBegin) {}
175 
176   void emit() const;
177 
178 #ifndef NDEBUG
179   void print(raw_ostream &OS) const;
dump() const180   void dump() const { print(dbgs()); }
181 #endif
182 };
183 
184 /// Class responsible for emitting a DWARF v5 Accelerator Table. The only
185 /// public function is emit(), which performs the actual emission.
186 ///
187 /// The class is templated in its data type. This allows us to emit both dyamic
188 /// and static data entries. A callback abstract the logic to provide a CU
189 /// index for a given entry, which is different per data type, but identical
190 /// for every entry in the same table.
191 template <typename DataT>
192 class Dwarf5AccelTableWriter : public AccelTableWriter {
193   struct Header {
194     uint32_t UnitLength = 0;
195     uint16_t Version = 5;
196     uint16_t Padding = 0;
197     uint32_t CompUnitCount;
198     uint32_t LocalTypeUnitCount = 0;
199     uint32_t ForeignTypeUnitCount = 0;
200     uint32_t BucketCount;
201     uint32_t NameCount;
202     uint32_t AbbrevTableSize = 0;
203     uint32_t AugmentationStringSize = sizeof(AugmentationString);
204     char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
205 
Header__anon41ef894b0311::Dwarf5AccelTableWriter::Header206     Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount)
207         : CompUnitCount(CompUnitCount), BucketCount(BucketCount),
208           NameCount(NameCount) {}
209 
210     void emit(const Dwarf5AccelTableWriter &Ctx) const;
211   };
212   struct AttributeEncoding {
213     dwarf::Index Index;
214     dwarf::Form Form;
215   };
216 
217   Header Header;
218   DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
219   ArrayRef<MCSymbol *> CompUnits;
220   llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry;
221   MCSymbol *ContributionStart = Asm->createTempSymbol("names_start");
222   MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end");
223   MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
224   MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
225   MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
226 
227   DenseSet<uint32_t> getUniqueTags() const;
228 
229   // Right now, we emit uniform attributes for all tags.
230   SmallVector<AttributeEncoding, 2> getUniformAttributes() const;
231 
232   void emitCUList() const;
233   void emitBuckets() const;
234   void emitStringOffsets() const;
235   void emitAbbrevs() const;
236   void emitEntry(const DataT &Entry) const;
237   void emitData() const;
238 
239 public:
240   Dwarf5AccelTableWriter(
241       AsmPrinter *Asm, const AccelTableBase &Contents,
242       ArrayRef<MCSymbol *> CompUnits,
243       llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry);
244 
245   void emit() const;
246 };
247 } // namespace
248 
emitHashes() const249 void AccelTableWriter::emitHashes() const {
250   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
251   unsigned BucketIdx = 0;
252   for (auto &Bucket : Contents.getBuckets()) {
253     for (auto &Hash : Bucket) {
254       uint32_t HashValue = Hash->HashValue;
255       if (SkipIdenticalHashes && PrevHash == HashValue)
256         continue;
257       Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
258       Asm->emitInt32(HashValue);
259       PrevHash = HashValue;
260     }
261     BucketIdx++;
262   }
263 }
264 
emitOffsets(const MCSymbol * Base) const265 void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
266   const auto &Buckets = Contents.getBuckets();
267   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
268   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
269     for (auto *Hash : Buckets[i]) {
270       uint32_t HashValue = Hash->HashValue;
271       if (SkipIdenticalHashes && PrevHash == HashValue)
272         continue;
273       PrevHash = HashValue;
274       Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
275       Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t));
276     }
277   }
278 }
279 
emit(AsmPrinter * Asm) const280 void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
281   Asm->OutStreamer->AddComment("Header Magic");
282   Asm->emitInt32(Magic);
283   Asm->OutStreamer->AddComment("Header Version");
284   Asm->emitInt16(Version);
285   Asm->OutStreamer->AddComment("Header Hash Function");
286   Asm->emitInt16(HashFunction);
287   Asm->OutStreamer->AddComment("Header Bucket Count");
288   Asm->emitInt32(BucketCount);
289   Asm->OutStreamer->AddComment("Header Hash Count");
290   Asm->emitInt32(HashCount);
291   Asm->OutStreamer->AddComment("Header Data Length");
292   Asm->emitInt32(HeaderDataLength);
293 }
294 
emit(AsmPrinter * Asm) const295 void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
296   Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
297   Asm->emitInt32(DieOffsetBase);
298   Asm->OutStreamer->AddComment("HeaderData Atom Count");
299   Asm->emitInt32(Atoms.size());
300 
301   for (const Atom &A : Atoms) {
302     Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
303     Asm->emitInt16(A.Type);
304     Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
305     Asm->emitInt16(A.Form);
306   }
307 }
308 
emitBuckets() const309 void AppleAccelTableWriter::emitBuckets() const {
310   const auto &Buckets = Contents.getBuckets();
311   unsigned index = 0;
312   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
313     Asm->OutStreamer->AddComment("Bucket " + Twine(i));
314     if (!Buckets[i].empty())
315       Asm->emitInt32(index);
316     else
317       Asm->emitInt32(std::numeric_limits<uint32_t>::max());
318     // Buckets point in the list of hashes, not to the data. Do not increment
319     // the index multiple times in case of hash collisions.
320     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
321     for (auto *HD : Buckets[i]) {
322       uint32_t HashValue = HD->HashValue;
323       if (PrevHash != HashValue)
324         ++index;
325       PrevHash = HashValue;
326     }
327   }
328 }
329 
emitData() const330 void AppleAccelTableWriter::emitData() const {
331   const auto &Buckets = Contents.getBuckets();
332   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
333     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
334     for (auto &Hash : Buckets[i]) {
335       // Terminate the previous entry if there is no hash collision with the
336       // current one.
337       if (PrevHash != std::numeric_limits<uint64_t>::max() &&
338           PrevHash != Hash->HashValue)
339         Asm->emitInt32(0);
340       // Remember to emit the label for our offset.
341       Asm->OutStreamer->EmitLabel(Hash->Sym);
342       Asm->OutStreamer->AddComment(Hash->Name.getString());
343       Asm->emitDwarfStringOffset(Hash->Name);
344       Asm->OutStreamer->AddComment("Num DIEs");
345       Asm->emitInt32(Hash->Values.size());
346       for (const auto *V : Hash->Values)
347         static_cast<const AppleAccelTableData *>(V)->emit(Asm);
348       PrevHash = Hash->HashValue;
349     }
350     // Emit the final end marker for the bucket.
351     if (!Buckets[i].empty())
352       Asm->emitInt32(0);
353   }
354 }
355 
emit() const356 void AppleAccelTableWriter::emit() const {
357   Header.emit(Asm);
358   HeaderData.emit(Asm);
359   emitBuckets();
360   emitHashes();
361   emitOffsets(SecBegin);
362   emitData();
363 }
364 
365 template <typename DataT>
emit(const Dwarf5AccelTableWriter & Ctx) const366 void Dwarf5AccelTableWriter<DataT>::Header::emit(
367     const Dwarf5AccelTableWriter &Ctx) const {
368   assert(CompUnitCount > 0 && "Index must have at least one CU.");
369 
370   AsmPrinter *Asm = Ctx.Asm;
371   Asm->OutStreamer->AddComment("Header: unit length");
372   Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart,
373                            sizeof(uint32_t));
374   Asm->OutStreamer->EmitLabel(Ctx.ContributionStart);
375   Asm->OutStreamer->AddComment("Header: version");
376   Asm->emitInt16(Version);
377   Asm->OutStreamer->AddComment("Header: padding");
378   Asm->emitInt16(Padding);
379   Asm->OutStreamer->AddComment("Header: compilation unit count");
380   Asm->emitInt32(CompUnitCount);
381   Asm->OutStreamer->AddComment("Header: local type unit count");
382   Asm->emitInt32(LocalTypeUnitCount);
383   Asm->OutStreamer->AddComment("Header: foreign type unit count");
384   Asm->emitInt32(ForeignTypeUnitCount);
385   Asm->OutStreamer->AddComment("Header: bucket count");
386   Asm->emitInt32(BucketCount);
387   Asm->OutStreamer->AddComment("Header: name count");
388   Asm->emitInt32(NameCount);
389   Asm->OutStreamer->AddComment("Header: abbreviation table size");
390   Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
391   Asm->OutStreamer->AddComment("Header: augmentation string size");
392   assert(AugmentationStringSize % 4 == 0);
393   Asm->emitInt32(AugmentationStringSize);
394   Asm->OutStreamer->AddComment("Header: augmentation string");
395   Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize});
396 }
397 
398 template <typename DataT>
getUniqueTags() const399 DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const {
400   DenseSet<uint32_t> UniqueTags;
401   for (auto &Bucket : Contents.getBuckets()) {
402     for (auto *Hash : Bucket) {
403       for (auto *Value : Hash->Values) {
404         unsigned Tag = static_cast<const DataT *>(Value)->getDieTag();
405         UniqueTags.insert(Tag);
406       }
407     }
408   }
409   return UniqueTags;
410 }
411 
412 template <typename DataT>
413 SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2>
getUniformAttributes() const414 Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const {
415   SmallVector<AttributeEncoding, 2> UA;
416   if (CompUnits.size() > 1) {
417     size_t LargestCUIndex = CompUnits.size() - 1;
418     dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex);
419     UA.push_back({dwarf::DW_IDX_compile_unit, Form});
420   }
421   UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
422   return UA;
423 }
424 
425 template <typename DataT>
emitCUList() const426 void Dwarf5AccelTableWriter<DataT>::emitCUList() const {
427   for (const auto &CU : enumerate(CompUnits)) {
428     Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
429     Asm->emitDwarfSymbolReference(CU.value());
430   }
431 }
432 
433 template <typename DataT>
emitBuckets() const434 void Dwarf5AccelTableWriter<DataT>::emitBuckets() const {
435   uint32_t Index = 1;
436   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
437     Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
438     Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
439     Index += Bucket.value().size();
440   }
441 }
442 
443 template <typename DataT>
emitStringOffsets() const444 void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const {
445   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
446     for (auto *Hash : Bucket.value()) {
447       DwarfStringPoolEntryRef String = Hash->Name;
448       Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
449                                    ": " + String.getString());
450       Asm->emitDwarfStringOffset(String);
451     }
452   }
453 }
454 
455 template <typename DataT>
emitAbbrevs() const456 void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {
457   Asm->OutStreamer->EmitLabel(AbbrevStart);
458   for (const auto &Abbrev : Abbreviations) {
459     Asm->OutStreamer->AddComment("Abbrev code");
460     assert(Abbrev.first != 0);
461     Asm->EmitULEB128(Abbrev.first);
462     Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first));
463     Asm->EmitULEB128(Abbrev.first);
464     for (const auto &AttrEnc : Abbrev.second) {
465       Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
466       Asm->EmitULEB128(AttrEnc.Form,
467                        dwarf::FormEncodingString(AttrEnc.Form).data());
468     }
469     Asm->EmitULEB128(0, "End of abbrev");
470     Asm->EmitULEB128(0, "End of abbrev");
471   }
472   Asm->EmitULEB128(0, "End of abbrev list");
473   Asm->OutStreamer->EmitLabel(AbbrevEnd);
474 }
475 
476 template <typename DataT>
emitEntry(const DataT & Entry) const477 void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
478   auto AbbrevIt = Abbreviations.find(Entry.getDieTag());
479   assert(AbbrevIt != Abbreviations.end() &&
480          "Why wasn't this abbrev generated?");
481 
482   Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code");
483   for (const auto &AttrEnc : AbbrevIt->second) {
484     Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
485     switch (AttrEnc.Index) {
486     case dwarf::DW_IDX_compile_unit: {
487       DIEInteger ID(getCUIndexForEntry(Entry));
488       ID.EmitValue(Asm, AttrEnc.Form);
489       break;
490     }
491     case dwarf::DW_IDX_die_offset:
492       assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
493       Asm->emitInt32(Entry.getDieOffset());
494       break;
495     default:
496       llvm_unreachable("Unexpected index attribute!");
497     }
498   }
499 }
500 
emitData() const501 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const {
502   Asm->OutStreamer->EmitLabel(EntryPool);
503   for (auto &Bucket : Contents.getBuckets()) {
504     for (auto *Hash : Bucket) {
505       // Remember to emit the label for our offset.
506       Asm->OutStreamer->EmitLabel(Hash->Sym);
507       for (const auto *Value : Hash->Values)
508         emitEntry(*static_cast<const DataT *>(Value));
509       Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
510       Asm->emitInt32(0);
511     }
512   }
513 }
514 
515 template <typename DataT>
Dwarf5AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<MCSymbol * > CompUnits,llvm::function_ref<unsigned (const DataT &)> getCUIndexForEntry)516 Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter(
517     AsmPrinter *Asm, const AccelTableBase &Contents,
518     ArrayRef<MCSymbol *> CompUnits,
519     llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry)
520     : AccelTableWriter(Asm, Contents, false),
521       Header(CompUnits.size(), Contents.getBucketCount(),
522              Contents.getUniqueNameCount()),
523       CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) {
524   DenseSet<uint32_t> UniqueTags = getUniqueTags();
525   SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();
526 
527   Abbreviations.reserve(UniqueTags.size());
528   for (uint32_t Tag : UniqueTags)
529     Abbreviations.try_emplace(Tag, UniformAttributes);
530 }
531 
emit() const532 template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() const {
533   Header.emit(*this);
534   emitCUList();
535   emitBuckets();
536   emitHashes();
537   emitStringOffsets();
538   emitOffsets(EntryPool);
539   emitAbbrevs();
540   emitData();
541   Asm->OutStreamer->EmitValueToAlignment(4, 0);
542   Asm->OutStreamer->EmitLabel(ContributionEnd);
543 }
544 
emitAppleAccelTableImpl(AsmPrinter * Asm,AccelTableBase & Contents,StringRef Prefix,const MCSymbol * SecBegin,ArrayRef<AppleAccelTableData::Atom> Atoms)545 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
546                                    StringRef Prefix, const MCSymbol *SecBegin,
547                                    ArrayRef<AppleAccelTableData::Atom> Atoms) {
548   Contents.finalize(Asm, Prefix);
549   AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
550 }
551 
emitDWARF5AccelTable(AsmPrinter * Asm,AccelTable<DWARF5AccelTableData> & Contents,const DwarfDebug & DD,ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs)552 void llvm::emitDWARF5AccelTable(
553     AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
554     const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
555   std::vector<MCSymbol *> CompUnits;
556   for (const auto &CU : enumerate(CUs)) {
557     assert(CU.index() == CU.value()->getUniqueID());
558     const DwarfCompileUnit *MainCU =
559         DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
560     CompUnits.push_back(MainCU->getLabelBegin());
561   }
562 
563   Contents.finalize(Asm, "names");
564   Dwarf5AccelTableWriter<DWARF5AccelTableData>(
565       Asm, Contents, CompUnits,
566       [&DD](const DWARF5AccelTableData &Entry) {
567         const DIE *CUDie = Entry.getDie().getUnitDie();
568         return DD.lookupCU(CUDie)->getUniqueID();
569       })
570       .emit();
571 }
572 
emitDWARF5AccelTable(AsmPrinter * Asm,AccelTable<DWARF5AccelTableStaticData> & Contents,ArrayRef<MCSymbol * > CUs,llvm::function_ref<unsigned (const DWARF5AccelTableStaticData &)> getCUIndexForEntry)573 void llvm::emitDWARF5AccelTable(
574     AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
575     ArrayRef<MCSymbol *> CUs,
576     llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
577         getCUIndexForEntry) {
578   Contents.finalize(Asm, "names");
579   Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs,
580                                                      getCUIndexForEntry)
581       .emit();
582 }
583 
emit(AsmPrinter * Asm) const584 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
585   Asm->emitInt32(Die.getDebugSectionOffset());
586 }
587 
emit(AsmPrinter * Asm) const588 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
589   Asm->emitInt32(Die.getDebugSectionOffset());
590   Asm->emitInt16(Die.getTag());
591   Asm->emitInt8(0);
592 }
593 
emit(AsmPrinter * Asm) const594 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
595   Asm->emitInt32(Offset);
596 }
597 
emit(AsmPrinter * Asm) const598 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
599   Asm->emitInt32(Offset);
600   Asm->emitInt16(Tag);
601   Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
602                                           : 0);
603   Asm->emitInt32(QualifiedNameHash);
604 }
605 
606 #ifndef _MSC_VER
607 // The lines below are rejected by older versions (TBD) of MSVC.
608 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
609 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
610 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
611 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
612 #else
613 // FIXME: Erase this path once the minimum MSCV version has been bumped.
614 const SmallVector<AppleAccelTableData::Atom, 4>
615     AppleAccelTableOffsetData::Atoms = {
616         Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
617 const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms =
618     {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
619      Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
620      Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
621 const SmallVector<AppleAccelTableData::Atom, 4>
622     AppleAccelTableStaticOffsetData::Atoms = {
623         Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
624 const SmallVector<AppleAccelTableData::Atom, 4>
625     AppleAccelTableStaticTypeData::Atoms = {
626         Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
627         Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
628         Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
629 #endif
630 
631 #ifndef NDEBUG
print(raw_ostream & OS) const632 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
633   OS << "Magic: " << format("0x%x", Magic) << "\n"
634      << "Version: " << Version << "\n"
635      << "Hash Function: " << HashFunction << "\n"
636      << "Bucket Count: " << BucketCount << "\n"
637      << "Header Data Length: " << HeaderDataLength << "\n";
638 }
639 
print(raw_ostream & OS) const640 void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
641   OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
642      << "Form: " << dwarf::FormEncodingString(Form) << "\n";
643 }
644 
print(raw_ostream & OS) const645 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
646   OS << "DIE Offset Base: " << DieOffsetBase << "\n";
647   for (auto Atom : Atoms)
648     Atom.print(OS);
649 }
650 
print(raw_ostream & OS) const651 void AppleAccelTableWriter::print(raw_ostream &OS) const {
652   Header.print(OS);
653   HeaderData.print(OS);
654   Contents.print(OS);
655   SecBegin->print(OS, nullptr);
656 }
657 
print(raw_ostream & OS) const658 void AccelTableBase::HashData::print(raw_ostream &OS) const {
659   OS << "Name: " << Name.getString() << "\n";
660   OS << "  Hash Value: " << format("0x%x", HashValue) << "\n";
661   OS << "  Symbol: ";
662   if (Sym)
663     OS << *Sym;
664   else
665     OS << "<none>";
666   OS << "\n";
667   for (auto *Value : Values)
668     Value->print(OS);
669 }
670 
print(raw_ostream & OS) const671 void AccelTableBase::print(raw_ostream &OS) const {
672   // Print Content.
673   OS << "Entries: \n";
674   for (const auto &Entry : Entries) {
675     OS << "Name: " << Entry.first() << "\n";
676     for (auto *V : Entry.second.Values)
677       V->print(OS);
678   }
679 
680   OS << "Buckets and Hashes: \n";
681   for (auto &Bucket : Buckets)
682     for (auto &Hash : Bucket)
683       Hash->print(OS);
684 
685   OS << "Data: \n";
686   for (auto &E : Entries)
687     E.second.print(OS);
688 }
689 
print(raw_ostream & OS) const690 void DWARF5AccelTableData::print(raw_ostream &OS) const {
691   OS << "  Offset: " << getDieOffset() << "\n";
692   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
693 }
694 
print(raw_ostream & OS) const695 void DWARF5AccelTableStaticData::print(raw_ostream &OS) const {
696   OS << "  Offset: " << getDieOffset() << "\n";
697   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
698 }
699 
print(raw_ostream & OS) const700 void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
701   OS << "  Offset: " << Die.getOffset() << "\n";
702 }
703 
print(raw_ostream & OS) const704 void AppleAccelTableTypeData::print(raw_ostream &OS) const {
705   OS << "  Offset: " << Die.getOffset() << "\n";
706   OS << "  Tag: " << dwarf::TagString(Die.getTag()) << "\n";
707 }
708 
print(raw_ostream & OS) const709 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
710   OS << "  Static Offset: " << Offset << "\n";
711 }
712 
print(raw_ostream & OS) const713 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
714   OS << "  Static Offset: " << Offset << "\n";
715   OS << "  QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
716   OS << "  Tag: " << dwarf::TagString(Tag) << "\n";
717   OS << "  ObjCClassIsImplementation: "
718      << (ObjCClassIsImplementation ? "true" : "false");
719   OS << "\n";
720 }
721 #endif
722