blob: a1ae137d2668db56c4312f798c15b968655fccf2 [file] [log] [blame]
Jonas Devlieghere855fc3b2018-01-29 14:52:41 +00001//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
Eric Christopher6e472042011-11-07 09:18:42 +00002//
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//
Jonas Devlieghere855fc3b2018-01-29 14:52:41 +000010// This file contains support for writing accelerator tables.
Eric Christopher6e472042011-11-07 09:18:42 +000011//
12//===----------------------------------------------------------------------===//
13
Jonas Devlieghere855fc3b2018-01-29 14:52:41 +000014#include "llvm/CodeGen/AccelTable.h"
Pavel Labath6088c232018-04-04 14:42:14 +000015#include "DwarfCompileUnit.h"
Benjamin Kramer3e6719c2012-03-26 14:17:26 +000016#include "llvm/ADT/STLExtras.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000017#include "llvm/ADT/StringMap.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000018#include "llvm/ADT/Twine.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000019#include "llvm/BinaryFormat/Dwarf.h"
Eric Christopher6e472042011-11-07 09:18:42 +000020#include "llvm/CodeGen/AsmPrinter.h"
Frederic Risse541e0b2015-01-05 21:29:41 +000021#include "llvm/CodeGen/DIE.h"
Eric Christopher6e472042011-11-07 09:18:42 +000022#include "llvm/MC/MCExpr.h"
23#include "llvm/MC/MCStreamer.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000024#include "llvm/Support/raw_ostream.h"
25#include <algorithm>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000026#include <cstddef>
27#include <cstdint>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000028#include <limits>
29#include <vector>
Eric Christopher6e472042011-11-07 09:18:42 +000030
31using namespace llvm;
32
Pavel Labatha7c457d2018-02-19 16:12:20 +000033void AccelTableBase::computeBucketCount() {
34 // First get the number of unique hashes.
35 std::vector<uint32_t> Uniques;
36 Uniques.reserve(Entries.size());
37 for (const auto &E : Entries)
38 Uniques.push_back(E.second.HashValue);
39 array_pod_sort(Uniques.begin(), Uniques.end());
40 std::vector<uint32_t>::iterator P =
41 std::unique(Uniques.begin(), Uniques.end());
42
43 UniqueHashCount = std::distance(Uniques.begin(), P);
44
45 if (UniqueHashCount > 1024)
46 BucketCount = UniqueHashCount / 4;
47 else if (UniqueHashCount > 16)
48 BucketCount = UniqueHashCount / 2;
49 else
50 BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
51}
52
53void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
54 // Create the individual hash data outputs.
55 for (auto &E : Entries) {
56 // Unique the entries.
57 std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
58 [](const AccelTableData *A, const AccelTableData *B) {
59 return *A < *B;
60 });
61 E.second.Values.erase(
62 std::unique(E.second.Values.begin(), E.second.Values.end()),
63 E.second.Values.end());
64 }
65
66 // Figure out how many buckets we need, then compute the bucket contents and
67 // the final ordering. The hashes and offsets can be emitted by walking these
68 // data structures. We add temporary symbols to the data so they can be
69 // referenced when emitting the offsets.
70 computeBucketCount();
71
72 // Compute bucket contents and final ordering.
73 Buckets.resize(BucketCount);
74 for (auto &E : Entries) {
75 uint32_t Bucket = E.second.HashValue % BucketCount;
76 Buckets[Bucket].push_back(&E.second);
77 E.second.Sym = Asm->createTempSymbol(Prefix);
78 }
79
80 // Sort the contents of the buckets by hash value so that hash collisions end
81 // up together. Stable sort makes testing easier and doesn't cost much more.
82 for (auto &Bucket : Buckets)
83 std::stable_sort(Bucket.begin(), Bucket.end(),
84 [](HashData *LHS, HashData *RHS) {
85 return LHS->HashValue < RHS->HashValue;
86 });
87}
88
89namespace {
Pavel Labath6088c232018-04-04 14:42:14 +000090/// Base class for writing out Accelerator tables. It holds the common
91/// functionality for the two Accelerator table types.
Pavel Labatha7c457d2018-02-19 16:12:20 +000092class AccelTableEmitter {
93protected:
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
108public:
109 AccelTableEmitter(AsmPrinter *Asm, const AccelTableBase &Contents,
110 bool SkipIdenticalHashes)
111 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
112 }
113};
114
115class AppleAccelTableEmitter : public AccelTableEmitter {
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
167public:
168 AppleAccelTableEmitter(AsmPrinter *Asm, const AccelTableBase &Contents,
169 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
170 : AccelTableEmitter(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};
Pavel Labath6088c232018-04-04 14:42:14 +0000182
183/// Class responsible for emitting a DWARF v5 Accelerator Table. The only public
184/// function is emit(), which performs the actual emission.
185class Dwarf5AccelTableEmitter : public AccelTableEmitter {
186 struct Header {
187 uint32_t UnitLength = 0;
188 uint16_t Version = 5;
189 uint16_t Padding = 0;
190 uint32_t CompUnitCount;
191 uint32_t LocalTypeUnitCount = 0;
192 uint32_t ForeignTypeUnitCount = 0;
193 uint32_t BucketCount;
194 uint32_t NameCount;
195 uint32_t AbbrevTableSize = 0;
196 uint32_t AugmentationStringSize = sizeof(AugmentationString);
197 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
198
199 Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount)
200 : CompUnitCount(CompUnitCount), BucketCount(BucketCount),
201 NameCount(NameCount) {}
202
203 void emit(const Dwarf5AccelTableEmitter &Ctx) const;
204 };
205 struct AttributeEncoding {
206 dwarf::Index Index;
207 dwarf::Form Form;
208 };
209
210 Header Header;
211 DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
212 const DwarfDebug &DD;
213 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits;
214 MCSymbol *ContributionStart = Asm->createTempSymbol("names_start");
215 MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end");
216 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
217 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
218 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
219
220 DenseSet<uint32_t> getUniqueTags() const;
221
222 // Right now, we emit uniform attributes for all tags.
223 SmallVector<AttributeEncoding, 2> getUniformAttributes() const;
224
225 void emitCUList() const;
226 void emitBuckets() const;
227 void emitStringOffsets() const;
228 void emitAbbrevs() const;
229 void emitEntry(const DWARF5AccelTableData &Data) const;
230 void emitData() const;
231
232public:
233 Dwarf5AccelTableEmitter(
234 AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD,
235 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits);
236
237 void emit() const;
238};
Pavel Labatha7c457d2018-02-19 16:12:20 +0000239} // namespace
240
241void AccelTableEmitter::emitHashes() const {
242 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
243 unsigned BucketIdx = 0;
244 for (auto &Bucket : Contents.getBuckets()) {
245 for (auto &Hash : Bucket) {
246 uint32_t HashValue = Hash->HashValue;
247 if (SkipIdenticalHashes && PrevHash == HashValue)
248 continue;
249 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000250 Asm->emitInt32(HashValue);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000251 PrevHash = HashValue;
252 }
253 BucketIdx++;
254 }
255}
256
257void AccelTableEmitter::emitOffsets(const MCSymbol *Base) const {
258 const auto &Buckets = Contents.getBuckets();
259 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
260 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
261 for (auto *Hash : Buckets[i]) {
262 uint32_t HashValue = Hash->HashValue;
263 if (SkipIdenticalHashes && PrevHash == HashValue)
264 continue;
265 PrevHash = HashValue;
266 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
267 Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t));
268 }
269 }
270}
271
272void AppleAccelTableEmitter::Header::emit(AsmPrinter *Asm) const {
Lang Hames9ff69c82015-04-24 19:11:51 +0000273 Asm->OutStreamer->AddComment("Header Magic");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000274 Asm->emitInt32(Magic);
Lang Hames9ff69c82015-04-24 19:11:51 +0000275 Asm->OutStreamer->AddComment("Header Version");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000276 Asm->emitInt16(Version);
Lang Hames9ff69c82015-04-24 19:11:51 +0000277 Asm->OutStreamer->AddComment("Header Hash Function");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000278 Asm->emitInt16(HashFunction);
Lang Hames9ff69c82015-04-24 19:11:51 +0000279 Asm->OutStreamer->AddComment("Header Bucket Count");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000280 Asm->emitInt32(BucketCount);
Lang Hames9ff69c82015-04-24 19:11:51 +0000281 Asm->OutStreamer->AddComment("Header Hash Count");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000282 Asm->emitInt32(HashCount);
Lang Hames9ff69c82015-04-24 19:11:51 +0000283 Asm->OutStreamer->AddComment("Header Data Length");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000284 Asm->emitInt32(HeaderDataLength);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000285}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000286
Pavel Labatha7c457d2018-02-19 16:12:20 +0000287void AppleAccelTableEmitter::HeaderData::emit(AsmPrinter *Asm) const {
Lang Hames9ff69c82015-04-24 19:11:51 +0000288 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000289 Asm->emitInt32(DieOffsetBase);
Lang Hames9ff69c82015-04-24 19:11:51 +0000290 Asm->OutStreamer->AddComment("HeaderData Atom Count");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000291 Asm->emitInt32(Atoms.size());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000292
Pavel Labatha7c457d2018-02-19 16:12:20 +0000293 for (const Atom &A : Atoms) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000294 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000295 Asm->emitInt16(A.Type);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000296 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000297 Asm->emitInt16(A.Form);
Eric Christopher6e472042011-11-07 09:18:42 +0000298 }
299}
300
Pavel Labatha7c457d2018-02-19 16:12:20 +0000301void AppleAccelTableEmitter::emitBuckets() const {
302 const auto &Buckets = Contents.getBuckets();
Eric Christopher6e472042011-11-07 09:18:42 +0000303 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +0000304 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Lang Hames9ff69c82015-04-24 19:11:51 +0000305 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000306 if (!Buckets[i].empty())
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000307 Asm->emitInt32(index);
Eric Christopher6e472042011-11-07 09:18:42 +0000308 else
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000309 Asm->emitInt32(std::numeric_limits<uint32_t>::max());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000310 // Buckets point in the list of hashes, not to the data. Do not increment
311 // the index multiple times in case of hash collisions.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000312 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000313 for (auto *HD : Buckets[i]) {
314 uint32_t HashValue = HD->HashValue;
315 if (PrevHash != HashValue)
316 ++index;
317 PrevHash = HashValue;
318 }
Eric Christopher6e472042011-11-07 09:18:42 +0000319 }
320}
321
Pavel Labatha7c457d2018-02-19 16:12:20 +0000322void AppleAccelTableEmitter::emitData() const {
323 const auto &Buckets = Contents.getBuckets();
Eric Christopher54ce295d2011-11-08 18:38:40 +0000324 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000325 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000326 for (auto &Hash : Buckets[i]) {
327 // Terminate the previous entry if there is no hash collision with the
328 // current one.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000329 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000330 PrevHash != Hash->HashValue)
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000331 Asm->emitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000332 // Remember to emit the label for our offset.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000333 Asm->OutStreamer->EmitLabel(Hash->Sym);
Pavel Labath062eb532018-02-09 10:06:56 +0000334 Asm->OutStreamer->AddComment(Hash->Name.getString());
335 Asm->emitDwarfStringOffset(Hash->Name);
Lang Hames9ff69c82015-04-24 19:11:51 +0000336 Asm->OutStreamer->AddComment("Num DIEs");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000337 Asm->emitInt32(Hash->Values.size());
Pavel Labatha7c457d2018-02-19 16:12:20 +0000338 for (const auto *V : Hash->Values)
339 static_cast<const AppleAccelTableData *>(V)->emit(Asm);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000340 PrevHash = Hash->HashValue;
Eric Christopher6e472042011-11-07 09:18:42 +0000341 }
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000342 // Emit the final end marker for the bucket.
Frederic Riss44a219f2015-03-10 03:47:55 +0000343 if (!Buckets[i].empty())
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000344 Asm->emitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000345 }
346}
347
Pavel Labatha7c457d2018-02-19 16:12:20 +0000348void AppleAccelTableEmitter::emit() const {
349 Header.emit(Asm);
350 HeaderData.emit(Asm);
351 emitBuckets();
352 emitHashes();
353 emitOffsets(SecBegin);
354 emitData();
Eric Christopher6e472042011-11-07 09:18:42 +0000355}
356
Pavel Labath6088c232018-04-04 14:42:14 +0000357void Dwarf5AccelTableEmitter::Header::emit(
358 const Dwarf5AccelTableEmitter &Ctx) const {
Pavel Labatheadfac82018-04-09 14:38:53 +0000359 assert(CompUnitCount > 0 && "Index must have at least one CU.");
360
Pavel Labath6088c232018-04-04 14:42:14 +0000361 AsmPrinter *Asm = Ctx.Asm;
362 Asm->OutStreamer->AddComment("Header: unit length");
363 Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart,
364 sizeof(uint32_t));
365 Asm->OutStreamer->EmitLabel(Ctx.ContributionStart);
366 Asm->OutStreamer->AddComment("Header: version");
367 Asm->emitInt16(Version);
368 Asm->OutStreamer->AddComment("Header: padding");
369 Asm->emitInt16(Padding);
370 Asm->OutStreamer->AddComment("Header: compilation unit count");
371 Asm->emitInt32(CompUnitCount);
372 Asm->OutStreamer->AddComment("Header: local type unit count");
373 Asm->emitInt32(LocalTypeUnitCount);
374 Asm->OutStreamer->AddComment("Header: foreign type unit count");
375 Asm->emitInt32(ForeignTypeUnitCount);
376 Asm->OutStreamer->AddComment("Header: bucket count");
377 Asm->emitInt32(BucketCount);
378 Asm->OutStreamer->AddComment("Header: name count");
379 Asm->emitInt32(NameCount);
380 Asm->OutStreamer->AddComment("Header: abbreviation table size");
381 Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
382 Asm->OutStreamer->AddComment("Header: augmentation string size");
383 assert(AugmentationStringSize % 4 == 0);
384 Asm->emitInt32(AugmentationStringSize);
385 Asm->OutStreamer->AddComment("Header: augmentation string");
386 Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize});
387}
388
389DenseSet<uint32_t> Dwarf5AccelTableEmitter::getUniqueTags() const {
390 DenseSet<uint32_t> UniqueTags;
391 for (auto &Bucket : Contents.getBuckets()) {
392 for (auto *Hash : Bucket) {
393 for (auto *Value : Hash->Values) {
394 const DIE &Die =
395 static_cast<const DWARF5AccelTableData *>(Value)->getDie();
396 UniqueTags.insert(Die.getTag());
397 }
398 }
399 }
400 return UniqueTags;
401}
402
403SmallVector<Dwarf5AccelTableEmitter::AttributeEncoding, 2>
404Dwarf5AccelTableEmitter::getUniformAttributes() const {
405 SmallVector<AttributeEncoding, 2> UA;
406 if (CompUnits.size() > 1) {
407 size_t LargestCUIndex = CompUnits.size() - 1;
408 dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex);
409 UA.push_back({dwarf::DW_IDX_compile_unit, Form});
410 }
411 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
412 return UA;
413}
414
415void Dwarf5AccelTableEmitter::emitCUList() const {
416 for (const auto &CU : enumerate(CompUnits)) {
417 assert(CU.index() == CU.value()->getUniqueID());
418 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
Pavel Labath3fb39c72018-04-18 12:11:59 +0000419 const DwarfCompileUnit *MainCU =
420 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
421 Asm->emitDwarfSymbolReference(MainCU->getLabelBegin());
Pavel Labath6088c232018-04-04 14:42:14 +0000422 }
423}
424
425void Dwarf5AccelTableEmitter::emitBuckets() const {
426 uint32_t Index = 1;
427 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
428 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
429 Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
430 Index += Bucket.value().size();
431 }
432}
433
434void Dwarf5AccelTableEmitter::emitStringOffsets() const {
435 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
436 for (auto *Hash : Bucket.value()) {
437 DwarfStringPoolEntryRef String = Hash->Name;
438 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
439 ": " + String.getString());
440 Asm->emitDwarfStringOffset(String);
441 }
442 }
443}
444
445void Dwarf5AccelTableEmitter::emitAbbrevs() const {
446 Asm->OutStreamer->EmitLabel(AbbrevStart);
447 for (const auto &Abbrev : Abbreviations) {
448 Asm->OutStreamer->AddComment("Abbrev code");
449 assert(Abbrev.first != 0);
450 Asm->EmitULEB128(Abbrev.first);
451 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first));
452 Asm->EmitULEB128(Abbrev.first);
453 for (const auto &AttrEnc : Abbrev.second) {
454 Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
455 Asm->EmitULEB128(AttrEnc.Form,
456 dwarf::FormEncodingString(AttrEnc.Form).data());
457 }
458 Asm->EmitULEB128(0, "End of abbrev");
459 Asm->EmitULEB128(0, "End of abbrev");
460 }
461 Asm->EmitULEB128(0, "End of abbrev list");
462 Asm->OutStreamer->EmitLabel(AbbrevEnd);
463}
464
465void Dwarf5AccelTableEmitter::emitEntry(
466 const DWARF5AccelTableData &Entry) const {
467 auto AbbrevIt = Abbreviations.find(Entry.getDie().getTag());
468 assert(AbbrevIt != Abbreviations.end() &&
469 "Why wasn't this abbrev generated?");
470
471 Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code");
472 for (const auto &AttrEnc : AbbrevIt->second) {
473 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
474 switch (AttrEnc.Index) {
475 case dwarf::DW_IDX_compile_unit: {
476 const DIE *CUDie = Entry.getDie().getUnitDie();
477 DIEInteger ID(DD.lookupCU(CUDie)->getUniqueID());
478 ID.EmitValue(Asm, AttrEnc.Form);
479 break;
480 }
481 case dwarf::DW_IDX_die_offset:
482 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
483 Asm->emitInt32(Entry.getDie().getOffset());
484 break;
485 default:
486 llvm_unreachable("Unexpected index attribute!");
487 }
488 }
489}
490
491void Dwarf5AccelTableEmitter::emitData() const {
492 Asm->OutStreamer->EmitLabel(EntryPool);
493 for (auto &Bucket : Contents.getBuckets()) {
494 for (auto *Hash : Bucket) {
495 // Remember to emit the label for our offset.
496 Asm->OutStreamer->EmitLabel(Hash->Sym);
497 for (const auto *Value : Hash->Values)
498 emitEntry(*static_cast<const DWARF5AccelTableData *>(Value));
499 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
500 Asm->emitInt32(0);
501 }
502 }
503}
504
505Dwarf5AccelTableEmitter::Dwarf5AccelTableEmitter(
506 AsmPrinter *Asm, const AccelTableBase &Contents, const DwarfDebug &DD,
507 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits)
508 : AccelTableEmitter(Asm, Contents, false),
509 Header(CompUnits.size(), Contents.getBucketCount(),
510 Contents.getUniqueNameCount()),
511 DD(DD), CompUnits(CompUnits) {
512 DenseSet<uint32_t> UniqueTags = getUniqueTags();
513 SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();
514
515 Abbreviations.reserve(UniqueTags.size());
516 for (uint32_t Tag : UniqueTags)
517 Abbreviations.try_emplace(Tag, UniformAttributes);
518}
519
520void Dwarf5AccelTableEmitter::emit() const {
521 Header.emit(*this);
522 emitCUList();
523 emitBuckets();
524 emitHashes();
525 emitStringOffsets();
526 emitOffsets(EntryPool);
527 emitAbbrevs();
528 emitData();
529 Asm->OutStreamer->EmitValueToAlignment(4, 0);
530 Asm->OutStreamer->EmitLabel(ContributionEnd);
531}
532
Pavel Labatha7c457d2018-02-19 16:12:20 +0000533void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
534 StringRef Prefix, const MCSymbol *SecBegin,
535 ArrayRef<AppleAccelTableData::Atom> Atoms) {
536 Contents.finalize(Asm, Prefix);
537 AppleAccelTableEmitter(Asm, Contents, Atoms, SecBegin).emit();
Eric Christopher6e472042011-11-07 09:18:42 +0000538}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000539
Pavel Labath6088c232018-04-04 14:42:14 +0000540void llvm::emitDWARF5AccelTable(
541 AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
542 const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
543 Contents.finalize(Asm, "names");
544 Dwarf5AccelTableEmitter(Asm, Contents, DD, CUs).emit();
545}
546
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000547void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000548 Asm->emitInt32(Die->getDebugSectionOffset());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000549}
550
551void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000552 Asm->emitInt32(Die->getDebugSectionOffset());
553 Asm->emitInt16(Die->getTag());
554 Asm->emitInt8(0);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000555}
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000556
557void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000558 Asm->emitInt32(Offset);
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000559}
560
561void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000562 Asm->emitInt32(Offset);
563 Asm->emitInt16(Tag);
564 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000565 : 0);
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000566 Asm->emitInt32(QualifiedNameHash);
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000567}
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000568
569#ifndef _MSC_VER
570// The lines below are rejected by older versions (TBD) of MSVC.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000571constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
572constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
573constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
574constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000575#else
576// FIXME: Erase this path once the minimum MSCV version has been bumped.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000577const SmallVector<AppleAccelTableData::Atom, 4>
578 AppleAccelTableOffsetData::Atoms = {
579 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
580const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms =
581 {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
582 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
583 Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
584const SmallVector<AppleAccelTableData::Atom, 4>
585 AppleAccelTableStaticOffsetData::Atoms = {
586 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
587const SmallVector<AppleAccelTableData::Atom, 4>
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000588 AppleAccelTableStaticTypeData::Atoms = {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000589 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
590 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
591 Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000592#endif
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000593
594#ifndef NDEBUG
Pavel Labatha7c457d2018-02-19 16:12:20 +0000595void AppleAccelTableEmitter::Header::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000596 OS << "Magic: " << format("0x%x", Magic) << "\n"
597 << "Version: " << Version << "\n"
598 << "Hash Function: " << HashFunction << "\n"
599 << "Bucket Count: " << BucketCount << "\n"
600 << "Header Data Length: " << HeaderDataLength << "\n";
601}
602
Pavel Labatha7c457d2018-02-19 16:12:20 +0000603void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000604 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
605 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
606}
607
Pavel Labatha7c457d2018-02-19 16:12:20 +0000608void AppleAccelTableEmitter::HeaderData::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000609 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
610 for (auto Atom : Atoms)
611 Atom.print(OS);
612}
613
Pavel Labatha7c457d2018-02-19 16:12:20 +0000614void AppleAccelTableEmitter::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000615 Header.print(OS);
616 HeaderData.print(OS);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000617 Contents.print(OS);
618 SecBegin->print(OS, nullptr);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000619}
620
Pavel Labatha7c457d2018-02-19 16:12:20 +0000621void AccelTableBase::HashData::print(raw_ostream &OS) const {
Pavel Labath062eb532018-02-09 10:06:56 +0000622 OS << "Name: " << Name.getString() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000623 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
624 OS << " Symbol: ";
625 if (Sym)
626 OS << *Sym;
627 else
628 OS << "<none>";
629 OS << "\n";
Pavel Labath062eb532018-02-09 10:06:56 +0000630 for (auto *Value : Values)
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000631 Value->print(OS);
632}
633
Pavel Labatha7c457d2018-02-19 16:12:20 +0000634void AccelTableBase::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000635 // Print Content.
636 OS << "Entries: \n";
637 for (const auto &Entry : Entries) {
638 OS << "Name: " << Entry.first() << "\n";
639 for (auto *V : Entry.second.Values)
640 V->print(OS);
641 }
642
643 OS << "Buckets and Hashes: \n";
644 for (auto &Bucket : Buckets)
645 for (auto &Hash : Bucket)
646 Hash->print(OS);
647
648 OS << "Data: \n";
Pavel Labath062eb532018-02-09 10:06:56 +0000649 for (auto &E : Entries)
650 E.second.print(OS);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000651}
652
Pavel Labath6088c232018-04-04 14:42:14 +0000653void DWARF5AccelTableData::print(raw_ostream &OS) const {
654 OS << " Offset: " << Die.getOffset() << "\n";
655 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
656}
657
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000658void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
659 OS << " Offset: " << Die->getOffset() << "\n";
660}
661
662void AppleAccelTableTypeData::print(raw_ostream &OS) const {
663 OS << " Offset: " << Die->getOffset() << "\n";
664 OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n";
665}
666
667void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
668 OS << " Static Offset: " << Offset << "\n";
669}
670
671void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
672 OS << " Static Offset: " << Offset << "\n";
673 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
674 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
675 OS << " ObjCClassIsImplementation: "
676 << (ObjCClassIsImplementation ? "true" : "false");
677 OS << "\n";
678}
679#endif