1 //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===// 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 accelerator tables. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/CodeGen/AccelTable.h" 15 #include "DwarfCompileUnit.h" 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/StringMap.h" 18 #include "llvm/ADT/Twine.h" 19 #include "llvm/BinaryFormat/Dwarf.h" 20 #include "llvm/CodeGen/AsmPrinter.h" 21 #include "llvm/CodeGen/DIE.h" 22 #include "llvm/MC/MCExpr.h" 23 #include "llvm/MC/MCStreamer.h" 24 #include "llvm/Support/raw_ostream.h" 25 #include <algorithm> 26 #include <cstddef> 27 #include <cstdint> 28 #include <limits> 29 #include <vector> 30 31 using namespace llvm; 32 33 void AccelTableBase::computeBucketCount() { 34 // First get the number of unique hashes. 35 std::vector<uint32_t> Uniques; 36 Uniques.reserve(Entries.size()); 37 for (const auto &E : Entries) 38 Uniques.push_back(E.second.HashValue); 39 array_pod_sort(Uniques.begin(), Uniques.end()); 40 std::vector<uint32_t>::iterator P = 41 std::unique(Uniques.begin(), Uniques.end()); 42 43 UniqueHashCount = std::distance(Uniques.begin(), P); 44 45 if (UniqueHashCount > 1024) 46 BucketCount = UniqueHashCount / 4; 47 else if (UniqueHashCount > 16) 48 BucketCount = UniqueHashCount / 2; 49 else 50 BucketCount = std::max<uint32_t>(UniqueHashCount, 1); 51 } 52 53 void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) { 54 // Create the individual hash data outputs. 55 for (auto &E : Entries) { 56 // Unique the entries. 57 std::stable_sort(E.second.Values.begin(), E.second.Values.end(), 58 [](const AccelTableData *A, const AccelTableData *B) { 59 return *A < *B; 60 }); 61 E.second.Values.erase( 62 std::unique(E.second.Values.begin(), E.second.Values.end()), 63 E.second.Values.end()); 64 } 65 66 // Figure out how many buckets we need, then compute the bucket contents and 67 // the final ordering. The hashes and offsets can be emitted by walking these 68 // data structures. We add temporary symbols to the data so they can be 69 // referenced when emitting the offsets. 70 computeBucketCount(); 71 72 // Compute bucket contents and final ordering. 73 Buckets.resize(BucketCount); 74 for (auto &E : Entries) { 75 uint32_t Bucket = E.second.HashValue % BucketCount; 76 Buckets[Bucket].push_back(&E.second); 77 E.second.Sym = Asm->createTempSymbol(Prefix); 78 } 79 80 // Sort the contents of the buckets by hash value so that hash collisions end 81 // up together. Stable sort makes testing easier and doesn't cost much more. 82 for (auto &Bucket : Buckets) 83 std::stable_sort(Bucket.begin(), Bucket.end(), 84 [](HashData *LHS, HashData *RHS) { 85 return LHS->HashValue < RHS->HashValue; 86 }); 87 } 88 89 namespace { 90 /// Base class for writing out Accelerator tables. It holds the common 91 /// functionality for the two Accelerator table types. 92 class AccelTableWriter { 93 protected: 94 AsmPrinter *const Asm; ///< Destination. 95 const AccelTableBase &Contents; ///< Data to emit. 96 97 /// Controls whether to emit duplicate hash and offset table entries for names 98 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5 99 /// tables do. 100 const bool SkipIdenticalHashes; 101 102 void emitHashes() const; 103 104 /// Emit offsets to lists of entries with identical names. The offsets are 105 /// relative to the Base argument. 106 void emitOffsets(const MCSymbol *Base) const; 107 108 public: 109 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 110 bool SkipIdenticalHashes) 111 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) { 112 } 113 }; 114 115 class AppleAccelTableWriter : public AccelTableWriter { 116 using Atom = AppleAccelTableData::Atom; 117 118 /// The fixed header of an Apple Accelerator Table. 119 struct Header { 120 uint32_t Magic = MagicHash; 121 uint16_t Version = 1; 122 uint16_t HashFunction = dwarf::DW_hash_function_djb; 123 uint32_t BucketCount; 124 uint32_t HashCount; 125 uint32_t HeaderDataLength; 126 127 /// 'HASH' magic value to detect endianness. 128 static const uint32_t MagicHash = 0x48415348; 129 130 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength) 131 : BucketCount(BucketCount), HashCount(UniqueHashCount), 132 HeaderDataLength(DataLength) {} 133 134 void emit(AsmPrinter *Asm) const; 135 #ifndef NDEBUG 136 void print(raw_ostream &OS) const; 137 void dump() const { print(dbgs()); } 138 #endif 139 }; 140 141 /// The HeaderData describes the structure of an Apple accelerator table 142 /// through a list of Atoms. 143 struct HeaderData { 144 /// In the case of data that is referenced via DW_FORM_ref_* the offset 145 /// base is used to describe the offset for all forms in the list of atoms. 146 uint32_t DieOffsetBase; 147 148 const SmallVector<Atom, 4> Atoms; 149 150 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0) 151 : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {} 152 153 void emit(AsmPrinter *Asm) const; 154 #ifndef NDEBUG 155 void print(raw_ostream &OS) const; 156 void dump() const { print(dbgs()); } 157 #endif 158 }; 159 160 Header Header; 161 HeaderData HeaderData; 162 const MCSymbol *SecBegin; 163 164 void emitBuckets() const; 165 void emitData() const; 166 167 public: 168 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 169 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin) 170 : AccelTableWriter(Asm, Contents, true), 171 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(), 172 8 + (Atoms.size() * 4)), 173 HeaderData(Atoms), SecBegin(SecBegin) {} 174 175 void emit() const; 176 177 #ifndef NDEBUG 178 void print(raw_ostream &OS) const; 179 void dump() const { print(dbgs()); } 180 #endif 181 }; 182 183 /// Class responsible for emitting a DWARF v5 Accelerator Table. The only public 184 /// function is emit(), which performs the actual emission. 185 class Dwarf5AccelTableWriter : public AccelTableWriter { 186 struct Header { 187 uint32_t UnitLength = 0; 188 uint16_t Version = 5; 189 uint16_t Padding = 0; 190 uint32_t CompUnitCount; 191 uint32_t LocalTypeUnitCount = 0; 192 uint32_t ForeignTypeUnitCount = 0; 193 uint32_t BucketCount; 194 uint32_t NameCount; 195 uint32_t AbbrevTableSize = 0; 196 uint32_t AugmentationStringSize = sizeof(AugmentationString); 197 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'}; 198 199 Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount) 200 : CompUnitCount(CompUnitCount), BucketCount(BucketCount), 201 NameCount(NameCount) {} 202 203 void emit(const Dwarf5AccelTableWriter &Ctx) const; 204 }; 205 struct AttributeEncoding { 206 dwarf::Index Index; 207 dwarf::Form Form; 208 }; 209 210 Header Header; 211 DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations; 212 std::unique_ptr<AccelTableWriterInfo> WriterInfo; 213 MCSymbol *ContributionStart = Asm->createTempSymbol("names_start"); 214 MCSymbol *ContributionEnd = Asm->createTempSymbol("names_end"); 215 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start"); 216 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end"); 217 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries"); 218 219 DenseSet<uint32_t> getUniqueTags() const; 220 221 // Right now, we emit uniform attributes for all tags. 222 SmallVector<AttributeEncoding, 2> getUniformAttributes() const; 223 224 void emitCUList() const; 225 void emitBuckets() const; 226 void emitStringOffsets() const; 227 void emitAbbrevs() const; 228 void emitEntry(const DWARF5AccelTableData &Data) const; 229 void emitData() const; 230 231 public: 232 Dwarf5AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents, 233 std::unique_ptr<AccelTableWriterInfo> WriterInfo); 234 235 void emit() const; 236 }; 237 238 /// Default emitter info used by DwarfDebug. 239 class DefaultAccelTableWriterInfo final : public AccelTableWriterInfo { 240 private: 241 const DwarfDebug ⅅ 242 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits; 243 244 public: 245 DefaultAccelTableWriterInfo(const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits); 246 MCSymbol *getLabelForCU(unsigned Idx) const override; 247 unsigned getNumberOfCUs() const override; 248 unsigned getUnqiueIDForUnitDie(const DIE *UnitDie) const override; 249 }; 250 } // namespace 251 252 DefaultAccelTableWriterInfo::DefaultAccelTableWriterInfo( 253 const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CompUnits) 254 : DD(DD), CompUnits(CompUnits) {} 255 256 MCSymbol *DefaultAccelTableWriterInfo::getLabelForCU(unsigned Idx) const { 257 assert(Idx < CompUnits.size()); 258 const auto &CU = CompUnits[Idx]; 259 assert(Idx == CU->getUniqueID()); 260 const DwarfCompileUnit *MainCU = 261 DD.useSplitDwarf() ? CU->getSkeleton() : CU.get(); 262 return MainCU->getLabelBegin(); 263 } 264 265 unsigned DefaultAccelTableWriterInfo::getNumberOfCUs() const { 266 return CompUnits.size(); 267 } 268 269 unsigned 270 DefaultAccelTableWriterInfo::getUnqiueIDForUnitDie(const DIE *UnitDie) const { 271 return DD.lookupCU(UnitDie)->getUniqueID(); 272 } 273 274 void AccelTableWriter::emitHashes() const { 275 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 276 unsigned BucketIdx = 0; 277 for (auto &Bucket : Contents.getBuckets()) { 278 for (auto &Hash : Bucket) { 279 uint32_t HashValue = Hash->HashValue; 280 if (SkipIdenticalHashes && PrevHash == HashValue) 281 continue; 282 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx)); 283 Asm->emitInt32(HashValue); 284 PrevHash = HashValue; 285 } 286 BucketIdx++; 287 } 288 } 289 290 void AccelTableWriter::emitOffsets(const MCSymbol *Base) const { 291 const auto &Buckets = Contents.getBuckets(); 292 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 293 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 294 for (auto *Hash : Buckets[i]) { 295 uint32_t HashValue = Hash->HashValue; 296 if (SkipIdenticalHashes && PrevHash == HashValue) 297 continue; 298 PrevHash = HashValue; 299 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i)); 300 Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t)); 301 } 302 } 303 } 304 305 void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const { 306 Asm->OutStreamer->AddComment("Header Magic"); 307 Asm->emitInt32(Magic); 308 Asm->OutStreamer->AddComment("Header Version"); 309 Asm->emitInt16(Version); 310 Asm->OutStreamer->AddComment("Header Hash Function"); 311 Asm->emitInt16(HashFunction); 312 Asm->OutStreamer->AddComment("Header Bucket Count"); 313 Asm->emitInt32(BucketCount); 314 Asm->OutStreamer->AddComment("Header Hash Count"); 315 Asm->emitInt32(HashCount); 316 Asm->OutStreamer->AddComment("Header Data Length"); 317 Asm->emitInt32(HeaderDataLength); 318 } 319 320 void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const { 321 Asm->OutStreamer->AddComment("HeaderData Die Offset Base"); 322 Asm->emitInt32(DieOffsetBase); 323 Asm->OutStreamer->AddComment("HeaderData Atom Count"); 324 Asm->emitInt32(Atoms.size()); 325 326 for (const Atom &A : Atoms) { 327 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type)); 328 Asm->emitInt16(A.Type); 329 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form)); 330 Asm->emitInt16(A.Form); 331 } 332 } 333 334 void AppleAccelTableWriter::emitBuckets() const { 335 const auto &Buckets = Contents.getBuckets(); 336 unsigned index = 0; 337 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 338 Asm->OutStreamer->AddComment("Bucket " + Twine(i)); 339 if (!Buckets[i].empty()) 340 Asm->emitInt32(index); 341 else 342 Asm->emitInt32(std::numeric_limits<uint32_t>::max()); 343 // Buckets point in the list of hashes, not to the data. Do not increment 344 // the index multiple times in case of hash collisions. 345 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 346 for (auto *HD : Buckets[i]) { 347 uint32_t HashValue = HD->HashValue; 348 if (PrevHash != HashValue) 349 ++index; 350 PrevHash = HashValue; 351 } 352 } 353 } 354 355 void AppleAccelTableWriter::emitData() const { 356 const auto &Buckets = Contents.getBuckets(); 357 for (size_t i = 0, e = Buckets.size(); i < e; ++i) { 358 uint64_t PrevHash = std::numeric_limits<uint64_t>::max(); 359 for (auto &Hash : Buckets[i]) { 360 // Terminate the previous entry if there is no hash collision with the 361 // current one. 362 if (PrevHash != std::numeric_limits<uint64_t>::max() && 363 PrevHash != Hash->HashValue) 364 Asm->emitInt32(0); 365 // Remember to emit the label for our offset. 366 Asm->OutStreamer->EmitLabel(Hash->Sym); 367 Asm->OutStreamer->AddComment(Hash->Name.getString()); 368 Asm->emitDwarfStringOffset(Hash->Name); 369 Asm->OutStreamer->AddComment("Num DIEs"); 370 Asm->emitInt32(Hash->Values.size()); 371 for (const auto *V : Hash->Values) 372 static_cast<const AppleAccelTableData *>(V)->emit(Asm); 373 PrevHash = Hash->HashValue; 374 } 375 // Emit the final end marker for the bucket. 376 if (!Buckets[i].empty()) 377 Asm->emitInt32(0); 378 } 379 } 380 381 void AppleAccelTableWriter::emit() const { 382 Header.emit(Asm); 383 HeaderData.emit(Asm); 384 emitBuckets(); 385 emitHashes(); 386 emitOffsets(SecBegin); 387 emitData(); 388 } 389 390 void Dwarf5AccelTableWriter::Header::emit( 391 const Dwarf5AccelTableWriter &Ctx) const { 392 assert(CompUnitCount > 0 && "Index must have at least one CU."); 393 394 AsmPrinter *Asm = Ctx.Asm; 395 Asm->OutStreamer->AddComment("Header: unit length"); 396 Asm->EmitLabelDifference(Ctx.ContributionEnd, Ctx.ContributionStart, 397 sizeof(uint32_t)); 398 Asm->OutStreamer->EmitLabel(Ctx.ContributionStart); 399 Asm->OutStreamer->AddComment("Header: version"); 400 Asm->emitInt16(Version); 401 Asm->OutStreamer->AddComment("Header: padding"); 402 Asm->emitInt16(Padding); 403 Asm->OutStreamer->AddComment("Header: compilation unit count"); 404 Asm->emitInt32(CompUnitCount); 405 Asm->OutStreamer->AddComment("Header: local type unit count"); 406 Asm->emitInt32(LocalTypeUnitCount); 407 Asm->OutStreamer->AddComment("Header: foreign type unit count"); 408 Asm->emitInt32(ForeignTypeUnitCount); 409 Asm->OutStreamer->AddComment("Header: bucket count"); 410 Asm->emitInt32(BucketCount); 411 Asm->OutStreamer->AddComment("Header: name count"); 412 Asm->emitInt32(NameCount); 413 Asm->OutStreamer->AddComment("Header: abbreviation table size"); 414 Asm->EmitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t)); 415 Asm->OutStreamer->AddComment("Header: augmentation string size"); 416 assert(AugmentationStringSize % 4 == 0); 417 Asm->emitInt32(AugmentationStringSize); 418 Asm->OutStreamer->AddComment("Header: augmentation string"); 419 Asm->OutStreamer->EmitBytes({AugmentationString, AugmentationStringSize}); 420 } 421 422 DenseSet<uint32_t> Dwarf5AccelTableWriter::getUniqueTags() const { 423 DenseSet<uint32_t> UniqueTags; 424 for (auto &Bucket : Contents.getBuckets()) { 425 for (auto *Hash : Bucket) { 426 for (auto *Value : Hash->Values) { 427 const DIE &Die = 428 static_cast<const DWARF5AccelTableData *>(Value)->getDie(); 429 UniqueTags.insert(Die.getTag()); 430 } 431 } 432 } 433 return UniqueTags; 434 } 435 436 SmallVector<Dwarf5AccelTableWriter::AttributeEncoding, 2> 437 Dwarf5AccelTableWriter::getUniformAttributes() const { 438 SmallVector<AttributeEncoding, 2> UA; 439 if (WriterInfo->getNumberOfCUs() > 1) { 440 size_t LargestCUIndex = WriterInfo->getNumberOfCUs() - 1; 441 dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex); 442 UA.push_back({dwarf::DW_IDX_compile_unit, Form}); 443 } 444 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); 445 return UA; 446 } 447 448 void Dwarf5AccelTableWriter::emitCUList() const { 449 for (unsigned Idx = 0, CUs = WriterInfo->getNumberOfCUs(); Idx < CUs; 450 ++Idx) { 451 Asm->OutStreamer->AddComment("Compilation unit " + Twine(Idx)); 452 Asm->emitDwarfSymbolReference(WriterInfo->getLabelForCU(Idx)); 453 } 454 } 455 456 void Dwarf5AccelTableWriter::emitBuckets() const { 457 uint32_t Index = 1; 458 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 459 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index())); 460 Asm->emitInt32(Bucket.value().empty() ? 0 : Index); 461 Index += Bucket.value().size(); 462 } 463 } 464 465 void Dwarf5AccelTableWriter::emitStringOffsets() const { 466 for (const auto &Bucket : enumerate(Contents.getBuckets())) { 467 for (auto *Hash : Bucket.value()) { 468 DwarfStringPoolEntryRef String = Hash->Name; 469 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) + 470 ": " + String.getString()); 471 Asm->emitDwarfStringOffset(String); 472 } 473 } 474 } 475 476 void Dwarf5AccelTableWriter::emitAbbrevs() const { 477 Asm->OutStreamer->EmitLabel(AbbrevStart); 478 for (const auto &Abbrev : Abbreviations) { 479 Asm->OutStreamer->AddComment("Abbrev code"); 480 assert(Abbrev.first != 0); 481 Asm->EmitULEB128(Abbrev.first); 482 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first)); 483 Asm->EmitULEB128(Abbrev.first); 484 for (const auto &AttrEnc : Abbrev.second) { 485 Asm->EmitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data()); 486 Asm->EmitULEB128(AttrEnc.Form, 487 dwarf::FormEncodingString(AttrEnc.Form).data()); 488 } 489 Asm->EmitULEB128(0, "End of abbrev"); 490 Asm->EmitULEB128(0, "End of abbrev"); 491 } 492 Asm->EmitULEB128(0, "End of abbrev list"); 493 Asm->OutStreamer->EmitLabel(AbbrevEnd); 494 } 495 496 void Dwarf5AccelTableWriter::emitEntry( 497 const DWARF5AccelTableData &Entry) const { 498 auto AbbrevIt = Abbreviations.find(Entry.getDie().getTag()); 499 assert(AbbrevIt != Abbreviations.end() && 500 "Why wasn't this abbrev generated?"); 501 502 Asm->EmitULEB128(AbbrevIt->first, "Abbreviation code"); 503 for (const auto &AttrEnc : AbbrevIt->second) { 504 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index)); 505 switch (AttrEnc.Index) { 506 case dwarf::DW_IDX_compile_unit: { 507 const DIE *CUDie = Entry.getDie().getUnitDie(); 508 DIEInteger ID(WriterInfo->getUnqiueIDForUnitDie(CUDie)); 509 ID.EmitValue(Asm, AttrEnc.Form); 510 break; 511 } 512 case dwarf::DW_IDX_die_offset: 513 assert(AttrEnc.Form == dwarf::DW_FORM_ref4); 514 Asm->emitInt32(Entry.getDie().getOffset()); 515 break; 516 default: 517 llvm_unreachable("Unexpected index attribute!"); 518 } 519 } 520 } 521 522 void Dwarf5AccelTableWriter::emitData() const { 523 Asm->OutStreamer->EmitLabel(EntryPool); 524 for (auto &Bucket : Contents.getBuckets()) { 525 for (auto *Hash : Bucket) { 526 // Remember to emit the label for our offset. 527 Asm->OutStreamer->EmitLabel(Hash->Sym); 528 for (const auto *Value : Hash->Values) 529 emitEntry(*static_cast<const DWARF5AccelTableData *>(Value)); 530 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString()); 531 Asm->emitInt32(0); 532 } 533 } 534 } 535 536 Dwarf5AccelTableWriter::Dwarf5AccelTableWriter( 537 AsmPrinter *Asm, const AccelTableBase &Contents, 538 std::unique_ptr<AccelTableWriterInfo> WriterInfo) 539 : AccelTableWriter(Asm, Contents, false), 540 Header(WriterInfo->getNumberOfCUs(), Contents.getBucketCount(), 541 Contents.getUniqueNameCount()), 542 WriterInfo(std::move(WriterInfo)) { 543 DenseSet<uint32_t> UniqueTags = getUniqueTags(); 544 SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes(); 545 546 Abbreviations.reserve(UniqueTags.size()); 547 for (uint32_t Tag : UniqueTags) 548 Abbreviations.try_emplace(Tag, UniformAttributes); 549 } 550 551 void Dwarf5AccelTableWriter::emit() const { 552 Header.emit(*this); 553 emitCUList(); 554 emitBuckets(); 555 emitHashes(); 556 emitStringOffsets(); 557 emitOffsets(EntryPool); 558 emitAbbrevs(); 559 emitData(); 560 Asm->OutStreamer->EmitValueToAlignment(4, 0); 561 Asm->OutStreamer->EmitLabel(ContributionEnd); 562 } 563 564 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, 565 StringRef Prefix, const MCSymbol *SecBegin, 566 ArrayRef<AppleAccelTableData::Atom> Atoms) { 567 Contents.finalize(Asm, Prefix); 568 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit(); 569 } 570 571 void llvm::emitDWARF5AccelTable( 572 AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents, 573 const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) { 574 auto WriterInfo = llvm::make_unique<DefaultAccelTableWriterInfo>(DD, CUs); 575 emitDWARF5AccelTable(Asm, Contents, std::move(WriterInfo)); 576 } 577 578 void llvm::emitDWARF5AccelTable( 579 AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents, 580 std::unique_ptr<AccelTableWriterInfo> WriterInfo) { 581 Contents.finalize(Asm, "names"); 582 Dwarf5AccelTableWriter(Asm, Contents, std::move(WriterInfo)).emit(); 583 } 584 585 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const { 586 Asm->emitInt32(Die->getDebugSectionOffset()); 587 } 588 589 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const { 590 Asm->emitInt32(Die->getDebugSectionOffset()); 591 Asm->emitInt16(Die->getTag()); 592 Asm->emitInt8(0); 593 } 594 595 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const { 596 Asm->emitInt32(Offset); 597 } 598 599 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const { 600 Asm->emitInt32(Offset); 601 Asm->emitInt16(Tag); 602 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation 603 : 0); 604 Asm->emitInt32(QualifiedNameHash); 605 } 606 607 #ifndef _MSC_VER 608 // The lines below are rejected by older versions (TBD) of MSVC. 609 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[]; 610 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[]; 611 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[]; 612 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[]; 613 #else 614 // FIXME: Erase this path once the minimum MSCV version has been bumped. 615 const SmallVector<AppleAccelTableData::Atom, 4> 616 AppleAccelTableOffsetData::Atoms = { 617 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; 618 const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms = 619 {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), 620 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), 621 Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)}; 622 const SmallVector<AppleAccelTableData::Atom, 4> 623 AppleAccelTableStaticOffsetData::Atoms = { 624 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)}; 625 const SmallVector<AppleAccelTableData::Atom, 4> 626 AppleAccelTableStaticTypeData::Atoms = { 627 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4), 628 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), 629 Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)}; 630 #endif 631 632 #ifndef NDEBUG 633 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const { 634 OS << "Magic: " << format("0x%x", Magic) << "\n" 635 << "Version: " << Version << "\n" 636 << "Hash Function: " << HashFunction << "\n" 637 << "Bucket Count: " << BucketCount << "\n" 638 << "Header Data Length: " << HeaderDataLength << "\n"; 639 } 640 641 void AppleAccelTableData::Atom::print(raw_ostream &OS) const { 642 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" 643 << "Form: " << dwarf::FormEncodingString(Form) << "\n"; 644 } 645 646 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const { 647 OS << "DIE Offset Base: " << DieOffsetBase << "\n"; 648 for (auto Atom : Atoms) 649 Atom.print(OS); 650 } 651 652 void AppleAccelTableWriter::print(raw_ostream &OS) const { 653 Header.print(OS); 654 HeaderData.print(OS); 655 Contents.print(OS); 656 SecBegin->print(OS, nullptr); 657 } 658 659 void AccelTableBase::HashData::print(raw_ostream &OS) const { 660 OS << "Name: " << Name.getString() << "\n"; 661 OS << " Hash Value: " << format("0x%x", HashValue) << "\n"; 662 OS << " Symbol: "; 663 if (Sym) 664 OS << *Sym; 665 else 666 OS << "<none>"; 667 OS << "\n"; 668 for (auto *Value : Values) 669 Value->print(OS); 670 } 671 672 void AccelTableBase::print(raw_ostream &OS) const { 673 // Print Content. 674 OS << "Entries: \n"; 675 for (const auto &Entry : Entries) { 676 OS << "Name: " << Entry.first() << "\n"; 677 for (auto *V : Entry.second.Values) 678 V->print(OS); 679 } 680 681 OS << "Buckets and Hashes: \n"; 682 for (auto &Bucket : Buckets) 683 for (auto &Hash : Bucket) 684 Hash->print(OS); 685 686 OS << "Data: \n"; 687 for (auto &E : Entries) 688 E.second.print(OS); 689 } 690 691 void DWARF5AccelTableData::print(raw_ostream &OS) const { 692 OS << " Offset: " << Die.getOffset() << "\n"; 693 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n"; 694 } 695 696 void AppleAccelTableOffsetData::print(raw_ostream &OS) const { 697 OS << " Offset: " << Die->getOffset() << "\n"; 698 } 699 700 void AppleAccelTableTypeData::print(raw_ostream &OS) const { 701 OS << " Offset: " << Die->getOffset() << "\n"; 702 OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n"; 703 } 704 705 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const { 706 OS << " Static Offset: " << Offset << "\n"; 707 } 708 709 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const { 710 OS << " Static Offset: " << Offset << "\n"; 711 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n"; 712 OS << " Tag: " << dwarf::TagString(Tag) << "\n"; 713 OS << " ObjCClassIsImplementation: " 714 << (ObjCClassIsImplementation ? "true" : "false"); 715 OS << "\n"; 716 } 717 #endif 718