1*855fc3bbSJonas Devlieghere //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
2*855fc3bbSJonas Devlieghere //
3*855fc3bbSJonas Devlieghere //                     The LLVM Compiler Infrastructure
4*855fc3bbSJonas Devlieghere //
5*855fc3bbSJonas Devlieghere // This file is distributed under the University of Illinois Open Source
6*855fc3bbSJonas Devlieghere // License. See LICENSE.TXT for details.
7*855fc3bbSJonas Devlieghere //
8*855fc3bbSJonas Devlieghere //===----------------------------------------------------------------------===//
9*855fc3bbSJonas Devlieghere //
10*855fc3bbSJonas Devlieghere // This file contains support for writing accelerator tables.
11*855fc3bbSJonas Devlieghere //
12*855fc3bbSJonas Devlieghere //===----------------------------------------------------------------------===//
13*855fc3bbSJonas Devlieghere 
14*855fc3bbSJonas Devlieghere #include "llvm/CodeGen/AccelTable.h"
15*855fc3bbSJonas Devlieghere #include "llvm/ADT/STLExtras.h"
16*855fc3bbSJonas Devlieghere #include "llvm/ADT/StringMap.h"
17*855fc3bbSJonas Devlieghere #include "llvm/ADT/Twine.h"
18*855fc3bbSJonas Devlieghere #include "llvm/BinaryFormat/Dwarf.h"
19*855fc3bbSJonas Devlieghere #include "llvm/CodeGen/AsmPrinter.h"
20*855fc3bbSJonas Devlieghere #include "llvm/CodeGen/DIE.h"
21*855fc3bbSJonas Devlieghere #include "llvm/MC/MCExpr.h"
22*855fc3bbSJonas Devlieghere #include "llvm/MC/MCStreamer.h"
23*855fc3bbSJonas Devlieghere #include "llvm/Support/raw_ostream.h"
24*855fc3bbSJonas Devlieghere #include <algorithm>
25*855fc3bbSJonas Devlieghere #include <cstddef>
26*855fc3bbSJonas Devlieghere #include <cstdint>
27*855fc3bbSJonas Devlieghere #include <limits>
28*855fc3bbSJonas Devlieghere #include <vector>
29*855fc3bbSJonas Devlieghere 
30*855fc3bbSJonas Devlieghere using namespace llvm;
31*855fc3bbSJonas Devlieghere 
32*855fc3bbSJonas Devlieghere void AppleAccelTableHeader::emit(AsmPrinter *Asm) {
33*855fc3bbSJonas Devlieghere   // Emit Header.
34*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("Header Magic");
35*855fc3bbSJonas Devlieghere   Asm->EmitInt32(Header.Magic);
36*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("Header Version");
37*855fc3bbSJonas Devlieghere   Asm->EmitInt16(Header.Version);
38*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("Header Hash Function");
39*855fc3bbSJonas Devlieghere   Asm->EmitInt16(Header.HashFunction);
40*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("Header Bucket Count");
41*855fc3bbSJonas Devlieghere   Asm->EmitInt32(Header.BucketCount);
42*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("Header Hash Count");
43*855fc3bbSJonas Devlieghere   Asm->EmitInt32(Header.HashCount);
44*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("Header Data Length");
45*855fc3bbSJonas Devlieghere   Asm->EmitInt32(Header.HeaderDataLength);
46*855fc3bbSJonas Devlieghere 
47*855fc3bbSJonas Devlieghere   //  Emit Header Data
48*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
49*855fc3bbSJonas Devlieghere   Asm->EmitInt32(HeaderData.DieOffsetBase);
50*855fc3bbSJonas Devlieghere   Asm->OutStreamer->AddComment("HeaderData Atom Count");
51*855fc3bbSJonas Devlieghere   Asm->EmitInt32(HeaderData.Atoms.size());
52*855fc3bbSJonas Devlieghere 
53*855fc3bbSJonas Devlieghere   for (size_t i = 0; i < HeaderData.Atoms.size(); i++) {
54*855fc3bbSJonas Devlieghere     Atom A = HeaderData.Atoms[i];
55*855fc3bbSJonas Devlieghere     Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
56*855fc3bbSJonas Devlieghere     Asm->EmitInt16(A.Type);
57*855fc3bbSJonas Devlieghere     Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
58*855fc3bbSJonas Devlieghere     Asm->EmitInt16(A.Form);
59*855fc3bbSJonas Devlieghere   }
60*855fc3bbSJonas Devlieghere }
61*855fc3bbSJonas Devlieghere 
62*855fc3bbSJonas Devlieghere void AppleAccelTableHeader::setBucketAndHashCount(uint32_t HashCount) {
63*855fc3bbSJonas Devlieghere   if (HashCount > 1024)
64*855fc3bbSJonas Devlieghere     Header.BucketCount = HashCount / 4;
65*855fc3bbSJonas Devlieghere   else if (HashCount > 16)
66*855fc3bbSJonas Devlieghere     Header.BucketCount = HashCount / 2;
67*855fc3bbSJonas Devlieghere   else
68*855fc3bbSJonas Devlieghere     Header.BucketCount = HashCount > 0 ? HashCount : 1;
69*855fc3bbSJonas Devlieghere 
70*855fc3bbSJonas Devlieghere   Header.HashCount = HashCount;
71*855fc3bbSJonas Devlieghere }
72*855fc3bbSJonas Devlieghere 
73*855fc3bbSJonas Devlieghere constexpr AppleAccelTableHeader::Atom AppleAccelTableTypeData::Atoms[];
74*855fc3bbSJonas Devlieghere constexpr AppleAccelTableHeader::Atom AppleAccelTableOffsetData::Atoms[];
75*855fc3bbSJonas Devlieghere 
76*855fc3bbSJonas Devlieghere void AppleAccelTableBase::emitHeader(AsmPrinter *Asm) { Header.emit(Asm); }
77*855fc3bbSJonas Devlieghere 
78*855fc3bbSJonas Devlieghere void AppleAccelTableBase::emitBuckets(AsmPrinter *Asm) {
79*855fc3bbSJonas Devlieghere   unsigned index = 0;
80*855fc3bbSJonas Devlieghere   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
81*855fc3bbSJonas Devlieghere     Asm->OutStreamer->AddComment("Bucket " + Twine(i));
82*855fc3bbSJonas Devlieghere     if (!Buckets[i].empty())
83*855fc3bbSJonas Devlieghere       Asm->EmitInt32(index);
84*855fc3bbSJonas Devlieghere     else
85*855fc3bbSJonas Devlieghere       Asm->EmitInt32(std::numeric_limits<uint32_t>::max());
86*855fc3bbSJonas Devlieghere     // Buckets point in the list of hashes, not to the data. Do not increment
87*855fc3bbSJonas Devlieghere     // the index multiple times in case of hash collisions.
88*855fc3bbSJonas Devlieghere     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
89*855fc3bbSJonas Devlieghere     for (auto *HD : Buckets[i]) {
90*855fc3bbSJonas Devlieghere       uint32_t HashValue = HD->HashValue;
91*855fc3bbSJonas Devlieghere       if (PrevHash != HashValue)
92*855fc3bbSJonas Devlieghere         ++index;
93*855fc3bbSJonas Devlieghere       PrevHash = HashValue;
94*855fc3bbSJonas Devlieghere     }
95*855fc3bbSJonas Devlieghere   }
96*855fc3bbSJonas Devlieghere }
97*855fc3bbSJonas Devlieghere 
98*855fc3bbSJonas Devlieghere void AppleAccelTableBase::emitHashes(AsmPrinter *Asm) {
99*855fc3bbSJonas Devlieghere   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
100*855fc3bbSJonas Devlieghere   unsigned BucketIdx = 0;
101*855fc3bbSJonas Devlieghere   for (auto &Bucket : Buckets) {
102*855fc3bbSJonas Devlieghere     for (auto &Hash : Bucket) {
103*855fc3bbSJonas Devlieghere       uint32_t HashValue = Hash->HashValue;
104*855fc3bbSJonas Devlieghere       if (PrevHash == HashValue)
105*855fc3bbSJonas Devlieghere         continue;
106*855fc3bbSJonas Devlieghere       Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
107*855fc3bbSJonas Devlieghere       Asm->EmitInt32(HashValue);
108*855fc3bbSJonas Devlieghere       PrevHash = HashValue;
109*855fc3bbSJonas Devlieghere     }
110*855fc3bbSJonas Devlieghere     BucketIdx++;
111*855fc3bbSJonas Devlieghere   }
112*855fc3bbSJonas Devlieghere }
113*855fc3bbSJonas Devlieghere 
114*855fc3bbSJonas Devlieghere void AppleAccelTableBase::emitOffsets(AsmPrinter *Asm,
115*855fc3bbSJonas Devlieghere                                       const MCSymbol *SecBegin) {
116*855fc3bbSJonas Devlieghere   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
117*855fc3bbSJonas Devlieghere   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
118*855fc3bbSJonas Devlieghere     for (auto HI = Buckets[i].begin(), HE = Buckets[i].end(); HI != HE; ++HI) {
119*855fc3bbSJonas Devlieghere       uint32_t HashValue = (*HI)->HashValue;
120*855fc3bbSJonas Devlieghere       if (PrevHash == HashValue)
121*855fc3bbSJonas Devlieghere         continue;
122*855fc3bbSJonas Devlieghere       PrevHash = HashValue;
123*855fc3bbSJonas Devlieghere       Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
124*855fc3bbSJonas Devlieghere       MCContext &Context = Asm->OutStreamer->getContext();
125*855fc3bbSJonas Devlieghere       const MCExpr *Sub = MCBinaryExpr::createSub(
126*855fc3bbSJonas Devlieghere           MCSymbolRefExpr::create((*HI)->Sym, Context),
127*855fc3bbSJonas Devlieghere           MCSymbolRefExpr::create(SecBegin, Context), Context);
128*855fc3bbSJonas Devlieghere       Asm->OutStreamer->EmitValue(Sub, sizeof(uint32_t));
129*855fc3bbSJonas Devlieghere     }
130*855fc3bbSJonas Devlieghere   }
131*855fc3bbSJonas Devlieghere }
132*855fc3bbSJonas Devlieghere 
133*855fc3bbSJonas Devlieghere void AppleAccelTableBase::emitData(AsmPrinter *Asm) {
134*855fc3bbSJonas Devlieghere   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
135*855fc3bbSJonas Devlieghere     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
136*855fc3bbSJonas Devlieghere     for (auto &Hash : Buckets[i]) {
137*855fc3bbSJonas Devlieghere       // Terminate the previous entry if there is no hash collision with the
138*855fc3bbSJonas Devlieghere       // current one.
139*855fc3bbSJonas Devlieghere       if (PrevHash != std::numeric_limits<uint64_t>::max() &&
140*855fc3bbSJonas Devlieghere           PrevHash != Hash->HashValue)
141*855fc3bbSJonas Devlieghere         Asm->EmitInt32(0);
142*855fc3bbSJonas Devlieghere       // Remember to emit the label for our offset.
143*855fc3bbSJonas Devlieghere       Asm->OutStreamer->EmitLabel(Hash->Sym);
144*855fc3bbSJonas Devlieghere       Asm->OutStreamer->AddComment(Hash->Str);
145*855fc3bbSJonas Devlieghere       Asm->emitDwarfStringOffset(Hash->Data.Name);
146*855fc3bbSJonas Devlieghere       Asm->OutStreamer->AddComment("Num DIEs");
147*855fc3bbSJonas Devlieghere       Asm->EmitInt32(Hash->Data.Values.size());
148*855fc3bbSJonas Devlieghere       for (const auto *V : Hash->Data.Values) {
149*855fc3bbSJonas Devlieghere         V->emit(Asm);
150*855fc3bbSJonas Devlieghere       }
151*855fc3bbSJonas Devlieghere       PrevHash = Hash->HashValue;
152*855fc3bbSJonas Devlieghere     }
153*855fc3bbSJonas Devlieghere     // Emit the final end marker for the bucket.
154*855fc3bbSJonas Devlieghere     if (!Buckets[i].empty())
155*855fc3bbSJonas Devlieghere       Asm->EmitInt32(0);
156*855fc3bbSJonas Devlieghere   }
157*855fc3bbSJonas Devlieghere }
158*855fc3bbSJonas Devlieghere 
159*855fc3bbSJonas Devlieghere void AppleAccelTableBase::computeBucketCount() {
160*855fc3bbSJonas Devlieghere   // First get the number of unique hashes.
161*855fc3bbSJonas Devlieghere   std::vector<uint32_t> uniques(Data.size());
162*855fc3bbSJonas Devlieghere   for (size_t i = 0, e = Data.size(); i < e; ++i)
163*855fc3bbSJonas Devlieghere     uniques[i] = Data[i]->HashValue;
164*855fc3bbSJonas Devlieghere   array_pod_sort(uniques.begin(), uniques.end());
165*855fc3bbSJonas Devlieghere   std::vector<uint32_t>::iterator p =
166*855fc3bbSJonas Devlieghere       std::unique(uniques.begin(), uniques.end());
167*855fc3bbSJonas Devlieghere 
168*855fc3bbSJonas Devlieghere   // Compute the hashes count and use it to set that together with the bucket
169*855fc3bbSJonas Devlieghere   // count in the header.
170*855fc3bbSJonas Devlieghere   Header.setBucketAndHashCount(std::distance(uniques.begin(), p));
171*855fc3bbSJonas Devlieghere }
172*855fc3bbSJonas Devlieghere 
173*855fc3bbSJonas Devlieghere void AppleAccelTableBase::finalizeTable(AsmPrinter *Asm, StringRef Prefix) {
174*855fc3bbSJonas Devlieghere   // Create the individual hash data outputs.
175*855fc3bbSJonas Devlieghere   Data.reserve(Entries.size());
176*855fc3bbSJonas Devlieghere   for (auto &E : Entries) {
177*855fc3bbSJonas Devlieghere     // Unique the entries.
178*855fc3bbSJonas Devlieghere     std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
179*855fc3bbSJonas Devlieghere                      [](const AppleAccelTableData *A,
180*855fc3bbSJonas Devlieghere                         const AppleAccelTableData *B) { return *A < *B; });
181*855fc3bbSJonas Devlieghere     E.second.Values.erase(
182*855fc3bbSJonas Devlieghere         std::unique(E.second.Values.begin(), E.second.Values.end()),
183*855fc3bbSJonas Devlieghere         E.second.Values.end());
184*855fc3bbSJonas Devlieghere 
185*855fc3bbSJonas Devlieghere     HashData *Entry = new (Allocator) HashData(E.first(), E.second);
186*855fc3bbSJonas Devlieghere     Data.push_back(Entry);
187*855fc3bbSJonas Devlieghere   }
188*855fc3bbSJonas Devlieghere 
189*855fc3bbSJonas Devlieghere   // Figure out how many buckets we need, then compute the bucket contents and
190*855fc3bbSJonas Devlieghere   // the final ordering. We'll emit the hashes and offsets by doing a walk
191*855fc3bbSJonas Devlieghere   // during the emission phase. We add temporary symbols to the data so that we
192*855fc3bbSJonas Devlieghere   // can reference them during the offset later, we'll emit them when we emit
193*855fc3bbSJonas Devlieghere   // the data.
194*855fc3bbSJonas Devlieghere   computeBucketCount();
195*855fc3bbSJonas Devlieghere 
196*855fc3bbSJonas Devlieghere   // Compute bucket contents and final ordering.
197*855fc3bbSJonas Devlieghere   Buckets.resize(Header.getBucketCount());
198*855fc3bbSJonas Devlieghere   for (auto &D : Data) {
199*855fc3bbSJonas Devlieghere     uint32_t bucket = D->HashValue % Header.getBucketCount();
200*855fc3bbSJonas Devlieghere     Buckets[bucket].push_back(D);
201*855fc3bbSJonas Devlieghere     D->Sym = Asm->createTempSymbol(Prefix);
202*855fc3bbSJonas Devlieghere   }
203*855fc3bbSJonas Devlieghere 
204*855fc3bbSJonas Devlieghere   // Sort the contents of the buckets by hash value so that hash collisions end
205*855fc3bbSJonas Devlieghere   // up together. Stable sort makes testing easier and doesn't cost much more.
206*855fc3bbSJonas Devlieghere   for (auto &Bucket : Buckets)
207*855fc3bbSJonas Devlieghere     std::stable_sort(Bucket.begin(), Bucket.end(),
208*855fc3bbSJonas Devlieghere                      [](HashData *LHS, HashData *RHS) {
209*855fc3bbSJonas Devlieghere                        return LHS->HashValue < RHS->HashValue;
210*855fc3bbSJonas Devlieghere                      });
211*855fc3bbSJonas Devlieghere }
212*855fc3bbSJonas Devlieghere 
213*855fc3bbSJonas Devlieghere void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
214*855fc3bbSJonas Devlieghere   Asm->EmitInt32(Die->getDebugSectionOffset());
215*855fc3bbSJonas Devlieghere }
216*855fc3bbSJonas Devlieghere 
217*855fc3bbSJonas Devlieghere void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
218*855fc3bbSJonas Devlieghere   Asm->EmitInt32(Die->getDebugSectionOffset());
219*855fc3bbSJonas Devlieghere   Asm->EmitInt16(Die->getTag());
220*855fc3bbSJonas Devlieghere   Asm->EmitInt8(0);
221*855fc3bbSJonas Devlieghere }
222