blob: 95875ccb8a0b9eb6611f10758237c257ca56e743 [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;
David Blaikie6dd452b2018-08-24 20:31:05 +0000557 SmallVector<unsigned, 1> CUIndex(CUs.size());
558 int Count = 0;
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000559 for (const auto &CU : enumerate(CUs)) {
David Blaikie66cf14d2018-08-16 21:29:55 +0000560 if (CU.value()->getCUNode()->getNameTableKind() ==
561 DICompileUnit::DebugNameTableKind::None)
562 continue;
David Blaikie6dd452b2018-08-24 20:31:05 +0000563 CUIndex[CU.index()] = Count++;
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000564 assert(CU.index() == CU.value()->getUniqueID());
565 const DwarfCompileUnit *MainCU =
566 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
567 CompUnits.push_back(MainCU->getLabelBegin());
568 }
569
David Blaikie66cf14d2018-08-16 21:29:55 +0000570 if (CompUnits.empty())
571 return;
572
573 Asm->OutStreamer->SwitchSection(
574 Asm->getObjFileLowering().getDwarfDebugNamesSection());
575
Pavel Labath6088c232018-04-04 14:42:14 +0000576 Contents.finalize(Asm, "names");
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000577 Dwarf5AccelTableWriter<DWARF5AccelTableData>(
578 Asm, Contents, CompUnits,
David Blaikie6dd452b2018-08-24 20:31:05 +0000579 [&](const DWARF5AccelTableData &Entry) {
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000580 const DIE *CUDie = Entry.getDie().getUnitDie();
David Blaikie6dd452b2018-08-24 20:31:05 +0000581 return CUIndex[DD.lookupCU(CUDie)->getUniqueID()];
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000582 })
583 .emit();
584}
585
586void llvm::emitDWARF5AccelTable(
587 AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
588 ArrayRef<MCSymbol *> CUs,
589 llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
590 getCUIndexForEntry) {
591 Contents.finalize(Asm, "names");
592 Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs,
593 getCUIndexForEntry)
594 .emit();
Pavel Labath6088c232018-04-04 14:42:14 +0000595}
596
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000597void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
Pavel Labath7f7e6062018-07-20 15:24:13 +0000598 Asm->emitInt32(Die.getDebugSectionOffset());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000599}
600
601void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
Pavel Labath7f7e6062018-07-20 15:24:13 +0000602 Asm->emitInt32(Die.getDebugSectionOffset());
603 Asm->emitInt16(Die.getTag());
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000604 Asm->emitInt8(0);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000605}
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000606
607void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000608 Asm->emitInt32(Offset);
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000609}
610
611void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000612 Asm->emitInt32(Offset);
613 Asm->emitInt16(Tag);
614 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000615 : 0);
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000616 Asm->emitInt32(QualifiedNameHash);
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000617}
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000618
619#ifndef _MSC_VER
620// The lines below are rejected by older versions (TBD) of MSVC.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000621constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
622constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
623constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
624constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000625#else
626// FIXME: Erase this path once the minimum MSCV version has been bumped.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000627const SmallVector<AppleAccelTableData::Atom, 4>
628 AppleAccelTableOffsetData::Atoms = {
629 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
630const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms =
631 {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
632 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
633 Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
634const SmallVector<AppleAccelTableData::Atom, 4>
635 AppleAccelTableStaticOffsetData::Atoms = {
636 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
637const SmallVector<AppleAccelTableData::Atom, 4>
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000638 AppleAccelTableStaticTypeData::Atoms = {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000639 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
640 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
641 Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000642#endif
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000643
644#ifndef NDEBUG
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000645void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000646 OS << "Magic: " << format("0x%x", Magic) << "\n"
647 << "Version: " << Version << "\n"
648 << "Hash Function: " << HashFunction << "\n"
649 << "Bucket Count: " << BucketCount << "\n"
650 << "Header Data Length: " << HeaderDataLength << "\n";
651}
652
Pavel Labatha7c457d2018-02-19 16:12:20 +0000653void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000654 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
655 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
656}
657
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000658void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000659 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
660 for (auto Atom : Atoms)
661 Atom.print(OS);
662}
663
Jonas Devliegheree60ca772018-07-09 08:47:38 +0000664void AppleAccelTableWriter::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000665 Header.print(OS);
666 HeaderData.print(OS);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000667 Contents.print(OS);
668 SecBegin->print(OS, nullptr);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000669}
670
Pavel Labatha7c457d2018-02-19 16:12:20 +0000671void AccelTableBase::HashData::print(raw_ostream &OS) const {
Pavel Labath062eb532018-02-09 10:06:56 +0000672 OS << "Name: " << Name.getString() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000673 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
674 OS << " Symbol: ";
675 if (Sym)
676 OS << *Sym;
677 else
678 OS << "<none>";
679 OS << "\n";
Pavel Labath062eb532018-02-09 10:06:56 +0000680 for (auto *Value : Values)
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000681 Value->print(OS);
682}
683
Pavel Labatha7c457d2018-02-19 16:12:20 +0000684void AccelTableBase::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000685 // Print Content.
686 OS << "Entries: \n";
687 for (const auto &Entry : Entries) {
688 OS << "Name: " << Entry.first() << "\n";
689 for (auto *V : Entry.second.Values)
690 V->print(OS);
691 }
692
693 OS << "Buckets and Hashes: \n";
694 for (auto &Bucket : Buckets)
695 for (auto &Hash : Bucket)
696 Hash->print(OS);
697
698 OS << "Data: \n";
Pavel Labath062eb532018-02-09 10:06:56 +0000699 for (auto &E : Entries)
700 E.second.print(OS);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000701}
702
Pavel Labath6088c232018-04-04 14:42:14 +0000703void DWARF5AccelTableData::print(raw_ostream &OS) const {
Jonas Devlieghere98062cb2018-07-16 10:52:27 +0000704 OS << " Offset: " << getDieOffset() << "\n";
705 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
706}
707
708void DWARF5AccelTableStaticData::print(raw_ostream &OS) const {
709 OS << " Offset: " << getDieOffset() << "\n";
710 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
Pavel Labath6088c232018-04-04 14:42:14 +0000711}
712
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000713void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
Pavel Labath01206912018-07-20 15:40:24 +0000714 OS << " Offset: " << Die.getOffset() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000715}
716
717void AppleAccelTableTypeData::print(raw_ostream &OS) const {
Pavel Labath01206912018-07-20 15:40:24 +0000718 OS << " Offset: " << Die.getOffset() << "\n";
719 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000720}
721
722void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
723 OS << " Static Offset: " << Offset << "\n";
724}
725
726void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
727 OS << " Static Offset: " << Offset << "\n";
728 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
729 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
730 OS << " ObjCClassIsImplementation: "
731 << (ObjCClassIsImplementation ? "true" : "false");
732 OS << "\n";
733}
734#endif