blob: d1eeb9308f2f6cdfa5ee7279f827798d56f931ba [file] [log] [blame]
Eric Christopher6e472042011-11-07 09:18:42 +00001//=-- llvm/CodeGen/DwarfAccelTable.cpp - Dwarf Accelerator Tables -*- C++ -*-=//
2//
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"
Craig Topper6e80c282012-03-26 06:58:25 +000015#include "DIE.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000016#include "DwarfDebug.h"
Benjamin Kramer3e6719c2012-03-26 14:17:26 +000017#include "llvm/ADT/STLExtras.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000018#include "llvm/ADT/Twine.h"
Eric Christopher6e472042011-11-07 09:18:42 +000019#include "llvm/CodeGen/AsmPrinter.h"
20#include "llvm/MC/MCExpr.h"
21#include "llvm/MC/MCStreamer.h"
22#include "llvm/MC/MCSymbol.h"
23#include "llvm/Support/Debug.h"
Eric Christopher6e472042011-11-07 09:18:42 +000024
25using namespace llvm;
26
Eric Christopher21bde872012-01-06 04:35:23 +000027// The length of the header data is always going to be 4 + 4 + 4*NumAtoms.
Eric Christopherb4e2cc42013-09-05 16:46:43 +000028DwarfAccelTable::DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom> atomList)
29 : Header(8 + (atomList.size() * 4)), HeaderData(atomList),
30 Entries(Allocator) {}
Eric Christopher21bde872012-01-06 04:35:23 +000031
David Blaikie2ea848b2013-11-19 22:51:04 +000032void DwarfAccelTable::AddName(StringRef Name, const DIE *die, char Flags) {
Benjamin Kramer330970d2012-04-13 20:06:17 +000033 assert(Data.empty() && "Already finalized!");
Eric Christopher6e472042011-11-07 09:18:42 +000034 // If the string is in the list already then add this die to the list
35 // otherwise add a new one.
Eric Christopher21bde872012-01-06 04:35:23 +000036 DataArray &DIEs = Entries[Name];
Benjamin Kramer330970d2012-04-13 20:06:17 +000037 DIEs.push_back(new (Allocator) HashDataContents(die, Flags));
Eric Christopher6e472042011-11-07 09:18:42 +000038}
39
40void DwarfAccelTable::ComputeBucketCount(void) {
41 // First get the number of unique hashes.
Benjamin Kramer3e6719c2012-03-26 14:17:26 +000042 std::vector<uint32_t> uniques(Data.size());
Eric Christopher54ce295d2011-11-08 18:38:40 +000043 for (size_t i = 0, e = Data.size(); i < e; ++i)
Eric Christopher6e472042011-11-07 09:18:42 +000044 uniques[i] = Data[i]->HashValue;
Benjamin Kramer3e6719c2012-03-26 14:17:26 +000045 array_pod_sort(uniques.begin(), uniques.end());
Eric Christopher6e472042011-11-07 09:18:42 +000046 std::vector<uint32_t>::iterator p =
Eric Christopherb4e2cc42013-09-05 16:46:43 +000047 std::unique(uniques.begin(), uniques.end());
Eric Christopher6e472042011-11-07 09:18:42 +000048 uint32_t num = std::distance(uniques.begin(), p);
49
50 // Then compute the bucket size, minimum of 1 bucket.
Eric Christopherb4e2cc42013-09-05 16:46:43 +000051 if (num > 1024)
52 Header.bucket_count = num / 4;
53 if (num > 16)
54 Header.bucket_count = num / 2;
55 else
56 Header.bucket_count = num > 0 ? num : 1;
Eric Christopher6e472042011-11-07 09:18:42 +000057
58 Header.hashes_count = num;
59}
60
Benjamin Kramer330970d2012-04-13 20:06:17 +000061// compareDIEs - comparison predicate that sorts DIEs by their offset.
62static bool compareDIEs(const DwarfAccelTable::HashDataContents *A,
63 const DwarfAccelTable::HashDataContents *B) {
64 return A->Die->getOffset() < B->Die->getOffset();
Eric Christopher0abbd0e2011-11-15 23:37:17 +000065}
66
Benjamin Kramer63e39eb2013-05-11 18:24:28 +000067void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, StringRef Prefix) {
Eric Christopher6e472042011-11-07 09:18:42 +000068 // Create the individual hash data outputs.
Eric Christopherb4e2cc42013-09-05 16:46:43 +000069 for (StringMap<DataArray>::iterator EI = Entries.begin(), EE = Entries.end();
70 EI != EE; ++EI) {
Eric Christopherd9843b32011-11-10 19:25:34 +000071
72 // Unique the entries.
Benjamin Kramer330970d2012-04-13 20:06:17 +000073 std::stable_sort(EI->second.begin(), EI->second.end(), compareDIEs);
Eric Christopher5a28a6e2012-01-06 23:03:27 +000074 EI->second.erase(std::unique(EI->second.begin(), EI->second.end()),
Eric Christopherb4e2cc42013-09-05 16:46:43 +000075 EI->second.end());
Eric Christopherd9843b32011-11-10 19:25:34 +000076
Benjamin Kramer330970d2012-04-13 20:06:17 +000077 HashData *Entry = new (Allocator) HashData(EI->getKey(), EI->second);
Eric Christopher6e472042011-11-07 09:18:42 +000078 Data.push_back(Entry);
79 }
80
81 // Figure out how many buckets we need, then compute the bucket
82 // contents and the final ordering. We'll emit the hashes and offsets
83 // by doing a walk during the emission phase. We add temporary
84 // symbols to the data so that we can reference them during the offset
85 // later, we'll emit them when we emit the data.
86 ComputeBucketCount();
87
88 // Compute bucket contents and final ordering.
89 Buckets.resize(Header.bucket_count);
Eric Christopher54ce295d2011-11-08 18:38:40 +000090 for (size_t i = 0, e = Data.size(); i < e; ++i) {
Eric Christopher6e472042011-11-07 09:18:42 +000091 uint32_t bucket = Data[i]->HashValue % Header.bucket_count;
92 Buckets[bucket].push_back(Data[i]);
93 Data[i]->Sym = Asm->GetTempSymbol(Prefix, i);
94 }
95}
96
97// Emits the header for the table via the AsmPrinter.
98void DwarfAccelTable::EmitHeader(AsmPrinter *Asm) {
99 Asm->OutStreamer.AddComment("Header Magic");
100 Asm->EmitInt32(Header.magic);
101 Asm->OutStreamer.AddComment("Header Version");
102 Asm->EmitInt16(Header.version);
103 Asm->OutStreamer.AddComment("Header Hash Function");
104 Asm->EmitInt16(Header.hash_function);
105 Asm->OutStreamer.AddComment("Header Bucket Count");
106 Asm->EmitInt32(Header.bucket_count);
107 Asm->OutStreamer.AddComment("Header Hash Count");
108 Asm->EmitInt32(Header.hashes_count);
109 Asm->OutStreamer.AddComment("Header Data Length");
110 Asm->EmitInt32(Header.header_data_len);
111 Asm->OutStreamer.AddComment("HeaderData Die Offset Base");
112 Asm->EmitInt32(HeaderData.die_offset_base);
113 Asm->OutStreamer.AddComment("HeaderData Atom Count");
114 Asm->EmitInt32(HeaderData.Atoms.size());
115 for (size_t i = 0; i < HeaderData.Atoms.size(); i++) {
116 Atom A = HeaderData.Atoms[i];
Eric Christophercf7289f2013-09-05 18:20:16 +0000117 Asm->OutStreamer.AddComment(dwarf::AtomTypeString(A.type));
Eric Christopher6e472042011-11-07 09:18:42 +0000118 Asm->EmitInt16(A.type);
119 Asm->OutStreamer.AddComment(dwarf::FormEncodingString(A.form));
120 Asm->EmitInt16(A.form);
121 }
122}
123
Eric Christopher28611362012-10-08 23:53:45 +0000124// Walk through and emit the buckets for the table. Each index is
125// an offset into the list of hashes.
Eric Christopher6e472042011-11-07 09:18:42 +0000126void DwarfAccelTable::EmitBuckets(AsmPrinter *Asm) {
127 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +0000128 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eric Christopher2c5dab52011-11-07 18:34:47 +0000129 Asm->OutStreamer.AddComment("Bucket " + Twine(i));
Eric Christopher6e472042011-11-07 09:18:42 +0000130 if (Buckets[i].size() != 0)
131 Asm->EmitInt32(index);
132 else
133 Asm->EmitInt32(UINT32_MAX);
134 index += Buckets[i].size();
135 }
136}
137
138// Walk through the buckets and emit the individual hashes for each
139// bucket.
140void DwarfAccelTable::EmitHashes(AsmPrinter *Asm) {
Eric Christopher54ce295d2011-11-08 18:38:40 +0000141 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eric Christopher6e472042011-11-07 09:18:42 +0000142 for (HashList::const_iterator HI = Buckets[i].begin(),
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000143 HE = Buckets[i].end();
144 HI != HE; ++HI) {
Eric Christopher2c5dab52011-11-07 18:34:47 +0000145 Asm->OutStreamer.AddComment("Hash in Bucket " + Twine(i));
Eric Christopher6e472042011-11-07 09:18:42 +0000146 Asm->EmitInt32((*HI)->HashValue);
Eric Christopher48fef592012-12-20 21:58:40 +0000147 }
Eric Christopher6e472042011-11-07 09:18:42 +0000148 }
149}
150
151// Walk through the buckets and emit the individual offsets for each
152// element in each bucket. This is done via a symbol subtraction from the
153// beginning of the section. The non-section symbol will be output later
154// when we emit the actual data.
155void DwarfAccelTable::EmitOffsets(AsmPrinter *Asm, MCSymbol *SecBegin) {
Eric Christopher54ce295d2011-11-08 18:38:40 +0000156 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eric Christopher6e472042011-11-07 09:18:42 +0000157 for (HashList::const_iterator HI = Buckets[i].begin(),
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000158 HE = Buckets[i].end();
159 HI != HE; ++HI) {
Eric Christopher2c5dab52011-11-07 18:34:47 +0000160 Asm->OutStreamer.AddComment("Offset in Bucket " + Twine(i));
Eric Christopher6e472042011-11-07 09:18:42 +0000161 MCContext &Context = Asm->OutStreamer.getContext();
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000162 const MCExpr *Sub = MCBinaryExpr::CreateSub(
163 MCSymbolRefExpr::Create((*HI)->Sym, Context),
164 MCSymbolRefExpr::Create(SecBegin, Context), Context);
Eric Christopherbf7bc492013-01-09 03:52:05 +0000165 Asm->OutStreamer.EmitValue(Sub, sizeof(uint32_t));
Eric Christopher6e472042011-11-07 09:18:42 +0000166 }
167 }
168}
169
170// Walk through the buckets and emit the full data for each element in
171// the bucket. For the string case emit the dies and the various offsets.
172// Terminate each HashData bucket with 0.
Eric Christopherf8194852013-12-05 18:06:10 +0000173void DwarfAccelTable::EmitData(AsmPrinter *Asm, DwarfFile *D) {
Eric Christopher6e472042011-11-07 09:18:42 +0000174 uint64_t PrevHash = UINT64_MAX;
Eric Christopher54ce295d2011-11-08 18:38:40 +0000175 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eric Christopher6e472042011-11-07 09:18:42 +0000176 for (HashList::const_iterator HI = Buckets[i].begin(),
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000177 HE = Buckets[i].end();
178 HI != HE; ++HI) {
Eric Christopher6e472042011-11-07 09:18:42 +0000179 // Remember to emit the label for our offset.
180 Asm->OutStreamer.EmitLabel((*HI)->Sym);
181 Asm->OutStreamer.AddComment((*HI)->Str);
David Blaikiedaefdbf2014-04-25 21:34:35 +0000182 Asm->EmitSectionOffset(D->getStringPool().getSymbol(*Asm, (*HI)->Str),
183 D->getStringPool().getSectionSymbol());
Eric Christopher6e472042011-11-07 09:18:42 +0000184 Asm->OutStreamer.AddComment("Num DIEs");
Eric Christopher21bde872012-01-06 04:35:23 +0000185 Asm->EmitInt32((*HI)->Data.size());
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000186 for (ArrayRef<HashDataContents *>::const_iterator
187 DI = (*HI)->Data.begin(),
188 DE = (*HI)->Data.end();
Eric Christopher6e472042011-11-07 09:18:42 +0000189 DI != DE; ++DI) {
Eric Christopher21bde872012-01-06 04:35:23 +0000190 // Emit the DIE offset
191 Asm->EmitInt32((*DI)->Die->getOffset());
192 // If we have multiple Atoms emit that info too.
193 // FIXME: A bit of a hack, we either emit only one atom or all info.
194 if (HeaderData.Atoms.size() > 1) {
195 Asm->EmitInt16((*DI)->Die->getTag());
196 Asm->EmitInt8((*DI)->Flags);
197 }
Eric Christopher6e472042011-11-07 09:18:42 +0000198 }
199 // Emit a 0 to terminate the data unless we have a hash collision.
200 if (PrevHash != (*HI)->HashValue)
201 Asm->EmitInt32(0);
202 PrevHash = (*HI)->HashValue;
203 }
204 }
205}
206
207// Emit the entire data structure to the output file.
Eric Christopherf8194852013-12-05 18:06:10 +0000208void DwarfAccelTable::Emit(AsmPrinter *Asm, MCSymbol *SecBegin, DwarfFile *D) {
Eric Christopher6e472042011-11-07 09:18:42 +0000209 // Emit the header.
210 EmitHeader(Asm);
211
212 // Emit the buckets.
213 EmitBuckets(Asm);
214
215 // Emit the hashes.
216 EmitHashes(Asm);
217
218 // Emit the offsets.
219 EmitOffsets(Asm, SecBegin);
220
221 // Emit the hash data.
222 EmitData(Asm, D);
223}
224
225#ifndef NDEBUG
226void DwarfAccelTable::print(raw_ostream &O) {
227
228 Header.print(O);
229 HeaderData.print(O);
230
231 O << "Entries: \n";
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000232 for (StringMap<DataArray>::const_iterator EI = Entries.begin(),
233 EE = Entries.end();
234 EI != EE; ++EI) {
Eric Christopher5a28a6e2012-01-06 23:03:27 +0000235 O << "Name: " << EI->getKeyData() << "\n";
236 for (DataArray::const_iterator DI = EI->second.begin(),
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000237 DE = EI->second.end();
Eric Christopher6e472042011-11-07 09:18:42 +0000238 DI != DE; ++DI)
239 (*DI)->print(O);
240 }
241
242 O << "Buckets and Hashes: \n";
Eric Christopher54ce295d2011-11-08 18:38:40 +0000243 for (size_t i = 0, e = Buckets.size(); i < e; ++i)
Eric Christopher6e472042011-11-07 09:18:42 +0000244 for (HashList::const_iterator HI = Buckets[i].begin(),
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000245 HE = Buckets[i].end();
246 HI != HE; ++HI)
Eric Christopher6e472042011-11-07 09:18:42 +0000247 (*HI)->print(O);
248
249 O << "Data: \n";
Eric Christopherb4e2cc42013-09-05 16:46:43 +0000250 for (std::vector<HashData *>::const_iterator DI = Data.begin(),
251 DE = Data.end();
252 DI != DE; ++DI)
253 (*DI)->print(O);
Eric Christopher6e472042011-11-07 09:18:42 +0000254}
255#endif