blob: 5c80206a1d7e39adce8782c8eec3871d284bf0d8 [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
73constexpr AppleAccelTableHeader::Atom AppleAccelTableTypeData::Atoms[];
74constexpr AppleAccelTableHeader::Atom AppleAccelTableOffsetData::Atoms[];
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +000075constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticOffsetData::Atoms[];
76constexpr AppleAccelTableHeader::Atom AppleAccelTableStaticTypeData::Atoms[];
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000077
78void AppleAccelTableBase::emitHeader(AsmPrinter *Asm) { Header.emit(Asm); }
79
80void AppleAccelTableBase::emitBuckets(AsmPrinter *Asm) {
Eric Christopher6e472042011-11-07 09:18:42 +000081 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +000082 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Lang Hames9ff69c82015-04-24 19:11:51 +000083 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000084 if (!Buckets[i].empty())
Eric Christopher6e472042011-11-07 09:18:42 +000085 Asm->EmitInt32(index);
86 else
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000087 Asm->EmitInt32(std::numeric_limits<uint32_t>::max());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000088 // Buckets point in the list of hashes, not to the data. Do not increment
89 // the index multiple times in case of hash collisions.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000090 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Frederic Riss0e9a50f2015-03-10 00:46:31 +000091 for (auto *HD : Buckets[i]) {
92 uint32_t HashValue = HD->HashValue;
93 if (PrevHash != HashValue)
94 ++index;
95 PrevHash = HashValue;
96 }
Eric Christopher6e472042011-11-07 09:18:42 +000097 }
98}
99
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000100void AppleAccelTableBase::emitHashes(AsmPrinter *Asm) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000101 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000102 unsigned BucketIdx = 0;
103 for (auto &Bucket : Buckets) {
104 for (auto &Hash : Bucket) {
105 uint32_t HashValue = Hash->HashValue;
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000106 if (PrevHash == HashValue)
107 continue;
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000108 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000109 Asm->EmitInt32(HashValue);
110 PrevHash = HashValue;
Eric Christopher48fef592012-12-20 21:58:40 +0000111 }
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000112 BucketIdx++;
Eric Christopher6e472042011-11-07 09:18:42 +0000113 }
114}
115
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000116void AppleAccelTableBase::emitOffsets(AsmPrinter *Asm,
117 const MCSymbol *SecBegin) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000118 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Eric Christopher54ce295d2011-11-08 18:38:40 +0000119 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000120 for (auto HI = Buckets[i].begin(), HE = Buckets[i].end(); HI != HE; ++HI) {
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000121 uint32_t HashValue = (*HI)->HashValue;
122 if (PrevHash == HashValue)
123 continue;
124 PrevHash = HashValue;
Lang Hames9ff69c82015-04-24 19:11:51 +0000125 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
126 MCContext &Context = Asm->OutStreamer->getContext();
Jim Grosbach13760bd2015-05-30 01:25:56 +0000127 const MCExpr *Sub = MCBinaryExpr::createSub(
128 MCSymbolRefExpr::create((*HI)->Sym, Context),
129 MCSymbolRefExpr::create(SecBegin, Context), Context);
Lang Hames9ff69c82015-04-24 19:11:51 +0000130 Asm->OutStreamer->EmitValue(Sub, sizeof(uint32_t));
Eric Christopher6e472042011-11-07 09:18:42 +0000131 }
132 }
133}
134
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000135void AppleAccelTableBase::emitData(AsmPrinter *Asm) {
Eric Christopher54ce295d2011-11-08 18:38:40 +0000136 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000137 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000138 for (auto &Hash : Buckets[i]) {
139 // Terminate the previous entry if there is no hash collision with the
140 // current one.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000141 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000142 PrevHash != Hash->HashValue)
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000143 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000144 // Remember to emit the label for our offset.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000145 Asm->OutStreamer->EmitLabel(Hash->Sym);
146 Asm->OutStreamer->AddComment(Hash->Str);
147 Asm->emitDwarfStringOffset(Hash->Data.Name);
Lang Hames9ff69c82015-04-24 19:11:51 +0000148 Asm->OutStreamer->AddComment("Num DIEs");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000149 Asm->EmitInt32(Hash->Data.Values.size());
150 for (const auto *V : Hash->Data.Values) {
151 V->emit(Asm);
Eric Christopher6e472042011-11-07 09:18:42 +0000152 }
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000153 PrevHash = Hash->HashValue;
Eric Christopher6e472042011-11-07 09:18:42 +0000154 }
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000155 // Emit the final end marker for the bucket.
Frederic Riss44a219f2015-03-10 03:47:55 +0000156 if (!Buckets[i].empty())
157 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000158 }
159}
160
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000161void AppleAccelTableBase::computeBucketCount() {
162 // First get the number of unique hashes.
163 std::vector<uint32_t> uniques(Data.size());
164 for (size_t i = 0, e = Data.size(); i < e; ++i)
165 uniques[i] = Data[i]->HashValue;
166 array_pod_sort(uniques.begin(), uniques.end());
167 std::vector<uint32_t>::iterator p =
168 std::unique(uniques.begin(), uniques.end());
Eric Christopher6e472042011-11-07 09:18:42 +0000169
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000170 // Compute the hashes count and use it to set that together with the bucket
171 // count in the header.
172 Header.setBucketAndHashCount(std::distance(uniques.begin(), p));
Eric Christopher6e472042011-11-07 09:18:42 +0000173}
174
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000175void AppleAccelTableBase::finalizeTable(AsmPrinter *Asm, StringRef Prefix) {
176 // Create the individual hash data outputs.
177 Data.reserve(Entries.size());
178 for (auto &E : Entries) {
179 // Unique the entries.
180 std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
181 [](const AppleAccelTableData *A,
182 const AppleAccelTableData *B) { return *A < *B; });
183 E.second.Values.erase(
184 std::unique(E.second.Values.begin(), E.second.Values.end()),
185 E.second.Values.end());
Eric Christopher6e472042011-11-07 09:18:42 +0000186
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000187 HashData *Entry = new (Allocator) HashData(E.first(), E.second);
188 Data.push_back(Entry);
Eric Christopher6e472042011-11-07 09:18:42 +0000189 }
190
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000191 // Figure out how many buckets we need, then compute the bucket contents and
192 // the final ordering. We'll emit the hashes and offsets by doing a walk
193 // during the emission phase. We add temporary symbols to the data so that we
194 // can reference them during the offset later, we'll emit them when we emit
195 // the data.
196 computeBucketCount();
Eric Christopher6e472042011-11-07 09:18:42 +0000197
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000198 // Compute bucket contents and final ordering.
199 Buckets.resize(Header.getBucketCount());
200 for (auto &D : Data) {
201 uint32_t bucket = D->HashValue % Header.getBucketCount();
202 Buckets[bucket].push_back(D);
203 D->Sym = Asm->createTempSymbol(Prefix);
204 }
205
206 // Sort the contents of the buckets by hash value so that hash collisions end
207 // up together. Stable sort makes testing easier and doesn't cost much more.
208 for (auto &Bucket : Buckets)
209 std::stable_sort(Bucket.begin(), Bucket.end(),
210 [](HashData *LHS, HashData *RHS) {
211 return LHS->HashValue < RHS->HashValue;
212 });
Eric Christopher6e472042011-11-07 09:18:42 +0000213}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000214
215void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
216 Asm->EmitInt32(Die->getDebugSectionOffset());
217}
218
219void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
220 Asm->EmitInt32(Die->getDebugSectionOffset());
221 Asm->EmitInt16(Die->getTag());
222 Asm->EmitInt8(0);
223}
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000224
225void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
226 Asm->EmitInt32(Offset);
227}
228
229void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
230 Asm->EmitInt32(Offset);
231 Asm->EmitInt16(Tag);
232 Asm->EmitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
233 : 0);
234 Asm->EmitInt32(QualifiedNameHash);
235}