diff options
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/DwarfAccelTable.h')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DwarfAccelTable.h | 339 |
1 files changed, 231 insertions, 108 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfAccelTable.h b/llvm/lib/CodeGen/AsmPrinter/DwarfAccelTable.h index 36373076096..43fcef94b74 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfAccelTable.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfAccelTable.h @@ -66,121 +66,135 @@ namespace llvm { class AsmPrinter; -class DwarfDebug; - -class DwarfAccelTable { - // Helper function to compute the number of buckets needed based on - // the number of unique hashes. - void ComputeBucketCount(); - - struct TableHeader { - uint32_t magic = MagicHash; // 'HASH' magic value to allow endian detection - uint16_t version = 1; // Version number. - uint16_t hash_function = dwarf::DW_hash_function_djb; - // The hash function enumeration that was used. - uint32_t bucket_count = 0; // The number of buckets in this hash table. - uint32_t hashes_count = 0; // The total number of unique hash values - // and hash data offsets in this table. - uint32_t header_data_len; // The bytes to skip to get to the hash - // indexes (buckets) for correct alignment. - // Also written to disk is the implementation specific header data. +/// Representation of the header of an Apple accelerator table. This consists +/// of the fixed header and the header data. The latter contains the atoms +/// which define the columns of the table. +class AppleAccelTableHeader { + struct Header { + uint32_t Magic = MagicHash; + uint16_t Version = 1; + uint16_t HashFunction = dwarf::DW_hash_function_djb; + uint32_t BucketCount = 0; + uint32_t HashCount = 0; + uint32_t HeaderDataLength; + + /// 'HASH' magic value to detect endianness. static const uint32_t MagicHash = 0x48415348; - TableHeader(uint32_t data_len) : header_data_len(data_len) {} + Header(uint32_t DataLength) : HeaderDataLength(DataLength) {} #ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "Magic: " << format("0x%x", magic) << "\n" - << "Version: " << version << "\n" - << "Hash Function: " << hash_function << "\n" - << "Bucket Count: " << bucket_count << "\n" - << "Header Data Length: " << header_data_len << "\n"; + void print(raw_ostream &OS) const { + OS << "Magic: " << format("0x%x", Magic) << "\n" + << "Version: " << Version << "\n" + << "Hash Function: " << HashFunction << "\n" + << "Bucket Count: " << BucketCount << "\n" + << "Header Data Length: " << HeaderDataLength << "\n"; } - void dump() { print(dbgs()); } + void dump() const { print(dbgs()); } #endif }; public: - // The HeaderData describes the form of each set of data. In general this - // is as a list of atoms (atom_count) where each atom contains a type - // (AtomType type) of data, and an encoding form (form). In the case of - // data that is referenced via DW_FORM_ref_* the die_offset_base is - // used to describe the offset for all forms in the list of atoms. - // This also serves as a public interface of sorts. - // When written to disk this will have the form: - // - // uint32_t die_offset_base - // uint32_t atom_count - // atom_count Atoms - - // Make these public so that they can be used as a general interface to - // the class. + /// An Atom defines the form of the data in the accelerator table. + /// Conceptually it is a column in the accelerator consisting of a type and a + /// specification of the form of its data. struct Atom { - uint16_t type; // enum AtomType - uint16_t form; // DWARF DW_FORM_ defines + /// Atom Type. + const uint16_t Type; + /// DWARF Form. + const uint16_t Form; - constexpr Atom(uint16_t type, uint16_t form) : type(type), form(form) {} + constexpr Atom(uint16_t Type, uint16_t Form) : Type(Type), Form(Form) {} #ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "Type: " << dwarf::AtomTypeString(type) << "\n" - << "Form: " << dwarf::FormEncodingString(form) << "\n"; + void print(raw_ostream &OS) const { + OS << "Type: " << dwarf::AtomTypeString(Type) << "\n" + << "Form: " << dwarf::FormEncodingString(Form) << "\n"; } - void dump() { print(dbgs()); } + void dump() const { print(dbgs()); } #endif }; private: - struct TableHeaderData { - uint32_t die_offset_base; + /// The HeaderData describes the structure of the accelerator table through a + /// list of Atoms. + struct HeaderData { + /// In the case of data that is referenced via DW_FORM_ref_* the offset + /// base is used to describe the offset for all forms in the list of atoms. + uint32_t DieOffsetBase; + SmallVector<Atom, 3> Atoms; - TableHeaderData(ArrayRef<Atom> AtomList, uint32_t offset = 0) - : die_offset_base(offset), Atoms(AtomList.begin(), AtomList.end()) {} + HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0) + : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {} #ifndef NDEBUG - void print(raw_ostream &OS) { - OS << "die_offset_base: " << die_offset_base << "\n"; - for (size_t i = 0; i < Atoms.size(); i++) - Atoms[i].print(OS); + void print(raw_ostream &OS) const { + OS << "DIE Offset Base: " << DieOffsetBase << "\n"; + for (auto Atom : Atoms) + Atom.print(OS); } - void dump() { print(dbgs()); } + void dump() const { print(dbgs()); } #endif }; - // The data itself consists of a str_offset, a count of the DIEs in the - // hash and the offsets to the DIEs themselves. - // On disk each data section is ended with a 0 KeyType as the end of the - // hash chain. - // On output this looks like: - // uint32_t str_offset - // uint32_t hash_data_count - // HashData[hash_data_count] + Header Header; + HeaderData HeaderData; + public: - struct HashDataContents { - const DIE *Die; // Offsets - char Flags; // Specific flags to output + /// The length of the header data is always going to be 4 + 4 + 4*NumAtoms. + AppleAccelTableHeader(ArrayRef<AppleAccelTableHeader::Atom> Atoms) + : Header(8 + (Atoms.size() * 4)), HeaderData(Atoms) {} + + /// Update header with hash and bucket count. + void setBucketAndHashCount(uint32_t HashCount); - HashDataContents(const DIE *D, char Flags) : Die(D), Flags(Flags) {} + uint32_t getHashCount() const { return Header.HashCount; } + uint32_t getBucketCount() const { return Header.BucketCount; } + + /// Emits the header via the AsmPrinter. + void emit(AsmPrinter *); #ifndef NDEBUG - void print(raw_ostream &OS) const { - OS << " Offset: " << Die->getOffset() << "\n" - << " Tag: " << dwarf::TagString(Die->getTag()) << "\n" - << " Flags: " << Flags << "\n"; - } + void print(raw_ostream &OS) const { + Header.print(OS); + HeaderData.print(OS); + } + + void dump() const { print(dbgs()); } #endif - }; +}; -private: - // String Data +/// Interface which the different types of accelerator table data have to +/// conform. +class AppleAccelTableData { +public: + virtual ~AppleAccelTableData() = default; + + virtual void emit(AsmPrinter *Asm) const = 0; + + bool operator<(const AppleAccelTableData &Other) const { + return order() < Other.order(); + } + +#ifndef NDEBUG + virtual void print(raw_ostream &OS) const = 0; +#endif +protected: + virtual uint64_t order() const; +}; + +/// Apple-style accelerator table base class. +class AppleAccelTableBase { +protected: struct DataArray { DwarfStringPoolEntryRef Name; - std::vector<HashDataContents *> Values; + std::vector<AppleAccelTableData *> Values; }; friend struct HashData; @@ -189,10 +203,9 @@ private: StringRef Str; uint32_t HashValue; MCSymbol *Sym; - DwarfAccelTable::DataArray &Data; // offsets + DataArray &Data; - HashData(StringRef S, DwarfAccelTable::DataArray &Data) - : Str(S), Data(Data) { + HashData(StringRef S, DataArray &Data) : Str(S), Data(Data) { HashValue = djbHash(S); } @@ -206,54 +219,164 @@ private: else OS << "<none>"; OS << "\n"; - for (HashDataContents *C : Data.Values) { - OS << " Offset: " << C->Die->getOffset() << "\n"; - OS << " Tag: " << dwarf::TagString(C->Die->getTag()) << "\n"; - OS << " Flags: " << C->Flags << "\n"; - } + for (auto *Value : Data.Values) + Value->print(OS); } void dump() { print(dbgs()); } #endif }; - // Internal Functions - void EmitHeader(AsmPrinter *); - void EmitBuckets(AsmPrinter *); - void EmitHashes(AsmPrinter *); - void emitOffsets(AsmPrinter *, const MCSymbol *); - void EmitData(AsmPrinter *, DwarfDebug *D); - - // Allocator for HashData and HashDataContents. + /// Allocator for HashData and Values. BumpPtrAllocator Allocator; - // Output Variables - TableHeader Header; - TableHeaderData HeaderData; + /// Header containing both the header and header data. + AppleAccelTableHeader Header; + std::vector<HashData *> Data; using StringEntries = StringMap<DataArray, BumpPtrAllocator &>; - StringEntries Entries; - // Buckets/Hashes/Offsets using HashList = std::vector<HashData *>; + HashList Hashes; + using BucketList = std::vector<HashList>; BucketList Buckets; - HashList Hashes; - // Public Implementation + AppleAccelTableBase(ArrayRef<AppleAccelTableHeader::Atom> Atoms) + : Header(Atoms), Entries(Allocator) {} + +private: + /// Emits the header for the table via the AsmPrinter. + void emitHeader(AsmPrinter *Asm); + + /// Helper function to compute the number of buckets needed based on the + /// number of unique hashes. + void computeBucketCount(); + + /// Walk through and emit the buckets for the table. Each index is an offset + /// into the list of hashes. + void emitBuckets(AsmPrinter *); + + /// Walk through the buckets and emit the individual hashes for each bucket. + void emitHashes(AsmPrinter *); + + /// Walk through the buckets and emit the individual offsets for each element + /// in each bucket. This is done via a symbol subtraction from the beginning + /// of the section. The non-section symbol will be output later when we emit + /// the actual data. + void emitOffsets(AsmPrinter *, const MCSymbol *); + + /// Walk through the buckets and emit the full data for each element in the + /// bucket. For the string case emit the dies and the various offsets. + /// Terminate each HashData bucket with 0. + void emitData(AsmPrinter *); + +public: + void finalizeTable(AsmPrinter *, StringRef); + + void emit(AsmPrinter *Asm, const MCSymbol *SecBegin) { + emitHeader(Asm); + emitBuckets(Asm); + emitHashes(Asm); + emitOffsets(Asm, SecBegin); + emitData(Asm); + } + +#ifndef NDEBUG + void print(raw_ostream &OS) const { + // Print Header. + Header.print(OS); + + // Print Content. + OS << "Entries: \n"; + for (const auto &Entry : Entries) { + OS << "Name: " << Entry.first() << "\n"; + for (auto *V : Entry.second.Values) + V->print(OS); + } + + OS << "Buckets and Hashes: \n"; + for (auto &Bucket : Buckets) + for (auto &Hash : Bucket) + Hash->print(OS); + + OS << "Data: \n"; + for (auto &D : Data) + D->print(OS); + } + void dump() const { print(dbgs()); } +#endif +}; + +template <typename AppleAccelTableDataT> +class AppleAccelTable : public AppleAccelTableBase { +public: + AppleAccelTable() : AppleAccelTableBase(AppleAccelTableDataT::Atoms) {} + AppleAccelTable(const AppleAccelTable &) = delete; + AppleAccelTable &operator=(const AppleAccelTable &) = delete; + + template <class... Types> + void addName(DwarfStringPoolEntryRef Name, Types... Args); +}; + +template <typename AppleAccelTableDataT> +template <class... Types> +void AppleAccelTable<AppleAccelTableDataT>::addName( + DwarfStringPoolEntryRef Name, Types... Args) { + assert(Data.empty() && "Already finalized!"); + // If the string is in the list already then add this die to the list + // otherwise add a new one. + DataArray &DA = Entries[Name.getString()]; + assert(!DA.Name || DA.Name == Name); + DA.Name = Name; + DA.Values.push_back(new (Allocator) AppleAccelTableDataT(Args...)); +} + +/// Accelerator table data implementation for simple accelerator tables with +/// just a DIE reference. +class AppleAccelTableOffsetData : public AppleAccelTableData { public: - DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom>); - DwarfAccelTable(const DwarfAccelTable &) = delete; - DwarfAccelTable &operator=(const DwarfAccelTable &) = delete; + AppleAccelTableOffsetData(const DIE *D) : Die(D) {} + + void emit(AsmPrinter *Asm) const override; + + static constexpr AppleAccelTableHeader::Atom Atoms[] = { + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset, + dwarf::DW_FORM_data4)}; + +#ifndef NDEBUG + void print(raw_ostream &OS) const override { + OS << " Offset: " << Die->getOffset() << "\n"; + } + +#endif +protected: + uint64_t order() const override { return Die->getOffset(); } + + const DIE *Die; +}; + +/// Accelerator table data implementation for type accelerator tables. +class AppleAccelTableTypeData : public AppleAccelTableOffsetData { +public: + AppleAccelTableTypeData(const DIE *D) : AppleAccelTableOffsetData(D) {} + + void emit(AsmPrinter *Asm) const override; + + static constexpr AppleAccelTableHeader::Atom Atoms[] = { + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_offset, + dwarf::DW_FORM_data4), + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2), + AppleAccelTableHeader::Atom(dwarf::DW_ATOM_type_flags, + dwarf::DW_FORM_data1)}; - void AddName(DwarfStringPoolEntryRef Name, const DIE *Die, char Flags = 0); - void FinalizeTable(AsmPrinter *, StringRef); - void emit(AsmPrinter *, const MCSymbol *, DwarfDebug *); #ifndef NDEBUG - void print(raw_ostream &OS); - void dump() { print(dbgs()); } + void print(raw_ostream &OS) const override { + OS << " Offset: " << Die->getOffset() << "\n"; + OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n"; + } #endif }; |