blob: e9c6c4d34b42d58ebb9afaaa7ec25ff6bc9e9fc7 [file] [log] [blame]
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +00001//===- llvm/CodeGen/DwarfAccelTable.cpp - Dwarf 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//
10// This file contains support for writing dwarf accelerator tables.
11//
12//===----------------------------------------------------------------------===//
13
Craig Topper6e80c282012-03-26 06:58:25 +000014#include "DwarfAccelTable.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[];
75
76void AppleAccelTableBase::emitHeader(AsmPrinter *Asm) { Header.emit(Asm); }
77
78void AppleAccelTableBase::emitBuckets(AsmPrinter *Asm) {
Eric Christopher6e472042011-11-07 09:18:42 +000079 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +000080 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Lang Hames9ff69c82015-04-24 19:11:51 +000081 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000082 if (!Buckets[i].empty())
Eric Christopher6e472042011-11-07 09:18:42 +000083 Asm->EmitInt32(index);
84 else
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000085 Asm->EmitInt32(std::numeric_limits<uint32_t>::max());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000086 // Buckets point in the list of hashes, not to the data. Do not increment
87 // the index multiple times in case of hash collisions.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000088 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Frederic Riss0e9a50f2015-03-10 00:46:31 +000089 for (auto *HD : Buckets[i]) {
90 uint32_t HashValue = HD->HashValue;
91 if (PrevHash != HashValue)
92 ++index;
93 PrevHash = HashValue;
94 }
Eric Christopher6e472042011-11-07 09:18:42 +000095 }
96}
97
Jonas Devliegheree699dfa2018-01-29 14:52:34 +000098void AppleAccelTableBase::emitHashes(AsmPrinter *Asm) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000099 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000100 unsigned BucketIdx = 0;
101 for (auto &Bucket : Buckets) {
102 for (auto &Hash : Bucket) {
103 uint32_t HashValue = Hash->HashValue;
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000104 if (PrevHash == HashValue)
105 continue;
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000106 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000107 Asm->EmitInt32(HashValue);
108 PrevHash = HashValue;
Eric Christopher48fef592012-12-20 21:58:40 +0000109 }
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000110 BucketIdx++;
Eric Christopher6e472042011-11-07 09:18:42 +0000111 }
112}
113
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000114void AppleAccelTableBase::emitOffsets(AsmPrinter *Asm,
115 const MCSymbol *SecBegin) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000116 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Eric Christopher54ce295d2011-11-08 18:38:40 +0000117 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000118 for (auto HI = Buckets[i].begin(), HE = Buckets[i].end(); HI != HE; ++HI) {
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000119 uint32_t HashValue = (*HI)->HashValue;
120 if (PrevHash == HashValue)
121 continue;
122 PrevHash = HashValue;
Lang Hames9ff69c82015-04-24 19:11:51 +0000123 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
124 MCContext &Context = Asm->OutStreamer->getContext();
Jim Grosbach13760bd2015-05-30 01:25:56 +0000125 const MCExpr *Sub = MCBinaryExpr::createSub(
126 MCSymbolRefExpr::create((*HI)->Sym, Context),
127 MCSymbolRefExpr::create(SecBegin, Context), Context);
Lang Hames9ff69c82015-04-24 19:11:51 +0000128 Asm->OutStreamer->EmitValue(Sub, sizeof(uint32_t));
Eric Christopher6e472042011-11-07 09:18:42 +0000129 }
130 }
131}
132
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000133void AppleAccelTableBase::emitData(AsmPrinter *Asm) {
Eric Christopher54ce295d2011-11-08 18:38:40 +0000134 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000135 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000136 for (auto &Hash : Buckets[i]) {
137 // Terminate the previous entry if there is no hash collision with the
138 // current one.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000139 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000140 PrevHash != Hash->HashValue)
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000141 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000142 // Remember to emit the label for our offset.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000143 Asm->OutStreamer->EmitLabel(Hash->Sym);
144 Asm->OutStreamer->AddComment(Hash->Str);
145 Asm->emitDwarfStringOffset(Hash->Data.Name);
Lang Hames9ff69c82015-04-24 19:11:51 +0000146 Asm->OutStreamer->AddComment("Num DIEs");
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000147 Asm->EmitInt32(Hash->Data.Values.size());
148 for (const auto *V : Hash->Data.Values) {
149 V->emit(Asm);
Eric Christopher6e472042011-11-07 09:18:42 +0000150 }
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000151 PrevHash = Hash->HashValue;
Eric Christopher6e472042011-11-07 09:18:42 +0000152 }
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000153 // Emit the final end marker for the bucket.
Frederic Riss44a219f2015-03-10 03:47:55 +0000154 if (!Buckets[i].empty())
155 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000156 }
157}
158
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000159void AppleAccelTableBase::computeBucketCount() {
160 // First get the number of unique hashes.
161 std::vector<uint32_t> uniques(Data.size());
162 for (size_t i = 0, e = Data.size(); i < e; ++i)
163 uniques[i] = Data[i]->HashValue;
164 array_pod_sort(uniques.begin(), uniques.end());
165 std::vector<uint32_t>::iterator p =
166 std::unique(uniques.begin(), uniques.end());
Eric Christopher6e472042011-11-07 09:18:42 +0000167
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000168 // Compute the hashes count and use it to set that together with the bucket
169 // count in the header.
170 Header.setBucketAndHashCount(std::distance(uniques.begin(), p));
Eric Christopher6e472042011-11-07 09:18:42 +0000171}
172
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000173void AppleAccelTableBase::finalizeTable(AsmPrinter *Asm, StringRef Prefix) {
174 // Create the individual hash data outputs.
175 Data.reserve(Entries.size());
176 for (auto &E : Entries) {
177 // Unique the entries.
178 std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
179 [](const AppleAccelTableData *A,
180 const AppleAccelTableData *B) { return *A < *B; });
181 E.second.Values.erase(
182 std::unique(E.second.Values.begin(), E.second.Values.end()),
183 E.second.Values.end());
Eric Christopher6e472042011-11-07 09:18:42 +0000184
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000185 HashData *Entry = new (Allocator) HashData(E.first(), E.second);
186 Data.push_back(Entry);
Eric Christopher6e472042011-11-07 09:18:42 +0000187 }
188
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000189 // Figure out how many buckets we need, then compute the bucket contents and
190 // the final ordering. We'll emit the hashes and offsets by doing a walk
191 // during the emission phase. We add temporary symbols to the data so that we
192 // can reference them during the offset later, we'll emit them when we emit
193 // the data.
194 computeBucketCount();
Eric Christopher6e472042011-11-07 09:18:42 +0000195
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000196 // Compute bucket contents and final ordering.
197 Buckets.resize(Header.getBucketCount());
198 for (auto &D : Data) {
199 uint32_t bucket = D->HashValue % Header.getBucketCount();
200 Buckets[bucket].push_back(D);
201 D->Sym = Asm->createTempSymbol(Prefix);
202 }
203
204 // Sort the contents of the buckets by hash value so that hash collisions end
205 // up together. Stable sort makes testing easier and doesn't cost much more.
206 for (auto &Bucket : Buckets)
207 std::stable_sort(Bucket.begin(), Bucket.end(),
208 [](HashData *LHS, HashData *RHS) {
209 return LHS->HashValue < RHS->HashValue;
210 });
Eric Christopher6e472042011-11-07 09:18:42 +0000211}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000212
213void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
214 Asm->EmitInt32(Die->getDebugSectionOffset());
215}
216
217void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
218 Asm->EmitInt32(Die->getDebugSectionOffset());
219 Asm->EmitInt16(Die->getTag());
220 Asm->EmitInt8(0);
221}