blob: 119f65e33f5af106fd49cf080f04bed738ec3e2d [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"
Jonas Devlieghere98062cb2018-07-16 10:52:27 +000024#include "llvm/MC/MCSymbol.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000025#include "llvm/Support/raw_ostream.h"
David Blaikie66cf14d2018-08-16 21:29:55 +000026#include "llvm/Target/TargetLoweringObjectFile.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000027#include <algorithm>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000028#include <cstddef>
29#include <cstdint>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000030#include <limits>
31#include <vector>
Eric Christopher6e472042011-11-07 09:18:42 +000032
33using namespace llvm;
34
Pavel Labatha7c457d2018-02-19 16:12:20 +000035void AccelTableBase::computeBucketCount() {
36 // First get the number of unique hashes.
37 std::vector<uint32_t> Uniques;
38 Uniques.reserve(Entries.size());
39 for (const auto &E : Entries)
40 Uniques.push_back(E.second.HashValue);
41 array_pod_sort(Uniques.begin(), Uniques.end());
42 std::vector<uint32_t>::iterator P =
43 std::unique(Uniques.begin(), Uniques.end());
44
45 UniqueHashCount = std::distance(Uniques.begin(), P);
46
47 if (UniqueHashCount > 1024)
48 BucketCount = UniqueHashCount / 4;
49 else if (UniqueHashCount > 16)
50 BucketCount = UniqueHashCount / 2;
51 else
52 BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
53}
54
55void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
56 // Create the individual hash data outputs.
57 for (auto &E : Entries) {
58 // Unique the entries.
59 std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
60 [](const AccelTableData *A, const AccelTableData *B) {
61 return *A < *B;
62 });
63 E.second.Values.erase(
64 std::unique(E.second.Values.begin(), E.second.Values.end()),
65 E.second.Values.end());
66 }
67
68 // Figure out how many buckets we need, then compute the bucket contents and
69 // the final ordering. The hashes and offsets can be emitted by walking these
70 // data structures. We add temporary symbols to the data so they can be
71 // referenced when emitting the offsets.
72 computeBucketCount();
73
74 // Compute bucket contents and final ordering.
75 Buckets.resize(BucketCount);
76 for (auto &E : Entries) {
77 uint32_t Bucket = E.second.HashValue % BucketCount;
78 Buckets[Bucket].push_back(&E.second);
79 E.second.Sym = Asm->createTempSymbol(Prefix);
80 }
81
82 // Sort the contents of the buckets by hash value so that hash collisions end
83 // up together. Stable sort makes testing easier and doesn't cost much more.
84 for (auto &Bucket : Buckets)
85 std::stable_sort(Bucket.begin(), Bucket.end(),
86 [](HashData *LHS, HashData *RHS) {
87 return LHS->HashValue < RHS->HashValue;
88 });
89}
90
91namespace {
Pavel Labath6088c232018-04-04 14:42:14 +000092/// Base class for writing out Accelerator tables. It holds the common
93/// functionality for the two Accelerator table types.
Jonas Devliegheree60ca772018-07-09 08:47:38 +000094class AccelTableWriter {
Pavel Labatha7c457d2018-02-19 16:12:20 +000095protected:
96 AsmPrinter *const Asm; ///< Destination.
97 const AccelTableBase &Contents; ///< Data to emit.
98
99 /// Controls whether to emit duplicate hash and offset table entries for names
100 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
101 /// tables do.
102 const bool SkipIdenticalHashes;
103
104 void emitHashes() const;
105
106 /// Emit offsets to lists of entries with identical names. The offsets are
107 /// relative to the Base argument.
108 void emitOffsets(const MCSymbol *Base) const;
109
110public:
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000111 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
112 bool SkipIdenticalHashes)
Pavel Labatha7c457d2018-02-19 16:12:20 +0000113 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
114 }
115};
116
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000117class AppleAccelTableWriter : public AccelTableWriter {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000118 using Atom = AppleAccelTableData::Atom;
119
120 /// The fixed header of an Apple Accelerator Table.
121 struct Header {
122 uint32_t Magic = MagicHash;
123 uint16_t Version = 1;
124 uint16_t HashFunction = dwarf::DW_hash_function_djb;
125 uint32_t BucketCount;
126 uint32_t HashCount;
127 uint32_t HeaderDataLength;
128
129 /// 'HASH' magic value to detect endianness.
130 static const uint32_t MagicHash = 0x48415348;
131
132 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
133 : BucketCount(BucketCount), HashCount(UniqueHashCount),
134 HeaderDataLength(DataLength) {}
135
136 void emit(AsmPrinter *Asm) const;
137#ifndef NDEBUG
138 void print(raw_ostream &OS) const;
139 void dump() const { print(dbgs()); }
140#endif
141 };
142
143 /// The HeaderData describes the structure of an Apple accelerator table
144 /// through a list of Atoms.
145 struct HeaderData {
146 /// In the case of data that is referenced via DW_FORM_ref_* the offset
147 /// base is used to describe the offset for all forms in the list of atoms.
148 uint32_t DieOffsetBase;
149
150 const SmallVector<Atom, 4> Atoms;
151
152 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
153 : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
154
155 void emit(AsmPrinter *Asm) const;
156#ifndef NDEBUG
157 void print(raw_ostream &OS) const;
158 void dump() const { print(dbgs()); }
159#endif
160 };
161
162 Header Header;
163 HeaderData HeaderData;
164 const MCSymbol *SecBegin;
165
166 void emitBuckets() const;
167 void emitData() const;
168
169public:
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000170 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
171 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
172 : AccelTableWriter(Asm, Contents, true),
Pavel Labatha7c457d2018-02-19 16:12:20 +0000173 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
174 8 + (Atoms.size() * 4)),
175 HeaderData(Atoms), SecBegin(SecBegin) {}
176
177 void emit() const;
178
179#ifndef NDEBUG
180 void print(raw_ostream &OS) const;
181 void dump() const { print(dbgs()); }
182#endif
183};
Pavel Labath6088c232018-04-04 14:42:14 +0000184
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000185/// Class responsible for emitting a DWARF v5 Accelerator Table. The only
186/// public function is emit(), which performs the actual emission.
187///
188/// The class is templated in its data type. This allows us to emit both dyamic
189/// and static data entries. A callback abstract the logic to provide a CU
190/// index for a given entry, which is different per data type, but identical
191/// for every entry in the same table.
192template <typename DataT>
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000193class Dwarf5AccelTableWriter : public AccelTableWriter {
Pavel Labath6088c232018-04-04 14:42:14 +0000194 struct Header {
195 uint32_t UnitLength = 0;
196 uint16_t Version = 5;
197 uint16_t Padding = 0;
198 uint32_t CompUnitCount;
199 uint32_t LocalTypeUnitCount = 0;
200 uint32_t ForeignTypeUnitCount = 0;
201 uint32_t BucketCount;
202 uint32_t NameCount;
203 uint32_t AbbrevTableSize = 0;
204 uint32_t AugmentationStringSize = sizeof(AugmentationString);
205 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
206
207 Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount)
208 : CompUnitCount(CompUnitCount), BucketCount(BucketCount),
209 NameCount(NameCount) {}
210
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000211 void emit(const Dwarf5AccelTableWriter &Ctx) const;
Pavel Labath6088c232018-04-04 14:42:14 +0000212 };
213 struct AttributeEncoding {
214 dwarf::Index Index;
215 dwarf::Form Form;
216 };
217
218 Header Header;
219 DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000220 ArrayRef<MCSymbol *> CompUnits;
221 llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry;
Pavel Labath6088c232018-04-04 14:42:14 +0000222 MCSymbol *ContributionStart = Asm->createTempSymbol("names_start");
223 MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end");
224 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
225 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
226 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
227
228 DenseSet<uint32_t> getUniqueTags() const;
229
230 // Right now, we emit uniform attributes for all tags.
231 SmallVector<AttributeEncoding, 2> getUniformAttributes() const;
232
233 void emitCUList() const;
234 void emitBuckets() const;
235 void emitStringOffsets() const;
236 void emitAbbrevs() const;
Fangrui Songcb0bab82018-07-16 18:51:40 +0000237 void emitEntry(const DataT &Entry) const;
Pavel Labath6088c232018-04-04 14:42:14 +0000238 void emitData() const;
239
240public:
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000241 Dwarf5AccelTableWriter(
242 AsmPrinter *Asm, const AccelTableBase &Contents,
243 ArrayRef<MCSymbol *> CompUnits,
244 llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry);
Pavel Labath6088c232018-04-04 14:42:14 +0000245
246 void emit() const;
247};
Pavel Labatha7c457d2018-02-19 16:12:20 +0000248} // namespace
249
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000250void AccelTableWriter::emitHashes() const {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000251 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
252 unsigned BucketIdx = 0;
253 for (auto &Bucket : Contents.getBuckets()) {
254 for (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));
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000259 Asm->emitInt32(HashValue);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000260 PrevHash = HashValue;
261 }
262 BucketIdx++;
263 }
264}
265
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000266void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000267 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, sizeof(uint32_t));
277 }
278 }
279}
280
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000281void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
Lang Hames9ff69c82015-04-24 19:11:51 +0000282 Asm->OutStreamer->AddComment("Header Magic");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000283 Asm->emitInt32(Magic);
Lang Hames9ff69c82015-04-24 19:11:51 +0000284 Asm->OutStreamer->AddComment("Header Version");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000285 Asm->emitInt16(Version);
Lang Hames9ff69c82015-04-24 19:11:51 +0000286 Asm->OutStreamer->AddComment("Header Hash Function");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000287 Asm->emitInt16(HashFunction);
Lang Hames9ff69c82015-04-24 19:11:51 +0000288 Asm->OutStreamer->AddComment("Header Bucket Count");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000289 Asm->emitInt32(BucketCount);
Lang Hames9ff69c82015-04-24 19:11:51 +0000290 Asm->OutStreamer->AddComment("Header Hash Count");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000291 Asm->emitInt32(HashCount);
Lang Hames9ff69c82015-04-24 19:11:51 +0000292 Asm->OutStreamer->AddComment("Header Data Length");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000293 Asm->emitInt32(HeaderDataLength);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000294}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000295
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000296void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
Lang Hames9ff69c82015-04-24 19:11:51 +0000297 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000298 Asm->emitInt32(DieOffsetBase);
Lang Hames9ff69c82015-04-24 19:11:51 +0000299 Asm->OutStreamer->AddComment("HeaderData Atom Count");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000300 Asm->emitInt32(Atoms.size());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000301
Pavel Labatha7c457d2018-02-19 16:12:20 +0000302 for (const Atom &A : Atoms) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000303 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000304 Asm->emitInt16(A.Type);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000305 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000306 Asm->emitInt16(A.Form);
Eric Christopher6e472042011-11-07 09:18:42 +0000307 }
308}
309
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000310void AppleAccelTableWriter::emitBuckets() const {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000311 const auto &Buckets = Contents.getBuckets();
Eric Christopher6e472042011-11-07 09:18:42 +0000312 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +0000313 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Lang Hames9ff69c82015-04-24 19:11:51 +0000314 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000315 if (!Buckets[i].empty())
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000316 Asm->emitInt32(index);
Eric Christopher6e472042011-11-07 09:18:42 +0000317 else
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000318 Asm->emitInt32(std::numeric_limits<uint32_t>::max());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000319 // Buckets point in the list of hashes, not to the data. Do not increment
320 // the index multiple times in case of hash collisions.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000321 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000322 for (auto *HD : Buckets[i]) {
323 uint32_t HashValue = HD->HashValue;
324 if (PrevHash != HashValue)
325 ++index;
326 PrevHash = HashValue;
327 }
Eric Christopher6e472042011-11-07 09:18:42 +0000328 }
329}
330
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000331void AppleAccelTableWriter::emitData() const {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000332 const auto &Buckets = Contents.getBuckets();
Eric Christopher54ce295d2011-11-08 18:38:40 +0000333 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000334 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000335 for (auto &Hash : Buckets[i]) {
336 // Terminate the previous entry if there is no hash collision with the
337 // current one.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000338 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000339 PrevHash != Hash->HashValue)
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000340 Asm->emitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000341 // Remember to emit the label for our offset.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000342 Asm->OutStreamer->EmitLabel(Hash->Sym);
Pavel Labath062eb532018-02-09 10:06:56 +0000343 Asm->OutStreamer->AddComment(Hash->Name.getString());
344 Asm->emitDwarfStringOffset(Hash->Name);
Lang Hames9ff69c82015-04-24 19:11:51 +0000345 Asm->OutStreamer->AddComment("Num DIEs");
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000346 Asm->emitInt32(Hash->Values.size());
Pavel Labatha7c457d2018-02-19 16:12:20 +0000347 for (const auto *V : Hash->Values)
348 static_cast<const AppleAccelTableData *>(V)->emit(Asm);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000349 PrevHash = Hash->HashValue;
Eric Christopher6e472042011-11-07 09:18:42 +0000350 }
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000351 // Emit the final end marker for the bucket.
Frederic Riss44a219f2015-03-10 03:47:55 +0000352 if (!Buckets[i].empty())
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000353 Asm->emitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000354 }
355}
356
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000357void AppleAccelTableWriter::emit() const {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000358 Header.emit(Asm);
359 HeaderData.emit(Asm);
360 emitBuckets();
361 emitHashes();
362 emitOffsets(SecBegin);
363 emitData();
Eric Christopher6e472042011-11-07 09:18:42 +0000364}
365
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000366template <typename DataT>
367void Dwarf5AccelTableWriter<DataT>::Header::emit(
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000368 const Dwarf5AccelTableWriter &Ctx) const {
Pavel Labatheadfac82018-04-09 14:38:53 +0000369 assert(CompUnitCount > 0 && "Index must have at least one CU.");
370
Pavel Labath6088c232018-04-04 14:42:14 +0000371 AsmPrinter *Asm = Ctx.Asm;
372 Asm->OutStreamer->AddComment("Header: unit length");
373 Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart,
374 sizeof(uint32_t));
375 Asm->OutStreamer->EmitLabel(Ctx.ContributionStart);
376 Asm->OutStreamer->AddComment("Header: version");
377 Asm->emitInt16(Version);
378 Asm->OutStreamer->AddComment("Header: padding");
379 Asm->emitInt16(Padding);
380 Asm->OutStreamer->AddComment("Header: compilation unit count");
381 Asm->emitInt32(CompUnitCount);
382 Asm->OutStreamer->AddComment("Header: local type unit count");
383 Asm->emitInt32(LocalTypeUnitCount);
384 Asm->OutStreamer->AddComment("Header: foreign type unit count");
385 Asm->emitInt32(ForeignTypeUnitCount);
386 Asm->OutStreamer->AddComment("Header: bucket count");
387 Asm->emitInt32(BucketCount);
388 Asm->OutStreamer->AddComment("Header: name count");
389 Asm->emitInt32(NameCount);
390 Asm->OutStreamer->AddComment("Header: abbreviation table size");
391 Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
392 Asm->OutStreamer->AddComment("Header: augmentation string size");
393 assert(AugmentationStringSize % 4 == 0);
394 Asm->emitInt32(AugmentationStringSize);
395 Asm->OutStreamer->AddComment("Header: augmentation string");
396 Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize});
397}
398
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000399template <typename DataT>
400DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000401 DenseSet<uint32_t> UniqueTags;
402 for (auto &Bucket : Contents.getBuckets()) {
403 for (auto *Hash : Bucket) {
404 for (auto *Value : Hash->Values) {
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000405 unsigned Tag = static_cast<const DataT *>(Value)->getDieTag();
406 UniqueTags.insert(Tag);
Pavel Labath6088c232018-04-04 14:42:14 +0000407 }
408 }
409 }
410 return UniqueTags;
411}
412
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000413template <typename DataT>
414SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2>
415Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000416 SmallVector<AttributeEncoding, 2> UA;
Jonas Devlieghere3192e352018-07-10 16:18:56 +0000417 if (CompUnits.size() > 1) {
418 size_t LargestCUIndex = CompUnits.size() - 1;
Pavel Labath6088c232018-04-04 14:42:14 +0000419 dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex);
420 UA.push_back({dwarf::DW_IDX_compile_unit, Form});
421 }
422 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
423 return UA;
424}
425
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000426template <typename DataT>
427void Dwarf5AccelTableWriter<DataT>::emitCUList() const {
Jonas Devlieghere3192e352018-07-10 16:18:56 +0000428 for (const auto &CU : enumerate(CompUnits)) {
Jonas Devlieghere3192e352018-07-10 16:18:56 +0000429 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000430 Asm->emitDwarfSymbolReference(CU.value());
Pavel Labath6088c232018-04-04 14:42:14 +0000431 }
432}
433
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000434template <typename DataT>
435void Dwarf5AccelTableWriter<DataT>::emitBuckets() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000436 uint32_t Index = 1;
437 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
438 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
439 Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
440 Index += Bucket.value().size();
441 }
442}
443
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000444template <typename DataT>
445void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000446 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
447 for (auto *Hash : Bucket.value()) {
448 DwarfStringPoolEntryRef String = Hash->Name;
449 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
450 ": " + String.getString());
451 Asm->emitDwarfStringOffset(String);
452 }
453 }
454}
455
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000456template <typename DataT>
457void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000458 Asm->OutStreamer->EmitLabel(AbbrevStart);
459 for (const auto &Abbrev : Abbreviations) {
460 Asm->OutStreamer->AddComment("Abbrev code");
461 assert(Abbrev.first != 0);
462 Asm->EmitULEB128(Abbrev.first);
463 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first));
464 Asm->EmitULEB128(Abbrev.first);
465 for (const auto &AttrEnc : Abbrev.second) {
466 Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
467 Asm->EmitULEB128(AttrEnc.Form,
468 dwarf::FormEncodingString(AttrEnc.Form).data());
469 }
470 Asm->EmitULEB128(0, "End of abbrev");
471 Asm->EmitULEB128(0, "End of abbrev");
472 }
473 Asm->EmitULEB128(0, "End of abbrev list");
474 Asm->OutStreamer->EmitLabel(AbbrevEnd);
475}
476
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000477template <typename DataT>
478void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
479 auto AbbrevIt = Abbreviations.find(Entry.getDieTag());
Pavel Labath6088c232018-04-04 14:42:14 +0000480 assert(AbbrevIt != Abbreviations.end() &&
481 "Why wasn't this abbrev generated?");
482
483 Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code");
484 for (const auto &AttrEnc : AbbrevIt->second) {
485 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
486 switch (AttrEnc.Index) {
487 case dwarf::DW_IDX_compile_unit: {
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000488 DIEInteger ID(getCUIndexForEntry(Entry));
Pavel Labath6088c232018-04-04 14:42:14 +0000489 ID.EmitValue(Asm, AttrEnc.Form);
490 break;
491 }
492 case dwarf::DW_IDX_die_offset:
493 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000494 Asm->emitInt32(Entry.getDieOffset());
Pavel Labath6088c232018-04-04 14:42:14 +0000495 break;
496 default:
497 llvm_unreachable("Unexpected index attribute!");
498 }
499 }
500}
501
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000502template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000503 Asm->OutStreamer->EmitLabel(EntryPool);
504 for (auto &Bucket : Contents.getBuckets()) {
505 for (auto *Hash : Bucket) {
506 // Remember to emit the label for our offset.
507 Asm->OutStreamer->EmitLabel(Hash->Sym);
508 for (const auto *Value : Hash->Values)
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000509 emitEntry(*static_cast<const DataT *>(Value));
Pavel Labath6088c232018-04-04 14:42:14 +0000510 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
511 Asm->emitInt32(0);
512 }
513 }
514}
515
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000516template <typename DataT>
517Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter(
518 AsmPrinter *Asm, const AccelTableBase &Contents,
519 ArrayRef<MCSymbol *> CompUnits,
520 llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry)
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000521 : AccelTableWriter(Asm, Contents, false),
Jonas Devlieghere3192e352018-07-10 16:18:56 +0000522 Header(CompUnits.size(), Contents.getBucketCount(),
Pavel Labath6088c232018-04-04 14:42:14 +0000523 Contents.getUniqueNameCount()),
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000524 CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) {
Pavel Labath6088c232018-04-04 14:42:14 +0000525 DenseSet<uint32_t> UniqueTags = getUniqueTags();
526 SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();
527
528 Abbreviations.reserve(UniqueTags.size());
529 for (uint32_t Tag : UniqueTags)
530 Abbreviations.try_emplace(Tag, UniformAttributes);
531}
532
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000533template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() const {
Pavel Labath6088c232018-04-04 14:42:14 +0000534 Header.emit(*this);
535 emitCUList();
536 emitBuckets();
537 emitHashes();
538 emitStringOffsets();
539 emitOffsets(EntryPool);
540 emitAbbrevs();
541 emitData();
542 Asm->OutStreamer->EmitValueToAlignment(4, 0);
543 Asm->OutStreamer->EmitLabel(ContributionEnd);
544}
545
Pavel Labatha7c457d2018-02-19 16:12:20 +0000546void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
547 StringRef Prefix, const MCSymbol *SecBegin,
548 ArrayRef<AppleAccelTableData::Atom> Atoms) {
549 Contents.finalize(Asm, Prefix);
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000550 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
Eric Christopher6e472042011-11-07 09:18:42 +0000551}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000552
Pavel Labath6088c232018-04-04 14:42:14 +0000553void llvm::emitDWARF5AccelTable(
554 AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
555 const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000556 std::vector<MCSymbol *> CompUnits;
557 for (const auto &CU : enumerate(CUs)) {
David Blaikie66cf14d2018-08-16 21:29:55 +0000558 if (CU.value()->getCUNode()->getNameTableKind() ==
559 DICompileUnit::DebugNameTableKind::None)
560 continue;
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000561 assert(CU.index() == CU.value()->getUniqueID());
562 const DwarfCompileUnit *MainCU =
563 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
564 CompUnits.push_back(MainCU->getLabelBegin());
565 }
566
David Blaikie66cf14d2018-08-16 21:29:55 +0000567 if (CompUnits.empty())
568 return;
569
570 Asm->OutStreamer->SwitchSection(
571 Asm->getObjFileLowering().getDwarfDebugNamesSection());
572
Pavel Labath6088c232018-04-04 14:42:14 +0000573 Contents.finalize(Asm, "names");
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000574 Dwarf5AccelTableWriter<DWARF5AccelTableData>(
575 Asm, Contents, CompUnits,
576 [&DD](const DWARF5AccelTableData &Entry) {
577 const DIE *CUDie = Entry.getDie().getUnitDie();
578 return DD.lookupCU(CUDie)->getUniqueID();
579 })
580 .emit();
581}
582
583void llvm::emitDWARF5AccelTable(
584 AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
585 ArrayRef<MCSymbol *> CUs,
586 llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
587 getCUIndexForEntry) {
588 Contents.finalize(Asm, "names");
589 Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs,
590 getCUIndexForEntry)
591 .emit();
Pavel Labath6088c232018-04-04 14:42:14 +0000592}
593
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000594void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
Pavel Labath7f7e6062018-07-20 15:24:13 +0000595 Asm->emitInt32(Die.getDebugSectionOffset());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000596}
597
598void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
Pavel Labath7f7e6062018-07-20 15:24:13 +0000599 Asm->emitInt32(Die.getDebugSectionOffset());
600 Asm->emitInt16(Die.getTag());
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000601 Asm->emitInt8(0);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000602}
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000603
604void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000605 Asm->emitInt32(Offset);
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000606}
607
608void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000609 Asm->emitInt32(Offset);
610 Asm->emitInt16(Tag);
611 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000612 : 0);
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000613 Asm->emitInt32(QualifiedNameHash);
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000614}
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000615
616#ifndef _MSC_VER
617// The lines below are rejected by older versions (TBD) of MSVC.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000618constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
619constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
620constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
621constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000622#else
623// FIXME: Erase this path once the minimum MSCV version has been bumped.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000624const SmallVector<AppleAccelTableData::Atom, 4>
625 AppleAccelTableOffsetData::Atoms = {
626 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
627const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms =
628 {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
629 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
630 Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
631const SmallVector<AppleAccelTableData::Atom, 4>
632 AppleAccelTableStaticOffsetData::Atoms = {
633 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
634const SmallVector<AppleAccelTableData::Atom, 4>
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000635 AppleAccelTableStaticTypeData::Atoms = {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000636 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
637 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
638 Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000639#endif
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000640
641#ifndef NDEBUG
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000642void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000643 OS << "Magic: " << format("0x%x", Magic) << "\n"
644 << "Version: " << Version << "\n"
645 << "Hash Function: " << HashFunction << "\n"
646 << "Bucket Count: " << BucketCount << "\n"
647 << "Header Data Length: " << HeaderDataLength << "\n";
648}
649
Pavel Labatha7c457d2018-02-19 16:12:20 +0000650void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000651 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
652 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
653}
654
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000655void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000656 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
657 for (auto Atom : Atoms)
658 Atom.print(OS);
659}
660
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000661void AppleAccelTableWriter::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000662 Header.print(OS);
663 HeaderData.print(OS);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000664 Contents.print(OS);
665 SecBegin->print(OS, nullptr);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000666}
667
Pavel Labatha7c457d2018-02-19 16:12:20 +0000668void AccelTableBase::HashData::print(raw_ostream &OS) const {
Pavel Labath062eb532018-02-09 10:06:56 +0000669 OS << "Name: " << Name.getString() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000670 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
671 OS << " Symbol: ";
672 if (Sym)
673 OS << *Sym;
674 else
675 OS << "<none>";
676 OS << "\n";
Pavel Labath062eb532018-02-09 10:06:56 +0000677 for (auto *Value : Values)
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000678 Value->print(OS);
679}
680
Pavel Labatha7c457d2018-02-19 16:12:20 +0000681void AccelTableBase::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000682 // Print Content.
683 OS << "Entries: \n";
684 for (const auto &Entry : Entries) {
685 OS << "Name: " << Entry.first() << "\n";
686 for (auto *V : Entry.second.Values)
687 V->print(OS);
688 }
689
690 OS << "Buckets and Hashes: \n";
691 for (auto &Bucket : Buckets)
692 for (auto &Hash : Bucket)
693 Hash->print(OS);
694
695 OS << "Data: \n";
Pavel Labath062eb532018-02-09 10:06:56 +0000696 for (auto &E : Entries)
697 E.second.print(OS);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000698}
699
Pavel Labath6088c232018-04-04 14:42:14 +0000700void DWARF5AccelTableData::print(raw_ostream &OS) const {
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000701 OS << " Offset: " << getDieOffset() << "\n";
702 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
703}
704
705void DWARF5AccelTableStaticData::print(raw_ostream &OS) const {
706 OS << " Offset: " << getDieOffset() << "\n";
707 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
Pavel Labath6088c232018-04-04 14:42:14 +0000708}
709
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000710void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
Pavel Labath01206912018-07-20 15:40:24 +0000711 OS << " Offset: " << Die.getOffset() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000712}
713
714void AppleAccelTableTypeData::print(raw_ostream &OS) const {
Pavel Labath01206912018-07-20 15:40:24 +0000715 OS << " Offset: " << Die.getOffset() << "\n";
716 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000717}
718
719void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
720 OS << " Static Offset: " << Offset << "\n";
721}
722
723void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
724 OS << " Static Offset: " << Offset << "\n";
725 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
726 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
727 OS << " ObjCClassIsImplementation: "
728 << (ObjCClassIsImplementation ? "true" : "false");
729 OS << "\n";
730}
731#endif