xref: /openbsd-src/gnu/llvm/llvm/lib/CodeGen/AsmPrinter/AccelTable.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file contains support for writing accelerator tables.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #include "llvm/CodeGen/AccelTable.h"
1409467b48Spatrick #include "DwarfCompileUnit.h"
1509467b48Spatrick #include "llvm/ADT/STLExtras.h"
1609467b48Spatrick #include "llvm/ADT/StringMap.h"
1709467b48Spatrick #include "llvm/ADT/Twine.h"
1809467b48Spatrick #include "llvm/BinaryFormat/Dwarf.h"
1909467b48Spatrick #include "llvm/CodeGen/AsmPrinter.h"
2009467b48Spatrick #include "llvm/CodeGen/DIE.h"
2109467b48Spatrick #include "llvm/MC/MCStreamer.h"
2209467b48Spatrick #include "llvm/MC/MCSymbol.h"
2309467b48Spatrick #include "llvm/Support/raw_ostream.h"
2409467b48Spatrick #include "llvm/Target/TargetLoweringObjectFile.h"
2509467b48Spatrick #include <algorithm>
2609467b48Spatrick #include <cstddef>
2709467b48Spatrick #include <cstdint>
2809467b48Spatrick #include <limits>
2909467b48Spatrick #include <vector>
3009467b48Spatrick 
3109467b48Spatrick using namespace llvm;
3209467b48Spatrick 
computeBucketCount()3309467b48Spatrick void AccelTableBase::computeBucketCount() {
3409467b48Spatrick   // First get the number of unique hashes.
3509467b48Spatrick   std::vector<uint32_t> Uniques;
3609467b48Spatrick   Uniques.reserve(Entries.size());
3709467b48Spatrick   for (const auto &E : Entries)
3809467b48Spatrick     Uniques.push_back(E.second.HashValue);
3909467b48Spatrick   array_pod_sort(Uniques.begin(), Uniques.end());
4009467b48Spatrick   std::vector<uint32_t>::iterator P =
4109467b48Spatrick       std::unique(Uniques.begin(), Uniques.end());
4209467b48Spatrick 
4309467b48Spatrick   UniqueHashCount = std::distance(Uniques.begin(), P);
4409467b48Spatrick 
4509467b48Spatrick   if (UniqueHashCount > 1024)
4609467b48Spatrick     BucketCount = UniqueHashCount / 4;
4709467b48Spatrick   else if (UniqueHashCount > 16)
4809467b48Spatrick     BucketCount = UniqueHashCount / 2;
4909467b48Spatrick   else
5009467b48Spatrick     BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
5109467b48Spatrick }
5209467b48Spatrick 
finalize(AsmPrinter * Asm,StringRef Prefix)5309467b48Spatrick void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
5409467b48Spatrick   // Create the individual hash data outputs.
5509467b48Spatrick   for (auto &E : Entries) {
5609467b48Spatrick     // Unique the entries.
5709467b48Spatrick     llvm::stable_sort(E.second.Values,
5809467b48Spatrick                       [](const AccelTableData *A, const AccelTableData *B) {
5909467b48Spatrick                         return *A < *B;
6009467b48Spatrick                       });
6109467b48Spatrick     E.second.Values.erase(
6209467b48Spatrick         std::unique(E.second.Values.begin(), E.second.Values.end()),
6309467b48Spatrick         E.second.Values.end());
6409467b48Spatrick   }
6509467b48Spatrick 
6609467b48Spatrick   // Figure out how many buckets we need, then compute the bucket contents and
6709467b48Spatrick   // the final ordering. The hashes and offsets can be emitted by walking these
6809467b48Spatrick   // data structures. We add temporary symbols to the data so they can be
6909467b48Spatrick   // referenced when emitting the offsets.
7009467b48Spatrick   computeBucketCount();
7109467b48Spatrick 
7209467b48Spatrick   // Compute bucket contents and final ordering.
7309467b48Spatrick   Buckets.resize(BucketCount);
7409467b48Spatrick   for (auto &E : Entries) {
7509467b48Spatrick     uint32_t Bucket = E.second.HashValue % BucketCount;
7609467b48Spatrick     Buckets[Bucket].push_back(&E.second);
7709467b48Spatrick     E.second.Sym = Asm->createTempSymbol(Prefix);
7809467b48Spatrick   }
7909467b48Spatrick 
8009467b48Spatrick   // Sort the contents of the buckets by hash value so that hash collisions end
8109467b48Spatrick   // up together. Stable sort makes testing easier and doesn't cost much more.
8209467b48Spatrick   for (auto &Bucket : Buckets)
8309467b48Spatrick     llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
8409467b48Spatrick       return LHS->HashValue < RHS->HashValue;
8509467b48Spatrick     });
8609467b48Spatrick }
8709467b48Spatrick 
8809467b48Spatrick namespace {
8909467b48Spatrick /// Base class for writing out Accelerator tables. It holds the common
9009467b48Spatrick /// functionality for the two Accelerator table types.
9109467b48Spatrick class AccelTableWriter {
9209467b48Spatrick protected:
9309467b48Spatrick   AsmPrinter *const Asm;          ///< Destination.
9409467b48Spatrick   const AccelTableBase &Contents; ///< Data to emit.
9509467b48Spatrick 
9609467b48Spatrick   /// Controls whether to emit duplicate hash and offset table entries for names
9709467b48Spatrick   /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
9809467b48Spatrick   /// tables do.
9909467b48Spatrick   const bool SkipIdenticalHashes;
10009467b48Spatrick 
10109467b48Spatrick   void emitHashes() const;
10209467b48Spatrick 
10309467b48Spatrick   /// Emit offsets to lists of entries with identical names. The offsets are
10409467b48Spatrick   /// relative to the Base argument.
10509467b48Spatrick   void emitOffsets(const MCSymbol *Base) const;
10609467b48Spatrick 
10709467b48Spatrick public:
AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,bool SkipIdenticalHashes)10809467b48Spatrick   AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
10909467b48Spatrick                    bool SkipIdenticalHashes)
11009467b48Spatrick       : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
11109467b48Spatrick   }
11209467b48Spatrick };
11309467b48Spatrick 
11409467b48Spatrick class AppleAccelTableWriter : public AccelTableWriter {
11509467b48Spatrick   using Atom = AppleAccelTableData::Atom;
11609467b48Spatrick 
11709467b48Spatrick   /// The fixed header of an Apple Accelerator Table.
11809467b48Spatrick   struct Header {
11909467b48Spatrick     uint32_t Magic = MagicHash;
12009467b48Spatrick     uint16_t Version = 1;
12109467b48Spatrick     uint16_t HashFunction = dwarf::DW_hash_function_djb;
12209467b48Spatrick     uint32_t BucketCount;
12309467b48Spatrick     uint32_t HashCount;
12409467b48Spatrick     uint32_t HeaderDataLength;
12509467b48Spatrick 
12609467b48Spatrick     /// 'HASH' magic value to detect endianness.
12709467b48Spatrick     static const uint32_t MagicHash = 0x48415348;
12809467b48Spatrick 
Header__anonae21389f0311::AppleAccelTableWriter::Header12909467b48Spatrick     Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
13009467b48Spatrick         : BucketCount(BucketCount), HashCount(UniqueHashCount),
13109467b48Spatrick           HeaderDataLength(DataLength) {}
13209467b48Spatrick 
13309467b48Spatrick     void emit(AsmPrinter *Asm) const;
13409467b48Spatrick #ifndef NDEBUG
13509467b48Spatrick     void print(raw_ostream &OS) const;
dump__anonae21389f0311::AppleAccelTableWriter::Header13609467b48Spatrick     void dump() const { print(dbgs()); }
13709467b48Spatrick #endif
13809467b48Spatrick   };
13909467b48Spatrick 
14009467b48Spatrick   /// The HeaderData describes the structure of an Apple accelerator table
14109467b48Spatrick   /// through a list of Atoms.
14209467b48Spatrick   struct HeaderData {
14309467b48Spatrick     /// In the case of data that is referenced via DW_FORM_ref_* the offset
14409467b48Spatrick     /// base is used to describe the offset for all forms in the list of atoms.
14509467b48Spatrick     uint32_t DieOffsetBase;
14609467b48Spatrick 
14709467b48Spatrick     const SmallVector<Atom, 4> Atoms;
14809467b48Spatrick 
HeaderData__anonae21389f0311::AppleAccelTableWriter::HeaderData14909467b48Spatrick     HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
15009467b48Spatrick         : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
15109467b48Spatrick 
15209467b48Spatrick     void emit(AsmPrinter *Asm) const;
15309467b48Spatrick #ifndef NDEBUG
15409467b48Spatrick     void print(raw_ostream &OS) const;
dump__anonae21389f0311::AppleAccelTableWriter::HeaderData15509467b48Spatrick     void dump() const { print(dbgs()); }
15609467b48Spatrick #endif
15709467b48Spatrick   };
15809467b48Spatrick 
15909467b48Spatrick   Header Header;
16009467b48Spatrick   HeaderData HeaderData;
16109467b48Spatrick   const MCSymbol *SecBegin;
16209467b48Spatrick 
16309467b48Spatrick   void emitBuckets() const;
16409467b48Spatrick   void emitData() const;
16509467b48Spatrick 
16609467b48Spatrick public:
AppleAccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<Atom> Atoms,const MCSymbol * SecBegin)16709467b48Spatrick   AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
16809467b48Spatrick                         ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
16909467b48Spatrick       : AccelTableWriter(Asm, Contents, true),
17009467b48Spatrick         Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
17109467b48Spatrick                8 + (Atoms.size() * 4)),
17209467b48Spatrick         HeaderData(Atoms), SecBegin(SecBegin) {}
17309467b48Spatrick 
17409467b48Spatrick   void emit() const;
17509467b48Spatrick 
17609467b48Spatrick #ifndef NDEBUG
17709467b48Spatrick   void print(raw_ostream &OS) const;
dump() const17809467b48Spatrick   void dump() const { print(dbgs()); }
17909467b48Spatrick #endif
18009467b48Spatrick };
18109467b48Spatrick 
18209467b48Spatrick /// Class responsible for emitting a DWARF v5 Accelerator Table. The only
18309467b48Spatrick /// public function is emit(), which performs the actual emission.
18409467b48Spatrick ///
18509467b48Spatrick /// The class is templated in its data type. This allows us to emit both dyamic
18609467b48Spatrick /// and static data entries. A callback abstract the logic to provide a CU
18709467b48Spatrick /// index for a given entry, which is different per data type, but identical
18809467b48Spatrick /// for every entry in the same table.
18909467b48Spatrick template <typename DataT>
19009467b48Spatrick class Dwarf5AccelTableWriter : public AccelTableWriter {
19109467b48Spatrick   struct Header {
19209467b48Spatrick     uint16_t Version = 5;
19309467b48Spatrick     uint16_t Padding = 0;
19409467b48Spatrick     uint32_t CompUnitCount;
19509467b48Spatrick     uint32_t LocalTypeUnitCount = 0;
19609467b48Spatrick     uint32_t ForeignTypeUnitCount = 0;
19709467b48Spatrick     uint32_t BucketCount;
19809467b48Spatrick     uint32_t NameCount;
19909467b48Spatrick     uint32_t AbbrevTableSize = 0;
20009467b48Spatrick     uint32_t AugmentationStringSize = sizeof(AugmentationString);
20109467b48Spatrick     char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
20209467b48Spatrick 
Header__anonae21389f0311::Dwarf5AccelTableWriter::Header20309467b48Spatrick     Header(uint32_t CompUnitCount, uint32_t BucketCount, uint32_t NameCount)
20409467b48Spatrick         : CompUnitCount(CompUnitCount), BucketCount(BucketCount),
20509467b48Spatrick           NameCount(NameCount) {}
20609467b48Spatrick 
20773471bf0Spatrick     void emit(Dwarf5AccelTableWriter &Ctx);
20809467b48Spatrick   };
20909467b48Spatrick   struct AttributeEncoding {
21009467b48Spatrick     dwarf::Index Index;
21109467b48Spatrick     dwarf::Form Form;
21209467b48Spatrick   };
21309467b48Spatrick 
21409467b48Spatrick   Header Header;
21509467b48Spatrick   DenseMap<uint32_t, SmallVector<AttributeEncoding, 2>> Abbreviations;
21609467b48Spatrick   ArrayRef<MCSymbol *> CompUnits;
21709467b48Spatrick   llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry;
21873471bf0Spatrick   MCSymbol *ContributionEnd = nullptr;
21909467b48Spatrick   MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
22009467b48Spatrick   MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
22109467b48Spatrick   MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
22209467b48Spatrick 
22309467b48Spatrick   DenseSet<uint32_t> getUniqueTags() const;
22409467b48Spatrick 
22509467b48Spatrick   // Right now, we emit uniform attributes for all tags.
22609467b48Spatrick   SmallVector<AttributeEncoding, 2> getUniformAttributes() const;
22709467b48Spatrick 
22809467b48Spatrick   void emitCUList() const;
22909467b48Spatrick   void emitBuckets() const;
23009467b48Spatrick   void emitStringOffsets() const;
23109467b48Spatrick   void emitAbbrevs() const;
23209467b48Spatrick   void emitEntry(const DataT &Entry) const;
23309467b48Spatrick   void emitData() const;
23409467b48Spatrick 
23509467b48Spatrick public:
23609467b48Spatrick   Dwarf5AccelTableWriter(
23709467b48Spatrick       AsmPrinter *Asm, const AccelTableBase &Contents,
23809467b48Spatrick       ArrayRef<MCSymbol *> CompUnits,
23909467b48Spatrick       llvm::function_ref<unsigned(const DataT &)> GetCUIndexForEntry);
24009467b48Spatrick 
24173471bf0Spatrick   void emit();
24209467b48Spatrick };
24309467b48Spatrick } // namespace
24409467b48Spatrick 
emitHashes() const24509467b48Spatrick void AccelTableWriter::emitHashes() const {
24609467b48Spatrick   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
24709467b48Spatrick   unsigned BucketIdx = 0;
248*d415bd75Srobert   for (const auto &Bucket : Contents.getBuckets()) {
249*d415bd75Srobert     for (const auto &Hash : Bucket) {
25009467b48Spatrick       uint32_t HashValue = Hash->HashValue;
25109467b48Spatrick       if (SkipIdenticalHashes && PrevHash == HashValue)
25209467b48Spatrick         continue;
25309467b48Spatrick       Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
25409467b48Spatrick       Asm->emitInt32(HashValue);
25509467b48Spatrick       PrevHash = HashValue;
25609467b48Spatrick     }
25709467b48Spatrick     BucketIdx++;
25809467b48Spatrick   }
25909467b48Spatrick }
26009467b48Spatrick 
emitOffsets(const MCSymbol * Base) const26109467b48Spatrick void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
26209467b48Spatrick   const auto &Buckets = Contents.getBuckets();
26309467b48Spatrick   uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
26409467b48Spatrick   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
26509467b48Spatrick     for (auto *Hash : Buckets[i]) {
26609467b48Spatrick       uint32_t HashValue = Hash->HashValue;
26709467b48Spatrick       if (SkipIdenticalHashes && PrevHash == HashValue)
26809467b48Spatrick         continue;
26909467b48Spatrick       PrevHash = HashValue;
27009467b48Spatrick       Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
27173471bf0Spatrick       Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
27209467b48Spatrick     }
27309467b48Spatrick   }
27409467b48Spatrick }
27509467b48Spatrick 
emit(AsmPrinter * Asm) const27609467b48Spatrick void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
27709467b48Spatrick   Asm->OutStreamer->AddComment("Header Magic");
27809467b48Spatrick   Asm->emitInt32(Magic);
27909467b48Spatrick   Asm->OutStreamer->AddComment("Header Version");
28009467b48Spatrick   Asm->emitInt16(Version);
28109467b48Spatrick   Asm->OutStreamer->AddComment("Header Hash Function");
28209467b48Spatrick   Asm->emitInt16(HashFunction);
28309467b48Spatrick   Asm->OutStreamer->AddComment("Header Bucket Count");
28409467b48Spatrick   Asm->emitInt32(BucketCount);
28509467b48Spatrick   Asm->OutStreamer->AddComment("Header Hash Count");
28609467b48Spatrick   Asm->emitInt32(HashCount);
28709467b48Spatrick   Asm->OutStreamer->AddComment("Header Data Length");
28809467b48Spatrick   Asm->emitInt32(HeaderDataLength);
28909467b48Spatrick }
29009467b48Spatrick 
emit(AsmPrinter * Asm) const29109467b48Spatrick void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
29209467b48Spatrick   Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
29309467b48Spatrick   Asm->emitInt32(DieOffsetBase);
29409467b48Spatrick   Asm->OutStreamer->AddComment("HeaderData Atom Count");
29509467b48Spatrick   Asm->emitInt32(Atoms.size());
29609467b48Spatrick 
29709467b48Spatrick   for (const Atom &A : Atoms) {
29809467b48Spatrick     Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
29909467b48Spatrick     Asm->emitInt16(A.Type);
30009467b48Spatrick     Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
30109467b48Spatrick     Asm->emitInt16(A.Form);
30209467b48Spatrick   }
30309467b48Spatrick }
30409467b48Spatrick 
emitBuckets() const30509467b48Spatrick void AppleAccelTableWriter::emitBuckets() const {
30609467b48Spatrick   const auto &Buckets = Contents.getBuckets();
30709467b48Spatrick   unsigned index = 0;
30809467b48Spatrick   for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
30909467b48Spatrick     Asm->OutStreamer->AddComment("Bucket " + Twine(i));
31009467b48Spatrick     if (!Buckets[i].empty())
31109467b48Spatrick       Asm->emitInt32(index);
31209467b48Spatrick     else
31309467b48Spatrick       Asm->emitInt32(std::numeric_limits<uint32_t>::max());
31409467b48Spatrick     // Buckets point in the list of hashes, not to the data. Do not increment
31509467b48Spatrick     // the index multiple times in case of hash collisions.
31609467b48Spatrick     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
31709467b48Spatrick     for (auto *HD : Buckets[i]) {
31809467b48Spatrick       uint32_t HashValue = HD->HashValue;
31909467b48Spatrick       if (PrevHash != HashValue)
32009467b48Spatrick         ++index;
32109467b48Spatrick       PrevHash = HashValue;
32209467b48Spatrick     }
32309467b48Spatrick   }
32409467b48Spatrick }
32509467b48Spatrick 
emitData() const32609467b48Spatrick void AppleAccelTableWriter::emitData() const {
32709467b48Spatrick   const auto &Buckets = Contents.getBuckets();
32873471bf0Spatrick   for (const AccelTableBase::HashList &Bucket : Buckets) {
32909467b48Spatrick     uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
330*d415bd75Srobert     for (const auto &Hash : Bucket) {
33109467b48Spatrick       // Terminate the previous entry if there is no hash collision with the
33209467b48Spatrick       // current one.
33309467b48Spatrick       if (PrevHash != std::numeric_limits<uint64_t>::max() &&
33409467b48Spatrick           PrevHash != Hash->HashValue)
33509467b48Spatrick         Asm->emitInt32(0);
33609467b48Spatrick       // Remember to emit the label for our offset.
337097a140dSpatrick       Asm->OutStreamer->emitLabel(Hash->Sym);
33809467b48Spatrick       Asm->OutStreamer->AddComment(Hash->Name.getString());
33909467b48Spatrick       Asm->emitDwarfStringOffset(Hash->Name);
34009467b48Spatrick       Asm->OutStreamer->AddComment("Num DIEs");
34109467b48Spatrick       Asm->emitInt32(Hash->Values.size());
34209467b48Spatrick       for (const auto *V : Hash->Values)
34309467b48Spatrick         static_cast<const AppleAccelTableData *>(V)->emit(Asm);
34409467b48Spatrick       PrevHash = Hash->HashValue;
34509467b48Spatrick     }
34609467b48Spatrick     // Emit the final end marker for the bucket.
34773471bf0Spatrick     if (!Bucket.empty())
34809467b48Spatrick       Asm->emitInt32(0);
34909467b48Spatrick   }
35009467b48Spatrick }
35109467b48Spatrick 
emit() const35209467b48Spatrick void AppleAccelTableWriter::emit() const {
35309467b48Spatrick   Header.emit(Asm);
35409467b48Spatrick   HeaderData.emit(Asm);
35509467b48Spatrick   emitBuckets();
35609467b48Spatrick   emitHashes();
35709467b48Spatrick   emitOffsets(SecBegin);
35809467b48Spatrick   emitData();
35909467b48Spatrick }
36009467b48Spatrick 
36109467b48Spatrick template <typename DataT>
emit(Dwarf5AccelTableWriter & Ctx)36273471bf0Spatrick void Dwarf5AccelTableWriter<DataT>::Header::emit(Dwarf5AccelTableWriter &Ctx) {
36309467b48Spatrick   assert(CompUnitCount > 0 && "Index must have at least one CU.");
36409467b48Spatrick 
36509467b48Spatrick   AsmPrinter *Asm = Ctx.Asm;
36673471bf0Spatrick   Ctx.ContributionEnd =
36773471bf0Spatrick       Asm->emitDwarfUnitLength("names", "Header: unit length");
36809467b48Spatrick   Asm->OutStreamer->AddComment("Header: version");
36909467b48Spatrick   Asm->emitInt16(Version);
37009467b48Spatrick   Asm->OutStreamer->AddComment("Header: padding");
37109467b48Spatrick   Asm->emitInt16(Padding);
37209467b48Spatrick   Asm->OutStreamer->AddComment("Header: compilation unit count");
37309467b48Spatrick   Asm->emitInt32(CompUnitCount);
37409467b48Spatrick   Asm->OutStreamer->AddComment("Header: local type unit count");
37509467b48Spatrick   Asm->emitInt32(LocalTypeUnitCount);
37609467b48Spatrick   Asm->OutStreamer->AddComment("Header: foreign type unit count");
37709467b48Spatrick   Asm->emitInt32(ForeignTypeUnitCount);
37809467b48Spatrick   Asm->OutStreamer->AddComment("Header: bucket count");
37909467b48Spatrick   Asm->emitInt32(BucketCount);
38009467b48Spatrick   Asm->OutStreamer->AddComment("Header: name count");
38109467b48Spatrick   Asm->emitInt32(NameCount);
38209467b48Spatrick   Asm->OutStreamer->AddComment("Header: abbreviation table size");
383097a140dSpatrick   Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
38409467b48Spatrick   Asm->OutStreamer->AddComment("Header: augmentation string size");
38509467b48Spatrick   assert(AugmentationStringSize % 4 == 0);
38609467b48Spatrick   Asm->emitInt32(AugmentationStringSize);
38709467b48Spatrick   Asm->OutStreamer->AddComment("Header: augmentation string");
388097a140dSpatrick   Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
38909467b48Spatrick }
39009467b48Spatrick 
39109467b48Spatrick template <typename DataT>
getUniqueTags() const39209467b48Spatrick DenseSet<uint32_t> Dwarf5AccelTableWriter<DataT>::getUniqueTags() const {
39309467b48Spatrick   DenseSet<uint32_t> UniqueTags;
39409467b48Spatrick   for (auto &Bucket : Contents.getBuckets()) {
39509467b48Spatrick     for (auto *Hash : Bucket) {
39609467b48Spatrick       for (auto *Value : Hash->Values) {
39709467b48Spatrick         unsigned Tag = static_cast<const DataT *>(Value)->getDieTag();
39809467b48Spatrick         UniqueTags.insert(Tag);
39909467b48Spatrick       }
40009467b48Spatrick     }
40109467b48Spatrick   }
40209467b48Spatrick   return UniqueTags;
40309467b48Spatrick }
40409467b48Spatrick 
40509467b48Spatrick template <typename DataT>
40609467b48Spatrick SmallVector<typename Dwarf5AccelTableWriter<DataT>::AttributeEncoding, 2>
getUniformAttributes() const40709467b48Spatrick Dwarf5AccelTableWriter<DataT>::getUniformAttributes() const {
40809467b48Spatrick   SmallVector<AttributeEncoding, 2> UA;
40909467b48Spatrick   if (CompUnits.size() > 1) {
41009467b48Spatrick     size_t LargestCUIndex = CompUnits.size() - 1;
41109467b48Spatrick     dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, LargestCUIndex);
41209467b48Spatrick     UA.push_back({dwarf::DW_IDX_compile_unit, Form});
41309467b48Spatrick   }
41409467b48Spatrick   UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
41509467b48Spatrick   return UA;
41609467b48Spatrick }
41709467b48Spatrick 
41809467b48Spatrick template <typename DataT>
emitCUList() const41909467b48Spatrick void Dwarf5AccelTableWriter<DataT>::emitCUList() const {
42009467b48Spatrick   for (const auto &CU : enumerate(CompUnits)) {
42109467b48Spatrick     Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
42209467b48Spatrick     Asm->emitDwarfSymbolReference(CU.value());
42309467b48Spatrick   }
42409467b48Spatrick }
42509467b48Spatrick 
42609467b48Spatrick template <typename DataT>
emitBuckets() const42709467b48Spatrick void Dwarf5AccelTableWriter<DataT>::emitBuckets() const {
42809467b48Spatrick   uint32_t Index = 1;
42909467b48Spatrick   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
43009467b48Spatrick     Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
43109467b48Spatrick     Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
43209467b48Spatrick     Index += Bucket.value().size();
43309467b48Spatrick   }
43409467b48Spatrick }
43509467b48Spatrick 
43609467b48Spatrick template <typename DataT>
emitStringOffsets() const43709467b48Spatrick void Dwarf5AccelTableWriter<DataT>::emitStringOffsets() const {
43809467b48Spatrick   for (const auto &Bucket : enumerate(Contents.getBuckets())) {
43909467b48Spatrick     for (auto *Hash : Bucket.value()) {
44009467b48Spatrick       DwarfStringPoolEntryRef String = Hash->Name;
44109467b48Spatrick       Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
44209467b48Spatrick                                    ": " + String.getString());
44309467b48Spatrick       Asm->emitDwarfStringOffset(String);
44409467b48Spatrick     }
44509467b48Spatrick   }
44609467b48Spatrick }
44709467b48Spatrick 
44809467b48Spatrick template <typename DataT>
emitAbbrevs() const44909467b48Spatrick void Dwarf5AccelTableWriter<DataT>::emitAbbrevs() const {
450097a140dSpatrick   Asm->OutStreamer->emitLabel(AbbrevStart);
45109467b48Spatrick   for (const auto &Abbrev : Abbreviations) {
45209467b48Spatrick     Asm->OutStreamer->AddComment("Abbrev code");
45309467b48Spatrick     assert(Abbrev.first != 0);
454097a140dSpatrick     Asm->emitULEB128(Abbrev.first);
45509467b48Spatrick     Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev.first));
456097a140dSpatrick     Asm->emitULEB128(Abbrev.first);
45709467b48Spatrick     for (const auto &AttrEnc : Abbrev.second) {
458097a140dSpatrick       Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
459097a140dSpatrick       Asm->emitULEB128(AttrEnc.Form,
46009467b48Spatrick                        dwarf::FormEncodingString(AttrEnc.Form).data());
46109467b48Spatrick     }
462097a140dSpatrick     Asm->emitULEB128(0, "End of abbrev");
463097a140dSpatrick     Asm->emitULEB128(0, "End of abbrev");
46409467b48Spatrick   }
465097a140dSpatrick   Asm->emitULEB128(0, "End of abbrev list");
466097a140dSpatrick   Asm->OutStreamer->emitLabel(AbbrevEnd);
46709467b48Spatrick }
46809467b48Spatrick 
46909467b48Spatrick template <typename DataT>
emitEntry(const DataT & Entry) const47009467b48Spatrick void Dwarf5AccelTableWriter<DataT>::emitEntry(const DataT &Entry) const {
47109467b48Spatrick   auto AbbrevIt = Abbreviations.find(Entry.getDieTag());
47209467b48Spatrick   assert(AbbrevIt != Abbreviations.end() &&
47309467b48Spatrick          "Why wasn't this abbrev generated?");
47409467b48Spatrick 
475097a140dSpatrick   Asm->emitULEB128(AbbrevIt->first, "Abbreviation code");
47609467b48Spatrick   for (const auto &AttrEnc : AbbrevIt->second) {
47709467b48Spatrick     Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
47809467b48Spatrick     switch (AttrEnc.Index) {
47909467b48Spatrick     case dwarf::DW_IDX_compile_unit: {
48009467b48Spatrick       DIEInteger ID(getCUIndexForEntry(Entry));
481097a140dSpatrick       ID.emitValue(Asm, AttrEnc.Form);
48209467b48Spatrick       break;
48309467b48Spatrick     }
48409467b48Spatrick     case dwarf::DW_IDX_die_offset:
48509467b48Spatrick       assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
48609467b48Spatrick       Asm->emitInt32(Entry.getDieOffset());
48709467b48Spatrick       break;
48809467b48Spatrick     default:
48909467b48Spatrick       llvm_unreachable("Unexpected index attribute!");
49009467b48Spatrick     }
49109467b48Spatrick   }
49209467b48Spatrick }
49309467b48Spatrick 
emitData() const49409467b48Spatrick template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emitData() const {
495097a140dSpatrick   Asm->OutStreamer->emitLabel(EntryPool);
49609467b48Spatrick   for (auto &Bucket : Contents.getBuckets()) {
49709467b48Spatrick     for (auto *Hash : Bucket) {
49809467b48Spatrick       // Remember to emit the label for our offset.
499097a140dSpatrick       Asm->OutStreamer->emitLabel(Hash->Sym);
50009467b48Spatrick       for (const auto *Value : Hash->Values)
50109467b48Spatrick         emitEntry(*static_cast<const DataT *>(Value));
50209467b48Spatrick       Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
50373471bf0Spatrick       Asm->emitInt8(0);
50409467b48Spatrick     }
50509467b48Spatrick   }
50609467b48Spatrick }
50709467b48Spatrick 
50809467b48Spatrick template <typename DataT>
Dwarf5AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<MCSymbol * > CompUnits,llvm::function_ref<unsigned (const DataT &)> getCUIndexForEntry)50909467b48Spatrick Dwarf5AccelTableWriter<DataT>::Dwarf5AccelTableWriter(
51009467b48Spatrick     AsmPrinter *Asm, const AccelTableBase &Contents,
51109467b48Spatrick     ArrayRef<MCSymbol *> CompUnits,
51209467b48Spatrick     llvm::function_ref<unsigned(const DataT &)> getCUIndexForEntry)
51309467b48Spatrick     : AccelTableWriter(Asm, Contents, false),
51409467b48Spatrick       Header(CompUnits.size(), Contents.getBucketCount(),
51509467b48Spatrick              Contents.getUniqueNameCount()),
51609467b48Spatrick       CompUnits(CompUnits), getCUIndexForEntry(std::move(getCUIndexForEntry)) {
51709467b48Spatrick   DenseSet<uint32_t> UniqueTags = getUniqueTags();
51809467b48Spatrick   SmallVector<AttributeEncoding, 2> UniformAttributes = getUniformAttributes();
51909467b48Spatrick 
52009467b48Spatrick   Abbreviations.reserve(UniqueTags.size());
52109467b48Spatrick   for (uint32_t Tag : UniqueTags)
52209467b48Spatrick     Abbreviations.try_emplace(Tag, UniformAttributes);
52309467b48Spatrick }
52409467b48Spatrick 
emit()52573471bf0Spatrick template <typename DataT> void Dwarf5AccelTableWriter<DataT>::emit() {
52609467b48Spatrick   Header.emit(*this);
52709467b48Spatrick   emitCUList();
52809467b48Spatrick   emitBuckets();
52909467b48Spatrick   emitHashes();
53009467b48Spatrick   emitStringOffsets();
53109467b48Spatrick   emitOffsets(EntryPool);
53209467b48Spatrick   emitAbbrevs();
53309467b48Spatrick   emitData();
534*d415bd75Srobert   Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
535097a140dSpatrick   Asm->OutStreamer->emitLabel(ContributionEnd);
53609467b48Spatrick }
53709467b48Spatrick 
emitAppleAccelTableImpl(AsmPrinter * Asm,AccelTableBase & Contents,StringRef Prefix,const MCSymbol * SecBegin,ArrayRef<AppleAccelTableData::Atom> Atoms)53809467b48Spatrick void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
53909467b48Spatrick                                    StringRef Prefix, const MCSymbol *SecBegin,
54009467b48Spatrick                                    ArrayRef<AppleAccelTableData::Atom> Atoms) {
54109467b48Spatrick   Contents.finalize(Asm, Prefix);
54209467b48Spatrick   AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
54309467b48Spatrick }
54409467b48Spatrick 
emitDWARF5AccelTable(AsmPrinter * Asm,AccelTable<DWARF5AccelTableData> & Contents,const DwarfDebug & DD,ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs)54509467b48Spatrick void llvm::emitDWARF5AccelTable(
54609467b48Spatrick     AsmPrinter *Asm, AccelTable<DWARF5AccelTableData> &Contents,
54709467b48Spatrick     const DwarfDebug &DD, ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
54809467b48Spatrick   std::vector<MCSymbol *> CompUnits;
54909467b48Spatrick   SmallVector<unsigned, 1> CUIndex(CUs.size());
55009467b48Spatrick   int Count = 0;
55109467b48Spatrick   for (const auto &CU : enumerate(CUs)) {
55209467b48Spatrick     if (CU.value()->getCUNode()->getNameTableKind() !=
55309467b48Spatrick         DICompileUnit::DebugNameTableKind::Default)
55409467b48Spatrick       continue;
55509467b48Spatrick     CUIndex[CU.index()] = Count++;
55609467b48Spatrick     assert(CU.index() == CU.value()->getUniqueID());
55709467b48Spatrick     const DwarfCompileUnit *MainCU =
55809467b48Spatrick         DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
55909467b48Spatrick     CompUnits.push_back(MainCU->getLabelBegin());
56009467b48Spatrick   }
56109467b48Spatrick 
56209467b48Spatrick   if (CompUnits.empty())
56309467b48Spatrick     return;
56409467b48Spatrick 
565*d415bd75Srobert   Asm->OutStreamer->switchSection(
56609467b48Spatrick       Asm->getObjFileLowering().getDwarfDebugNamesSection());
56709467b48Spatrick 
56809467b48Spatrick   Contents.finalize(Asm, "names");
56909467b48Spatrick   Dwarf5AccelTableWriter<DWARF5AccelTableData>(
57009467b48Spatrick       Asm, Contents, CompUnits,
57109467b48Spatrick       [&](const DWARF5AccelTableData &Entry) {
57209467b48Spatrick         const DIE *CUDie = Entry.getDie().getUnitDie();
57309467b48Spatrick         return CUIndex[DD.lookupCU(CUDie)->getUniqueID()];
57409467b48Spatrick       })
57509467b48Spatrick       .emit();
57609467b48Spatrick }
57709467b48Spatrick 
emitDWARF5AccelTable(AsmPrinter * Asm,AccelTable<DWARF5AccelTableStaticData> & Contents,ArrayRef<MCSymbol * > CUs,llvm::function_ref<unsigned (const DWARF5AccelTableStaticData &)> getCUIndexForEntry)57809467b48Spatrick void llvm::emitDWARF5AccelTable(
57909467b48Spatrick     AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
58009467b48Spatrick     ArrayRef<MCSymbol *> CUs,
58109467b48Spatrick     llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
58209467b48Spatrick         getCUIndexForEntry) {
58309467b48Spatrick   Contents.finalize(Asm, "names");
58409467b48Spatrick   Dwarf5AccelTableWriter<DWARF5AccelTableStaticData>(Asm, Contents, CUs,
58509467b48Spatrick                                                      getCUIndexForEntry)
58609467b48Spatrick       .emit();
58709467b48Spatrick }
58809467b48Spatrick 
emit(AsmPrinter * Asm) const58909467b48Spatrick void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
59073471bf0Spatrick   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
59173471bf0Spatrick          "The section offset exceeds the limit.");
59209467b48Spatrick   Asm->emitInt32(Die.getDebugSectionOffset());
59309467b48Spatrick }
59409467b48Spatrick 
emit(AsmPrinter * Asm) const59509467b48Spatrick void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
59673471bf0Spatrick   assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
59773471bf0Spatrick          "The section offset exceeds the limit.");
59809467b48Spatrick   Asm->emitInt32(Die.getDebugSectionOffset());
59909467b48Spatrick   Asm->emitInt16(Die.getTag());
60009467b48Spatrick   Asm->emitInt8(0);
60109467b48Spatrick }
60209467b48Spatrick 
emit(AsmPrinter * Asm) const60309467b48Spatrick void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
60409467b48Spatrick   Asm->emitInt32(Offset);
60509467b48Spatrick }
60609467b48Spatrick 
emit(AsmPrinter * Asm) const60709467b48Spatrick void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
60809467b48Spatrick   Asm->emitInt32(Offset);
60909467b48Spatrick   Asm->emitInt16(Tag);
61009467b48Spatrick   Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
61109467b48Spatrick                                           : 0);
61209467b48Spatrick   Asm->emitInt32(QualifiedNameHash);
61309467b48Spatrick }
61409467b48Spatrick 
61509467b48Spatrick constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
61609467b48Spatrick constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
61709467b48Spatrick constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
61809467b48Spatrick constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
61909467b48Spatrick 
62009467b48Spatrick #ifndef NDEBUG
print(raw_ostream & OS) const62109467b48Spatrick void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
62209467b48Spatrick   OS << "Magic: " << format("0x%x", Magic) << "\n"
62309467b48Spatrick      << "Version: " << Version << "\n"
62409467b48Spatrick      << "Hash Function: " << HashFunction << "\n"
62509467b48Spatrick      << "Bucket Count: " << BucketCount << "\n"
62609467b48Spatrick      << "Header Data Length: " << HeaderDataLength << "\n";
62709467b48Spatrick }
62809467b48Spatrick 
print(raw_ostream & OS) const62909467b48Spatrick void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
63009467b48Spatrick   OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
63109467b48Spatrick      << "Form: " << dwarf::FormEncodingString(Form) << "\n";
63209467b48Spatrick }
63309467b48Spatrick 
print(raw_ostream & OS) const63409467b48Spatrick void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
63509467b48Spatrick   OS << "DIE Offset Base: " << DieOffsetBase << "\n";
63609467b48Spatrick   for (auto Atom : Atoms)
63709467b48Spatrick     Atom.print(OS);
63809467b48Spatrick }
63909467b48Spatrick 
print(raw_ostream & OS) const64009467b48Spatrick void AppleAccelTableWriter::print(raw_ostream &OS) const {
64109467b48Spatrick   Header.print(OS);
64209467b48Spatrick   HeaderData.print(OS);
64309467b48Spatrick   Contents.print(OS);
64409467b48Spatrick   SecBegin->print(OS, nullptr);
64509467b48Spatrick }
64609467b48Spatrick 
print(raw_ostream & OS) const64709467b48Spatrick void AccelTableBase::HashData::print(raw_ostream &OS) const {
64809467b48Spatrick   OS << "Name: " << Name.getString() << "\n";
64909467b48Spatrick   OS << "  Hash Value: " << format("0x%x", HashValue) << "\n";
65009467b48Spatrick   OS << "  Symbol: ";
65109467b48Spatrick   if (Sym)
65209467b48Spatrick     OS << *Sym;
65309467b48Spatrick   else
65409467b48Spatrick     OS << "<none>";
65509467b48Spatrick   OS << "\n";
65609467b48Spatrick   for (auto *Value : Values)
65709467b48Spatrick     Value->print(OS);
65809467b48Spatrick }
65909467b48Spatrick 
print(raw_ostream & OS) const66009467b48Spatrick void AccelTableBase::print(raw_ostream &OS) const {
66109467b48Spatrick   // Print Content.
66209467b48Spatrick   OS << "Entries: \n";
66309467b48Spatrick   for (const auto &Entry : Entries) {
66409467b48Spatrick     OS << "Name: " << Entry.first() << "\n";
66509467b48Spatrick     for (auto *V : Entry.second.Values)
66609467b48Spatrick       V->print(OS);
66709467b48Spatrick   }
66809467b48Spatrick 
66909467b48Spatrick   OS << "Buckets and Hashes: \n";
670*d415bd75Srobert   for (const auto &Bucket : Buckets)
671*d415bd75Srobert     for (const auto &Hash : Bucket)
67209467b48Spatrick       Hash->print(OS);
67309467b48Spatrick 
67409467b48Spatrick   OS << "Data: \n";
675*d415bd75Srobert   for (const auto &E : Entries)
67609467b48Spatrick     E.second.print(OS);
67709467b48Spatrick }
67809467b48Spatrick 
print(raw_ostream & OS) const67909467b48Spatrick void DWARF5AccelTableData::print(raw_ostream &OS) const {
68009467b48Spatrick   OS << "  Offset: " << getDieOffset() << "\n";
68109467b48Spatrick   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
68209467b48Spatrick }
68309467b48Spatrick 
print(raw_ostream & OS) const68409467b48Spatrick void DWARF5AccelTableStaticData::print(raw_ostream &OS) const {
68509467b48Spatrick   OS << "  Offset: " << getDieOffset() << "\n";
68609467b48Spatrick   OS << "  Tag: " << dwarf::TagString(getDieTag()) << "\n";
68709467b48Spatrick }
68809467b48Spatrick 
print(raw_ostream & OS) const68909467b48Spatrick void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
69009467b48Spatrick   OS << "  Offset: " << Die.getOffset() << "\n";
69109467b48Spatrick }
69209467b48Spatrick 
print(raw_ostream & OS) const69309467b48Spatrick void AppleAccelTableTypeData::print(raw_ostream &OS) const {
69409467b48Spatrick   OS << "  Offset: " << Die.getOffset() << "\n";
69509467b48Spatrick   OS << "  Tag: " << dwarf::TagString(Die.getTag()) << "\n";
69609467b48Spatrick }
69709467b48Spatrick 
print(raw_ostream & OS) const69809467b48Spatrick void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
69909467b48Spatrick   OS << "  Static Offset: " << Offset << "\n";
70009467b48Spatrick }
70109467b48Spatrick 
print(raw_ostream & OS) const70209467b48Spatrick void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
70309467b48Spatrick   OS << "  Static Offset: " << Offset << "\n";
70409467b48Spatrick   OS << "  QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
70509467b48Spatrick   OS << "  Tag: " << dwarf::TagString(Tag) << "\n";
70609467b48Spatrick   OS << "  ObjCClassIsImplementation: "
70709467b48Spatrick      << (ObjCClassIsImplementation ? "true" : "false");
70809467b48Spatrick   OS << "\n";
70909467b48Spatrick }
71009467b48Spatrick #endif
711