DwarfAccelTable.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //=-- 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. #include "DwarfAccelTable.h"
  14. #include "DwarfCompileUnit.h"
  15. #include "DwarfDebug.h"
  16. #include "llvm/ADT/STLExtras.h"
  17. #include "llvm/ADT/Twine.h"
  18. #include "llvm/CodeGen/AsmPrinter.h"
  19. #include "llvm/CodeGen/DIE.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"
  24. using namespace llvm;
  25. // The length of the header data is always going to be 4 + 4 + 4*NumAtoms.
  26. DwarfAccelTable::DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom> atomList)
  27. : Header(8 + (atomList.size() * 4)), HeaderData(atomList),
  28. Entries(Allocator) {}
  29. void DwarfAccelTable::AddName(DwarfStringPoolEntryRef Name, const DIE *die,
  30. char Flags) {
  31. assert(Data.empty() && "Already finalized!");
  32. // If the string is in the list already then add this die to the list
  33. // otherwise add a new one.
  34. DataArray &DIEs = Entries[Name.getString()];
  35. assert(!DIEs.Name || DIEs.Name == Name);
  36. DIEs.Name = Name;
  37. DIEs.Values.push_back(new (Allocator) HashDataContents(die, Flags));
  38. }
  39. void DwarfAccelTable::ComputeBucketCount(void) {
  40. // First get the number of unique hashes.
  41. std::vector<uint32_t> uniques(Data.size());
  42. for (size_t i = 0, e = Data.size(); i < e; ++i)
  43. uniques[i] = Data[i]->HashValue;
  44. array_pod_sort(uniques.begin(), uniques.end());
  45. std::vector<uint32_t>::iterator p =
  46. std::unique(uniques.begin(), uniques.end());
  47. uint32_t num = std::distance(uniques.begin(), p);
  48. // Then compute the bucket size, minimum of 1 bucket.
  49. if (num > 1024)
  50. Header.bucket_count = num / 4;
  51. else if (num > 16)
  52. Header.bucket_count = num / 2;
  53. else
  54. Header.bucket_count = num > 0 ? num : 1;
  55. Header.hashes_count = num;
  56. }
  57. // compareDIEs - comparison predicate that sorts DIEs by their offset.
  58. static bool compareDIEs(const DwarfAccelTable::HashDataContents *A,
  59. const DwarfAccelTable::HashDataContents *B) {
  60. return A->Die->getOffset() < B->Die->getOffset();
  61. }
  62. void DwarfAccelTable::FinalizeTable(AsmPrinter *Asm, StringRef Prefix) {
  63. // Create the individual hash data outputs.
  64. Data.reserve(Entries.size());
  65. for (StringMap<DataArray>::iterator EI = Entries.begin(), EE = Entries.end();
  66. EI != EE; ++EI) {
  67. // Unique the entries.
  68. std::stable_sort(EI->second.Values.begin(), EI->second.Values.end(), compareDIEs);
  69. EI->second.Values.erase(
  70. std::unique(EI->second.Values.begin(), EI->second.Values.end()),
  71. EI->second.Values.end());
  72. HashData *Entry = new (Allocator) HashData(EI->getKey(), EI->second);
  73. Data.push_back(Entry);
  74. }
  75. // Figure out how many buckets we need, then compute the bucket
  76. // contents and the final ordering. We'll emit the hashes and offsets
  77. // by doing a walk during the emission phase. We add temporary
  78. // symbols to the data so that we can reference them during the offset
  79. // later, we'll emit them when we emit the data.
  80. ComputeBucketCount();
  81. // Compute bucket contents and final ordering.
  82. Buckets.resize(Header.bucket_count);
  83. for (size_t i = 0, e = Data.size(); i < e; ++i) {
  84. uint32_t bucket = Data[i]->HashValue % Header.bucket_count;
  85. Buckets[bucket].push_back(Data[i]);
  86. Data[i]->Sym = Asm->createTempSymbol(Prefix);
  87. }
  88. // Sort the contents of the buckets by hash value so that hash
  89. // collisions end up together. Stable sort makes testing easier and
  90. // doesn't cost much more.
  91. for (size_t i = 0; i < Buckets.size(); ++i)
  92. std::stable_sort(Buckets[i].begin(), Buckets[i].end(),
  93. [] (HashData *LHS, HashData *RHS) {
  94. return LHS->HashValue < RHS->HashValue;
  95. });
  96. }
  97. // Emits the header for the table via the AsmPrinter.
  98. void 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];
  117. Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.type));
  118. Asm->EmitInt16(A.type);
  119. Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.form));
  120. Asm->EmitInt16(A.form);
  121. }
  122. }
  123. // Walk through and emit the buckets for the table. Each index is
  124. // an offset into the list of hashes.
  125. void DwarfAccelTable::EmitBuckets(AsmPrinter *Asm) {
  126. unsigned index = 0;
  127. for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
  128. Asm->OutStreamer->AddComment("Bucket " + Twine(i));
  129. if (Buckets[i].size() != 0)
  130. Asm->EmitInt32(index);
  131. else
  132. Asm->EmitInt32(UINT32_MAX);
  133. // Buckets point in the list of hashes, not to the data. Do not
  134. // increment the index multiple times in case of hash collisions.
  135. uint64_t PrevHash = UINT64_MAX;
  136. for (auto *HD : Buckets[i]) {
  137. uint32_t HashValue = HD->HashValue;
  138. if (PrevHash != HashValue)
  139. ++index;
  140. PrevHash = HashValue;
  141. }
  142. }
  143. }
  144. // Walk through the buckets and emit the individual hashes for each
  145. // bucket.
  146. void DwarfAccelTable::EmitHashes(AsmPrinter *Asm) {
  147. uint64_t PrevHash = UINT64_MAX;
  148. for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
  149. for (HashList::const_iterator HI = Buckets[i].begin(),
  150. HE = Buckets[i].end();
  151. HI != HE; ++HI) {
  152. uint32_t HashValue = (*HI)->HashValue;
  153. if (PrevHash == HashValue)
  154. continue;
  155. Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(i));
  156. Asm->EmitInt32(HashValue);
  157. PrevHash = HashValue;
  158. }
  159. }
  160. }
  161. // Walk through the buckets and emit the individual offsets for each
  162. // element in each bucket. This is done via a symbol subtraction from the
  163. // beginning of the section. The non-section symbol will be output later
  164. // when we emit the actual data.
  165. void DwarfAccelTable::emitOffsets(AsmPrinter *Asm, const MCSymbol *SecBegin) {
  166. uint64_t PrevHash = UINT64_MAX;
  167. for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
  168. for (HashList::const_iterator HI = Buckets[i].begin(),
  169. HE = Buckets[i].end();
  170. HI != HE; ++HI) {
  171. uint32_t HashValue = (*HI)->HashValue;
  172. if (PrevHash == HashValue)
  173. continue;
  174. PrevHash = HashValue;
  175. Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
  176. MCContext &Context = Asm->OutStreamer->getContext();
  177. const MCExpr *Sub = MCBinaryExpr::createSub(
  178. MCSymbolRefExpr::create((*HI)->Sym, Context),
  179. MCSymbolRefExpr::create(SecBegin, Context), Context);
  180. Asm->OutStreamer->EmitValue(Sub, sizeof(uint32_t));
  181. }
  182. }
  183. }
  184. // Walk through the buckets and emit the full data for each element in
  185. // the bucket. For the string case emit the dies and the various offsets.
  186. // Terminate each HashData bucket with 0.
  187. void DwarfAccelTable::EmitData(AsmPrinter *Asm, DwarfDebug *D) {
  188. for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
  189. uint64_t PrevHash = UINT64_MAX;
  190. for (HashList::const_iterator HI = Buckets[i].begin(),
  191. HE = Buckets[i].end();
  192. HI != HE; ++HI) {
  193. // Terminate the previous entry if there is no hash collision
  194. // with the current one.
  195. if (PrevHash != UINT64_MAX && PrevHash != (*HI)->HashValue)
  196. Asm->EmitInt32(0);
  197. // Remember to emit the label for our offset.
  198. Asm->OutStreamer->EmitLabel((*HI)->Sym);
  199. Asm->OutStreamer->AddComment((*HI)->Str);
  200. Asm->emitDwarfStringOffset((*HI)->Data.Name);
  201. Asm->OutStreamer->AddComment("Num DIEs");
  202. Asm->EmitInt32((*HI)->Data.Values.size());
  203. for (HashDataContents *HD : (*HI)->Data.Values) {
  204. // Emit the DIE offset
  205. DwarfCompileUnit *CU = D->lookupUnit(HD->Die->getUnit());
  206. assert(CU && "Accelerated DIE should belong to a CU.");
  207. Asm->EmitInt32(HD->Die->getOffset() + CU->getDebugInfoOffset());
  208. // If we have multiple Atoms emit that info too.
  209. // FIXME: A bit of a hack, we either emit only one atom or all info.
  210. if (HeaderData.Atoms.size() > 1) {
  211. Asm->EmitInt16(HD->Die->getTag());
  212. Asm->EmitInt8(HD->Flags);
  213. }
  214. }
  215. PrevHash = (*HI)->HashValue;
  216. }
  217. // Emit the final end marker for the bucket.
  218. if (!Buckets[i].empty())
  219. Asm->EmitInt32(0);
  220. }
  221. }
  222. // Emit the entire data structure to the output file.
  223. void DwarfAccelTable::emit(AsmPrinter *Asm, const MCSymbol *SecBegin,
  224. DwarfDebug *D) {
  225. // Emit the header.
  226. EmitHeader(Asm);
  227. // Emit the buckets.
  228. EmitBuckets(Asm);
  229. // Emit the hashes.
  230. EmitHashes(Asm);
  231. // Emit the offsets.
  232. emitOffsets(Asm, SecBegin);
  233. // Emit the hash data.
  234. EmitData(Asm, D);
  235. }
  236. #ifndef NDEBUG
  237. void DwarfAccelTable::print(raw_ostream &O) {
  238. Header.print(O);
  239. HeaderData.print(O);
  240. O << "Entries: \n";
  241. for (StringMap<DataArray>::const_iterator EI = Entries.begin(),
  242. EE = Entries.end();
  243. EI != EE; ++EI) {
  244. O << "Name: " << EI->getKeyData() << "\n";
  245. for (HashDataContents *HD : EI->second.Values)
  246. HD->print(O);
  247. }
  248. O << "Buckets and Hashes: \n";
  249. for (size_t i = 0, e = Buckets.size(); i < e; ++i)
  250. for (HashList::const_iterator HI = Buckets[i].begin(),
  251. HE = Buckets[i].end();
  252. HI != HE; ++HI)
  253. (*HI)->print(O);
  254. O << "Data: \n";
  255. for (std::vector<HashData *>::const_iterator DI = Data.begin(),
  256. DE = Data.end();
  257. DI != DE; ++DI)
  258. (*DI)->print(O);
  259. }
  260. #endif