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