blob: 3ecef5d8a19e3220d251f2c359587f4618996026 [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"
Benjamin Kramer3e6719c2012-03-26 14:17:26 +000015#include "llvm/ADT/STLExtras.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000016#include "llvm/ADT/StringMap.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000017#include "llvm/ADT/Twine.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000018#include "llvm/BinaryFormat/Dwarf.h"
Eric Christopher6e472042011-11-07 09:18:42 +000019#include "llvm/CodeGen/AsmPrinter.h"
Frederic Risse541e0b2015-01-05 21:29:41 +000020#include "llvm/CodeGen/DIE.h"
Eric Christopher6e472042011-11-07 09:18:42 +000021#include "llvm/MC/MCExpr.h"
22#include "llvm/MC/MCStreamer.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000023#include "llvm/Support/raw_ostream.h"
24#include <algorithm>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000025#include <cstddef>
26#include <cstdint>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000027#include <limits>
28#include <vector>
Eric Christopher6e472042011-11-07 09:18:42 +000029
30using namespace llvm;
31
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000032void AppleAccelTableHeader::emit(AsmPrinter *Asm) {
33 // Emit Header.
Lang Hames9ff69c82015-04-24 19:11:51 +000034 Asm->OutStreamer->AddComment("Header Magic");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000035 Asm->EmitInt32(Header.Magic);
Lang Hames9ff69c82015-04-24 19:11:51 +000036 Asm->OutStreamer->AddComment("Header Version");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000037 Asm->EmitInt16(Header.Version);
Lang Hames9ff69c82015-04-24 19:11:51 +000038 Asm->OutStreamer->AddComment("Header Hash Function");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000039 Asm->EmitInt16(Header.HashFunction);
Lang Hames9ff69c82015-04-24 19:11:51 +000040 Asm->OutStreamer->AddComment("Header Bucket Count");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000041 Asm->EmitInt32(Header.BucketCount);
Lang Hames9ff69c82015-04-24 19:11:51 +000042 Asm->OutStreamer->AddComment("Header Hash Count");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000043 Asm->EmitInt32(Header.HashCount);
Lang Hames9ff69c82015-04-24 19:11:51 +000044 Asm->OutStreamer->AddComment("Header Data Length");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000045 Asm->EmitInt32(Header.HeaderDataLength);
46
47 // Emit Header Data
Lang Hames9ff69c82015-04-24 19:11:51 +000048 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000049 Asm->EmitInt32(HeaderData.DieOffsetBase);
Lang Hames9ff69c82015-04-24 19:11:51 +000050 Asm->OutStreamer->AddComment("HeaderData Atom Count");
Eric Christopher6e472042011-11-07 09:18:42 +000051 Asm->EmitInt32(HeaderData.Atoms.size());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000052
Eric Christopher6e472042011-11-07 09:18:42 +000053 for (size_t i = 0; i < HeaderData.Atoms.size(); i++) {
54 Atom A = HeaderData.Atoms[i];
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000055 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
56 Asm->EmitInt16(A.Type);
57 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
58 Asm->EmitInt16(A.Form);
Eric Christopher6e472042011-11-07 09:18:42 +000059 }
60}
61
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000062void AppleAccelTableHeader::setBucketAndHashCount(uint32_t HashCount) {
63 if (HashCount > 1024)
64 Header.BucketCount = HashCount / 4;
65 else if (HashCount > 16)
66 Header.BucketCount = HashCount / 2;
67 else
68 Header.BucketCount = HashCount > 0 ? HashCount : 1;
69
70 Header.HashCount = HashCount;
71}
72
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000073void AppleAccelTableBase::emitHeader(AsmPrinter *Asm) { Header.emit(Asm); }
74
75void AppleAccelTableBase::emitBuckets(AsmPrinter *Asm) {
Eric Christopher6e472042011-11-07 09:18:42 +000076 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +000077 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Lang Hames9ff69c82015-04-24 19:11:51 +000078 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000079 if (!Buckets[i].empty())
Eric Christopher6e472042011-11-07 09:18:42 +000080 Asm->EmitInt32(index);
81 else
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000082 Asm->EmitInt32(std::numeric_limits<uint32_t>::max());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000083 // Buckets point in the list of hashes, not to the data. Do not increment
84 // the index multiple times in case of hash collisions.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000085 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Frederic Riss0e9a50f2015-03-10 00:46:31 +000086 for (auto *HD : Buckets[i]) {
87 uint32_t HashValue = HD->HashValue;
88 if (PrevHash != HashValue)
89 ++index;
90 PrevHash = HashValue;
91 }
Eric Christopher6e472042011-11-07 09:18:42 +000092 }
93}
94
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000095void AppleAccelTableBase::emitHashes(AsmPrinter *Asm) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000096 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000097 unsigned BucketIdx = 0;
98 for (auto &Bucket : Buckets) {
99 for (auto &Hash : Bucket) {
100 uint32_t HashValue = Hash->HashValue;
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000101 if (PrevHash == HashValue)
102 continue;
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000103 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000104 Asm->EmitInt32(HashValue);
105 PrevHash = HashValue;
Eric Christopher48fef592012-12-20 21:58:40 +0000106 }
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000107 BucketIdx++;
Eric Christopher6e472042011-11-07 09:18:42 +0000108 }
109}
110
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000111void AppleAccelTableBase::emitOffsets(AsmPrinter *Asm,
112 const MCSymbol *SecBegin) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000113 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Eric Christopher54ce295d2011-11-08 18:38:40 +0000114 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000115 for (auto HI = Buckets[i].begin(), HE = Buckets[i].end(); HI != HE; ++HI) {
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000116 uint32_t HashValue = (*HI)->HashValue;
117 if (PrevHash == HashValue)
118 continue;
119 PrevHash = HashValue;
Lang Hames9ff69c82015-04-24 19:11:51 +0000120 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
121 MCContext &Context = Asm->OutStreamer->getContext();
Jim Grosbach13760bd2015-05-30 01:25:56 +0000122 const MCExpr *Sub = MCBinaryExpr::createSub(
123 MCSymbolRefExpr::create((*HI)->Sym, Context),
124 MCSymbolRefExpr::create(SecBegin, Context), Context);
Lang Hames9ff69c82015-04-24 19:11:51 +0000125 Asm->OutStreamer->EmitValue(Sub, sizeof(uint32_t));
Eric Christopher6e472042011-11-07 09:18:42 +0000126 }
127 }
128}
129
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000130void AppleAccelTableBase::emitData(AsmPrinter *Asm) {
Eric Christopher54ce295d2011-11-08 18:38:40 +0000131 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000132 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000133 for (auto &Hash : Buckets[i]) {
134 // Terminate the previous entry if there is no hash collision with the
135 // current one.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000136 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000137 PrevHash != Hash->HashValue)
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000138 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000139 // Remember to emit the label for our offset.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000140 Asm->OutStreamer->EmitLabel(Hash->Sym);
Pavel Labath062eb532018-02-09 10:06:56 +0000141 Asm->OutStreamer->AddComment(Hash->Name.getString());
142 Asm->emitDwarfStringOffset(Hash->Name);
Lang Hames9ff69c82015-04-24 19:11:51 +0000143 Asm->OutStreamer->AddComment("Num DIEs");
Pavel Labath062eb532018-02-09 10:06:56 +0000144 Asm->EmitInt32(Hash->Values.size());
145 for (const auto *V : Hash->Values) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000146 V->emit(Asm);
Eric Christopher6e472042011-11-07 09:18:42 +0000147 }
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000148 PrevHash = Hash->HashValue;
Eric Christopher6e472042011-11-07 09:18:42 +0000149 }
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000150 // Emit the final end marker for the bucket.
Frederic Riss44a219f2015-03-10 03:47:55 +0000151 if (!Buckets[i].empty())
152 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000153 }
154}
155
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000156void AppleAccelTableBase::computeBucketCount() {
157 // First get the number of unique hashes.
Pavel Labath062eb532018-02-09 10:06:56 +0000158 std::vector<uint32_t> uniques;
159 uniques.reserve(Entries.size());
160 for (const auto &E : Entries)
161 uniques.push_back(E.second.HashValue);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000162 array_pod_sort(uniques.begin(), uniques.end());
163 std::vector<uint32_t>::iterator p =
164 std::unique(uniques.begin(), uniques.end());
Eric Christopher6e472042011-11-07 09:18:42 +0000165
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000166 // Compute the hashes count and use it to set that together with the bucket
167 // count in the header.
168 Header.setBucketAndHashCount(std::distance(uniques.begin(), p));
Eric Christopher6e472042011-11-07 09:18:42 +0000169}
170
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000171void AppleAccelTableBase::finalizeTable(AsmPrinter *Asm, StringRef Prefix) {
172 // Create the individual hash data outputs.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000173 for (auto &E : Entries) {
174 // Unique the entries.
175 std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
176 [](const AppleAccelTableData *A,
177 const AppleAccelTableData *B) { return *A < *B; });
178 E.second.Values.erase(
179 std::unique(E.second.Values.begin(), E.second.Values.end()),
180 E.second.Values.end());
Eric Christopher6e472042011-11-07 09:18:42 +0000181 }
182
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000183 // Figure out how many buckets we need, then compute the bucket contents and
184 // the final ordering. We'll emit the hashes and offsets by doing a walk
185 // during the emission phase. We add temporary symbols to the data so that we
186 // can reference them during the offset later, we'll emit them when we emit
187 // the data.
188 computeBucketCount();
Eric Christopher6e472042011-11-07 09:18:42 +0000189
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000190 // Compute bucket contents and final ordering.
191 Buckets.resize(Header.getBucketCount());
Pavel Labath062eb532018-02-09 10:06:56 +0000192 for (auto &E : Entries) {
193 uint32_t bucket = E.second.HashValue % Header.getBucketCount();
194 Buckets[bucket].push_back(&E.second);
195 E.second.Sym = Asm->createTempSymbol(Prefix);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000196 }
197
198 // Sort the contents of the buckets by hash value so that hash collisions end
199 // up together. Stable sort makes testing easier and doesn't cost much more.
200 for (auto &Bucket : Buckets)
201 std::stable_sort(Bucket.begin(), Bucket.end(),
202 [](HashData *LHS, HashData *RHS) {
203 return LHS->HashValue < RHS->HashValue;
204 });
Eric Christopher6e472042011-11-07 09:18:42 +0000205}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000206
207void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
208 Asm->EmitInt32(Die->getDebugSectionOffset());
209}
210
211void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
212 Asm->EmitInt32(Die->getDebugSectionOffset());
213 Asm->EmitInt16(Die->getTag());
214 Asm->EmitInt8(0);
215}
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000216
217void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
218 Asm->EmitInt32(Offset);
219}
220
221void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
222 Asm->EmitInt32(Offset);
223 Asm->EmitInt16(Tag);
224 Asm->EmitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
225 : 0);
226 Asm->EmitInt32(QualifiedNameHash);
227}
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000228
229#ifndef _MSC_VER
230// The lines below are rejected by older versions (TBD) of MSVC.
231constexpr AppleAccelTableHeader::Atom AppleAccelTableTypeData::Atoms[];
232constexpr AppleAccelTableHeader::Atom AppleAccelTableOffsetData::Atoms[];
233constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticOffsetData::Atoms[];
234constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticTypeData::Atoms[];
235#else
236// FIXME: Erase this path once the minimum MSCV version has been bumped.
237const SmallVector<AppleAccelTableHeader::Atom, 4>
238 AppleAccelTableOffsetData::Atoms = {AppleAccelTableHeader::Atom(
239 dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
240const SmallVector<AppleAccelTableHeader::Atom, 4>
241 AppleAccelTableTypeData::Atoms = {
242 AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset,
243 dwarf::DW_FORM_data4),
244 AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_tag,
245 dwarf::DW_FORM_data2),
246 AppleAccelTableHeader::Atom(dwarf::DW_ATOM_type_flags,
247 dwarf::DW_FORM_data1)};
248const SmallVector<AppleAccelTableHeader::Atom, 4>
249 AppleAccelTableStaticOffsetData::Atoms = {AppleAccelTableHeader::Atom(
250 dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
251const SmallVector<AppleAccelTableHeader::Atom, 4>
252 AppleAccelTableStaticTypeData::Atoms = {
253 AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset,
254 dwarf::DW_FORM_data4),
255 AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_tag,
256 dwarf::DW_FORM_data2),
257 AppleAccelTableHeader::Atom(5, dwarf::DW_FORM_data1),
258 AppleAccelTableHeader::Atom(6, dwarf::DW_FORM_data4)};
259#endif
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000260
261#ifndef NDEBUG
262void AppleAccelTableHeader::Header::print(raw_ostream &OS) const {
263 OS << "Magic: " << format("0x%x", Magic) << "\n"
264 << "Version: " << Version << "\n"
265 << "Hash Function: " << HashFunction << "\n"
266 << "Bucket Count: " << BucketCount << "\n"
267 << "Header Data Length: " << HeaderDataLength << "\n";
268}
269
270void AppleAccelTableHeader::Atom::print(raw_ostream &OS) const {
271 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
272 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
273}
274
275void AppleAccelTableHeader::HeaderData::print(raw_ostream &OS) const {
276 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
277 for (auto Atom : Atoms)
278 Atom.print(OS);
279}
280
281void AppleAccelTableHeader::print(raw_ostream &OS) const {
282 Header.print(OS);
283 HeaderData.print(OS);
284}
285
Pavel Labath062eb532018-02-09 10:06:56 +0000286void AppleAccelTableBase::HashData::print(raw_ostream &OS) const {
287 OS << "Name: " << Name.getString() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000288 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
289 OS << " Symbol: ";
290 if (Sym)
291 OS << *Sym;
292 else
293 OS << "<none>";
294 OS << "\n";
Pavel Labath062eb532018-02-09 10:06:56 +0000295 for (auto *Value : Values)
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000296 Value->print(OS);
297}
298
299void AppleAccelTableBase::print(raw_ostream &OS) const {
300 // Print Header.
301 Header.print(OS);
302
303 // Print Content.
304 OS << "Entries: \n";
305 for (const auto &Entry : Entries) {
306 OS << "Name: " << Entry.first() << "\n";
307 for (auto *V : Entry.second.Values)
308 V->print(OS);
309 }
310
311 OS << "Buckets and Hashes: \n";
312 for (auto &Bucket : Buckets)
313 for (auto &Hash : Bucket)
314 Hash->print(OS);
315
316 OS << "Data: \n";
Pavel Labath062eb532018-02-09 10:06:56 +0000317 for (auto &E : Entries)
318 E.second.print(OS);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000319}
320
321void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
322 OS << " Offset: " << Die->getOffset() << "\n";
323}
324
325void AppleAccelTableTypeData::print(raw_ostream &OS) const {
326 OS << " Offset: " << Die->getOffset() << "\n";
327 OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n";
328}
329
330void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
331 OS << " Static Offset: " << Offset << "\n";
332}
333
334void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
335 OS << " Static Offset: " << Offset << "\n";
336 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
337 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
338 OS << " ObjCClassIsImplementation: "
339 << (ObjCClassIsImplementation ? "true" : "false");
340 OS << "\n";
341}
342#endif