10b57cec5SDimitry Andric //==- include/llvm/CodeGen/AccelTable.h - Accelerator Tables -----*- C++ -*-==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric /// \file
9fe6060f1SDimitry Andric /// This file contains support for writing accelerator tables.
10fe6060f1SDimitry Andric ///
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
13fe6060f1SDimitry Andric #ifndef LLVM_CODEGEN_ACCELTABLE_H
14fe6060f1SDimitry Andric #define LLVM_CODEGEN_ACCELTABLE_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1706c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h"
1881ad6265SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
200b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/DIE.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/DwarfStringPoolEntry.h"
230b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
240b57cec5SDimitry Andric #include "llvm/Support/DJB.h"
250b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
260b57cec5SDimitry Andric #include <cstdint>
275f757f3fSDimitry Andric #include <variant>
280b57cec5SDimitry Andric #include <vector>
290b57cec5SDimitry Andric 
30fe6060f1SDimitry Andric /// \file
310b57cec5SDimitry Andric /// The DWARF and Apple accelerator tables are an indirect hash table optimized
320b57cec5SDimitry Andric /// for null lookup rather than access to known data. The Apple accelerator
330b57cec5SDimitry Andric /// tables are a precursor of the newer DWARF v5 accelerator tables. Both
340b57cec5SDimitry Andric /// formats share common design ideas.
350b57cec5SDimitry Andric ///
360b57cec5SDimitry Andric /// The Apple accelerator table are output into an on-disk format that looks
370b57cec5SDimitry Andric /// like this:
380b57cec5SDimitry Andric ///
390b57cec5SDimitry Andric /// .------------------.
400b57cec5SDimitry Andric /// |  HEADER          |
410b57cec5SDimitry Andric /// |------------------|
420b57cec5SDimitry Andric /// |  BUCKETS         |
430b57cec5SDimitry Andric /// |------------------|
440b57cec5SDimitry Andric /// |  HASHES          |
450b57cec5SDimitry Andric /// |------------------|
460b57cec5SDimitry Andric /// |  OFFSETS         |
470b57cec5SDimitry Andric /// |------------------|
480b57cec5SDimitry Andric /// |  DATA            |
490b57cec5SDimitry Andric /// `------------------'
500b57cec5SDimitry Andric ///
510b57cec5SDimitry Andric /// The header contains a magic number, version, type of hash function,
520b57cec5SDimitry Andric /// the number of buckets, total number of hashes, and room for a special struct
530b57cec5SDimitry Andric /// of data and the length of that struct.
540b57cec5SDimitry Andric ///
550b57cec5SDimitry Andric /// The buckets contain an index (e.g. 6) into the hashes array. The hashes
560b57cec5SDimitry Andric /// section contains all of the 32-bit hash values in contiguous memory, and the
570b57cec5SDimitry Andric /// offsets contain the offset into the data area for the particular hash.
580b57cec5SDimitry Andric ///
590b57cec5SDimitry Andric /// For a lookup example, we could hash a function name and take it modulo the
600b57cec5SDimitry Andric /// number of buckets giving us our bucket. From there we take the bucket value
610b57cec5SDimitry Andric /// as an index into the hashes table and look at each successive hash as long
620b57cec5SDimitry Andric /// as the hash value is still the same modulo result (bucket value) as earlier.
630b57cec5SDimitry Andric /// If we have a match we look at that same entry in the offsets table and grab
640b57cec5SDimitry Andric /// the offset in the data for our final match.
650b57cec5SDimitry Andric ///
660b57cec5SDimitry Andric /// The DWARF v5 accelerator table consists of zero or more name indices that
670b57cec5SDimitry Andric /// are output into an on-disk format that looks like this:
680b57cec5SDimitry Andric ///
690b57cec5SDimitry Andric /// .------------------.
700b57cec5SDimitry Andric /// |  HEADER          |
710b57cec5SDimitry Andric /// |------------------|
720b57cec5SDimitry Andric /// |  CU LIST         |
730b57cec5SDimitry Andric /// |------------------|
740b57cec5SDimitry Andric /// |  LOCAL TU LIST   |
750b57cec5SDimitry Andric /// |------------------|
760b57cec5SDimitry Andric /// |  FOREIGN TU LIST |
770b57cec5SDimitry Andric /// |------------------|
780b57cec5SDimitry Andric /// |  HASH TABLE      |
790b57cec5SDimitry Andric /// |------------------|
800b57cec5SDimitry Andric /// |  NAME TABLE      |
810b57cec5SDimitry Andric /// |------------------|
820b57cec5SDimitry Andric /// |  ABBREV TABLE    |
830b57cec5SDimitry Andric /// |------------------|
840b57cec5SDimitry Andric /// |  ENTRY POOL      |
850b57cec5SDimitry Andric /// `------------------'
860b57cec5SDimitry Andric ///
870b57cec5SDimitry Andric /// For the full documentation please refer to the DWARF 5 standard.
880b57cec5SDimitry Andric ///
890b57cec5SDimitry Andric ///
900b57cec5SDimitry Andric /// This file defines the class template AccelTable, which is represents an
910b57cec5SDimitry Andric /// abstract view of an Accelerator table, without any notion of an on-disk
920b57cec5SDimitry Andric /// layout. This class is parameterized by an entry type, which should derive
930b57cec5SDimitry Andric /// from AccelTableData. This is the type of individual entries in the table,
940b57cec5SDimitry Andric /// and it should store the data necessary to emit them. AppleAccelTableData is
950b57cec5SDimitry Andric /// the base class for Apple Accelerator Table entries, which have a uniform
960b57cec5SDimitry Andric /// structure based on a sequence of Atoms. There are different sub-classes
970b57cec5SDimitry Andric /// derived from AppleAccelTable, which differ in the set of Atoms and how they
980b57cec5SDimitry Andric /// obtain their values.
990b57cec5SDimitry Andric ///
1000b57cec5SDimitry Andric /// An Apple Accelerator Table can be serialized by calling emitAppleAccelTable
1010b57cec5SDimitry Andric /// function.
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric namespace llvm {
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric class AsmPrinter;
1060b57cec5SDimitry Andric class DwarfDebug;
1075f757f3fSDimitry Andric class DwarfTypeUnit;
10881ad6265SDimitry Andric class MCSymbol;
10981ad6265SDimitry Andric class raw_ostream;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric /// Interface which the different types of accelerator table data have to
1120b57cec5SDimitry Andric /// conform. It serves as a base class for different values of the template
1130b57cec5SDimitry Andric /// argument of the AccelTable class template.
1140b57cec5SDimitry Andric class AccelTableData {
1150b57cec5SDimitry Andric public:
1160b57cec5SDimitry Andric   virtual ~AccelTableData() = default;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   bool operator<(const AccelTableData &Other) const {
1190b57cec5SDimitry Andric     return order() < Other.order();
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     // Subclasses should implement:
1230b57cec5SDimitry Andric     // static uint32_t hash(StringRef Name);
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric #ifndef NDEBUG
1260b57cec5SDimitry Andric   virtual void print(raw_ostream &OS) const = 0;
1270b57cec5SDimitry Andric #endif
1280b57cec5SDimitry Andric protected:
1290b57cec5SDimitry Andric   virtual uint64_t order() const = 0;
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric /// A base class holding non-template-dependant functionality of the AccelTable
1330b57cec5SDimitry Andric /// class. Clients should not use this class directly but rather instantiate
1340b57cec5SDimitry Andric /// AccelTable with a type derived from AccelTableData.
1350b57cec5SDimitry Andric class AccelTableBase {
1360b57cec5SDimitry Andric public:
1370b57cec5SDimitry Andric   using HashFn = uint32_t(StringRef);
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   /// Represents a group of entries with identical name (and hence, hash value).
1400b57cec5SDimitry Andric   struct HashData {
1410b57cec5SDimitry Andric     DwarfStringPoolEntryRef Name;
1420b57cec5SDimitry Andric     uint32_t HashValue;
1430b57cec5SDimitry Andric     std::vector<AccelTableData *> Values;
1440b57cec5SDimitry Andric     MCSymbol *Sym;
1450b57cec5SDimitry Andric 
1461db9f3b2SDimitry Andric     /// Get all AccelTableData cast as a `T`.
getValuesHashData1471db9f3b2SDimitry Andric     template <typename T = AccelTableData *> auto getValues() const {
1481db9f3b2SDimitry Andric       static_assert(std::is_pointer<T>());
1491db9f3b2SDimitry Andric       static_assert(
1501db9f3b2SDimitry Andric           std::is_base_of<AccelTableData, std::remove_pointer_t<T>>());
1511db9f3b2SDimitry Andric       return map_range(
1521db9f3b2SDimitry Andric           Values, [](AccelTableData *Data) { return static_cast<T>(Data); });
1531db9f3b2SDimitry Andric     }
1541db9f3b2SDimitry Andric 
1550b57cec5SDimitry Andric #ifndef NDEBUG
1560b57cec5SDimitry Andric     void print(raw_ostream &OS) const;
dumpHashData1570b57cec5SDimitry Andric     void dump() const { print(dbgs()); }
1580b57cec5SDimitry Andric #endif
1590b57cec5SDimitry Andric   };
1600b57cec5SDimitry Andric   using HashList = std::vector<HashData *>;
1610b57cec5SDimitry Andric   using BucketList = std::vector<HashList>;
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric protected:
1640b57cec5SDimitry Andric   /// Allocator for HashData and Values.
1650b57cec5SDimitry Andric   BumpPtrAllocator Allocator;
1660b57cec5SDimitry Andric 
16706c3fb27SDimitry Andric   using StringEntries = MapVector<StringRef, HashData>;
1680b57cec5SDimitry Andric   StringEntries Entries;
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   HashFn *Hash;
17106c3fb27SDimitry Andric   uint32_t BucketCount = 0;
17206c3fb27SDimitry Andric   uint32_t UniqueHashCount = 0;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   HashList Hashes;
1750b57cec5SDimitry Andric   BucketList Buckets;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   void computeBucketCount();
1780b57cec5SDimitry Andric 
AccelTableBase(HashFn * Hash)17906c3fb27SDimitry Andric   AccelTableBase(HashFn *Hash) : Hash(Hash) {}
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric public:
1820b57cec5SDimitry Andric   void finalize(AsmPrinter *Asm, StringRef Prefix);
getBuckets()1830b57cec5SDimitry Andric   ArrayRef<HashList> getBuckets() const { return Buckets; }
getBucketCount()1840b57cec5SDimitry Andric   uint32_t getBucketCount() const { return BucketCount; }
getUniqueHashCount()1850b57cec5SDimitry Andric   uint32_t getUniqueHashCount() const { return UniqueHashCount; }
getUniqueNameCount()1860b57cec5SDimitry Andric   uint32_t getUniqueNameCount() const { return Entries.size(); }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric #ifndef NDEBUG
1890b57cec5SDimitry Andric   void print(raw_ostream &OS) const;
dump()1900b57cec5SDimitry Andric   void dump() const { print(dbgs()); }
1910b57cec5SDimitry Andric #endif
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   AccelTableBase(const AccelTableBase &) = delete;
1940b57cec5SDimitry Andric   void operator=(const AccelTableBase &) = delete;
1950b57cec5SDimitry Andric };
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric /// This class holds an abstract representation of an Accelerator Table,
1980b57cec5SDimitry Andric /// consisting of a sequence of buckets, each bucket containint a sequence of
1990b57cec5SDimitry Andric /// HashData entries. The class is parameterized by the type of entries it
2000b57cec5SDimitry Andric /// holds. The type template parameter also defines the hash function to use for
2010b57cec5SDimitry Andric /// hashing names.
2020b57cec5SDimitry Andric template <typename DataT> class AccelTable : public AccelTableBase {
2030b57cec5SDimitry Andric public:
AccelTable()2040b57cec5SDimitry Andric   AccelTable() : AccelTableBase(DataT::hash) {}
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   template <typename... Types>
2070b57cec5SDimitry Andric   void addName(DwarfStringPoolEntryRef Name, Types &&... Args);
clear()2085f757f3fSDimitry Andric   void clear() { Entries.clear(); }
2095f757f3fSDimitry Andric   void addEntries(AccelTable<DataT> &Table);
getEntries()2105f757f3fSDimitry Andric   const StringEntries getEntries() const { return Entries; }
2110b57cec5SDimitry Andric };
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric template <typename AccelTableDataT>
2140b57cec5SDimitry Andric template <typename... Types>
addName(DwarfStringPoolEntryRef Name,Types &&...Args)2150b57cec5SDimitry Andric void AccelTable<AccelTableDataT>::addName(DwarfStringPoolEntryRef Name,
2160b57cec5SDimitry Andric                                           Types &&... Args) {
2170b57cec5SDimitry Andric   assert(Buckets.empty() && "Already finalized!");
2180b57cec5SDimitry Andric   // If the string is in the list already then add this die to the list
2190b57cec5SDimitry Andric   // otherwise add a new one.
22006c3fb27SDimitry Andric   auto &It = Entries[Name.getString()];
22106c3fb27SDimitry Andric   if (It.Values.empty()) {
22206c3fb27SDimitry Andric     It.Name = Name;
22306c3fb27SDimitry Andric     It.HashValue = Hash(Name.getString());
22406c3fb27SDimitry Andric   }
22506c3fb27SDimitry Andric   It.Values.push_back(new (Allocator)
22606c3fb27SDimitry Andric                           AccelTableDataT(std::forward<Types>(Args)...));
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric /// A base class for different implementations of Data classes for Apple
2300b57cec5SDimitry Andric /// Accelerator Tables. The columns in the table are defined by the static Atoms
2310b57cec5SDimitry Andric /// variable defined on the subclasses.
2320b57cec5SDimitry Andric class AppleAccelTableData : public AccelTableData {
2330b57cec5SDimitry Andric public:
2340b57cec5SDimitry Andric   /// An Atom defines the form of the data in an Apple accelerator table.
2350b57cec5SDimitry Andric   /// Conceptually it is a column in the accelerator consisting of a type and a
2360b57cec5SDimitry Andric   /// specification of the form of its data.
2370b57cec5SDimitry Andric   struct Atom {
2380b57cec5SDimitry Andric     /// Atom Type.
2390b57cec5SDimitry Andric     const uint16_t Type;
2400b57cec5SDimitry Andric     /// DWARF Form.
2410b57cec5SDimitry Andric     const uint16_t Form;
2420b57cec5SDimitry Andric 
AtomAtom2430b57cec5SDimitry Andric     constexpr Atom(uint16_t Type, uint16_t Form) : Type(Type), Form(Form) {}
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric #ifndef NDEBUG
2460b57cec5SDimitry Andric     void print(raw_ostream &OS) const;
dumpAtom2470b57cec5SDimitry Andric     void dump() const { print(dbgs()); }
2480b57cec5SDimitry Andric #endif
2490b57cec5SDimitry Andric   };
2500b57cec5SDimitry Andric   // Subclasses should define:
2510b57cec5SDimitry Andric   // static constexpr Atom Atoms[];
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   virtual void emit(AsmPrinter *Asm) const = 0;
2540b57cec5SDimitry Andric 
hash(StringRef Buffer)2550b57cec5SDimitry Andric   static uint32_t hash(StringRef Buffer) { return djbHash(Buffer); }
2560b57cec5SDimitry Andric };
2570b57cec5SDimitry Andric 
2587a6dacacSDimitry Andric /// Helper class to identify an entry in DWARF5AccelTable based on their DIE
2597a6dacacSDimitry Andric /// offset and UnitID.
2607a6dacacSDimitry Andric struct OffsetAndUnitID : std::pair<uint64_t, uint32_t> {
2617a6dacacSDimitry Andric   using Base = std::pair<uint64_t, uint32_t>;
OffsetAndUnitIDOffsetAndUnitID2627a6dacacSDimitry Andric   OffsetAndUnitID(Base B) : Base(B) {}
2637a6dacacSDimitry Andric 
OffsetAndUnitIDOffsetAndUnitID2647a6dacacSDimitry Andric   OffsetAndUnitID(uint64_t Offset, uint32_t UnitID) : Base(Offset, UnitID) {}
offsetOffsetAndUnitID2657a6dacacSDimitry Andric   uint64_t offset() const { return first; };
unitIDOffsetAndUnitID2667a6dacacSDimitry Andric   uint32_t unitID() const { return second; };
2677a6dacacSDimitry Andric };
2687a6dacacSDimitry Andric 
2697a6dacacSDimitry Andric template <>
2707a6dacacSDimitry Andric struct DenseMapInfo<OffsetAndUnitID> : DenseMapInfo<OffsetAndUnitID::Base> {};
2717a6dacacSDimitry Andric 
2720b57cec5SDimitry Andric /// The Data class implementation for DWARF v5 accelerator table. Unlike the
2730b57cec5SDimitry Andric /// Apple Data classes, this class is just a DIE wrapper, and does not know to
2740b57cec5SDimitry Andric /// serialize itself. The complete serialization logic is in the
2750b57cec5SDimitry Andric /// emitDWARF5AccelTable function.
2760b57cec5SDimitry Andric class DWARF5AccelTableData : public AccelTableData {
2770b57cec5SDimitry Andric public:
2785f757f3fSDimitry Andric   struct AttributeEncoding {
2795f757f3fSDimitry Andric     dwarf::Index Index;
2805f757f3fSDimitry Andric     dwarf::Form Form;
2810b57cec5SDimitry Andric   };
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric   static uint32_t hash(StringRef Name) { return caseFoldingDjbHash(Name); }
2840b57cec5SDimitry Andric 
2855f757f3fSDimitry Andric   DWARF5AccelTableData(const DIE &Die, const uint32_t UnitID,
2865f757f3fSDimitry Andric                        const bool IsTU = false);
2877a6dacacSDimitry Andric   DWARF5AccelTableData(const uint64_t DieOffset,
2887a6dacacSDimitry Andric                        const std::optional<uint64_t> DefiningParentOffset,
2897a6dacacSDimitry Andric                        const unsigned DieTag, const unsigned UnitID,
2907a6dacacSDimitry Andric                        const bool IsTU = false)
2917a6dacacSDimitry Andric       : OffsetVal(DieOffset), ParentOffset(DefiningParentOffset),
2927a6dacacSDimitry Andric         DieTag(DieTag), UnitID(UnitID), IsTU(IsTU) {}
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric #ifndef NDEBUG
2950b57cec5SDimitry Andric   void print(raw_ostream &OS) const override;
2960b57cec5SDimitry Andric #endif
2970b57cec5SDimitry Andric 
2985f757f3fSDimitry Andric   uint64_t getDieOffset() const {
299cb14a3feSDimitry Andric     assert(isNormalized() && "Accessing DIE Offset before normalizing.");
3005f757f3fSDimitry Andric     return std::get<uint64_t>(OffsetVal);
3015f757f3fSDimitry Andric   }
3027a6dacacSDimitry Andric 
3037a6dacacSDimitry Andric   OffsetAndUnitID getDieOffsetAndUnitID() const {
3047a6dacacSDimitry Andric     return {getDieOffset(), UnitID};
3057a6dacacSDimitry Andric   }
3067a6dacacSDimitry Andric 
3070b57cec5SDimitry Andric   unsigned getDieTag() const { return DieTag; }
3085f757f3fSDimitry Andric   unsigned getUnitID() const { return UnitID; }
3095f757f3fSDimitry Andric   bool isTU() const { return IsTU; }
3105f757f3fSDimitry Andric   void normalizeDIEToOffset() {
311cb14a3feSDimitry Andric     assert(!isNormalized() && "Accessing offset after normalizing.");
3127a6dacacSDimitry Andric     const DIE *Entry = std::get<const DIE *>(OffsetVal);
3137a6dacacSDimitry Andric     ParentOffset = getDefiningParentDieOffset(*Entry);
3147a6dacacSDimitry Andric     OffsetVal = Entry->getOffset();
3155f757f3fSDimitry Andric   }
3165f757f3fSDimitry Andric   bool isNormalized() const {
3175f757f3fSDimitry Andric     return std::holds_alternative<uint64_t>(OffsetVal);
3185f757f3fSDimitry Andric   }
3190b57cec5SDimitry Andric 
3207a6dacacSDimitry Andric   std::optional<uint64_t> getParentDieOffset() const {
3217a6dacacSDimitry Andric     if (auto OffsetAndId = getParentDieOffsetAndUnitID())
3227a6dacacSDimitry Andric       return OffsetAndId->offset();
3237a6dacacSDimitry Andric     return {};
3247a6dacacSDimitry Andric   }
3257a6dacacSDimitry Andric 
3267a6dacacSDimitry Andric   std::optional<OffsetAndUnitID> getParentDieOffsetAndUnitID() const {
3277a6dacacSDimitry Andric     assert(isNormalized() && "Accessing DIE Offset before normalizing.");
3287a6dacacSDimitry Andric     if (!ParentOffset)
3297a6dacacSDimitry Andric       return std::nullopt;
3307a6dacacSDimitry Andric     return OffsetAndUnitID(*ParentOffset, getUnitID());
3317a6dacacSDimitry Andric   }
3327a6dacacSDimitry Andric 
3337a6dacacSDimitry Andric   /// If `Die` has a non-null parent and the parent is not a declaration,
3347a6dacacSDimitry Andric   /// return its offset.
3357a6dacacSDimitry Andric   static std::optional<uint64_t> getDefiningParentDieOffset(const DIE &Die);
3367a6dacacSDimitry Andric 
3370b57cec5SDimitry Andric protected:
3385f757f3fSDimitry Andric   std::variant<const DIE *, uint64_t> OffsetVal;
3397a6dacacSDimitry Andric   std::optional<uint64_t> ParentOffset;
3405f757f3fSDimitry Andric   uint32_t DieTag : 16;
3415f757f3fSDimitry Andric   uint32_t UnitID : 15;
3425f757f3fSDimitry Andric   uint32_t IsTU : 1;
3430b57cec5SDimitry Andric 
3445f757f3fSDimitry Andric   uint64_t order() const override { return getDieOffset(); }
3455f757f3fSDimitry Andric };
3465f757f3fSDimitry Andric 
3475f757f3fSDimitry Andric struct TypeUnitMetaInfo {
3485f757f3fSDimitry Andric   // Symbol for start of the TU section or signature if this is SplitDwarf.
3495f757f3fSDimitry Andric   std::variant<MCSymbol *, uint64_t> LabelOrSignature;
3505f757f3fSDimitry Andric   // Unique ID of Type Unit.
3515f757f3fSDimitry Andric   unsigned UniqueID;
3525f757f3fSDimitry Andric };
3535f757f3fSDimitry Andric using TUVectorTy = SmallVector<TypeUnitMetaInfo, 1>;
3545f757f3fSDimitry Andric class DWARF5AccelTable : public AccelTable<DWARF5AccelTableData> {
3555f757f3fSDimitry Andric   // Symbols to start of all the TU sections that were generated.
3565f757f3fSDimitry Andric   TUVectorTy TUSymbolsOrHashes;
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric public:
3595f757f3fSDimitry Andric   struct UnitIndexAndEncoding {
3605f757f3fSDimitry Andric     unsigned Index;
361cb14a3feSDimitry Andric     DWARF5AccelTableData::AttributeEncoding Encoding;
3625f757f3fSDimitry Andric   };
3635f757f3fSDimitry Andric   /// Returns type units that were constructed.
3645f757f3fSDimitry Andric   const TUVectorTy &getTypeUnitsSymbols() { return TUSymbolsOrHashes; }
3655f757f3fSDimitry Andric   /// Add a type unit start symbol.
3665f757f3fSDimitry Andric   void addTypeUnitSymbol(DwarfTypeUnit &U);
3675f757f3fSDimitry Andric   /// Add a type unit Signature.
3685f757f3fSDimitry Andric   void addTypeUnitSignature(DwarfTypeUnit &U);
3695f757f3fSDimitry Andric   /// Convert DIE entries to explicit offset.
3705f757f3fSDimitry Andric   /// Needs to be called after DIE offsets are computed.
3715f757f3fSDimitry Andric   void convertDieToOffset() {
3725f757f3fSDimitry Andric     for (auto &Entry : Entries) {
3731db9f3b2SDimitry Andric       for (auto *Data : Entry.second.getValues<DWARF5AccelTableData *>()) {
3745f757f3fSDimitry Andric         // For TU we normalize as each Unit is emitted.
3755f757f3fSDimitry Andric         // So when this is invoked after CU construction we will be in mixed
3765f757f3fSDimitry Andric         // state.
3775f757f3fSDimitry Andric         if (!Data->isNormalized())
3785f757f3fSDimitry Andric           Data->normalizeDIEToOffset();
3795f757f3fSDimitry Andric       }
3805f757f3fSDimitry Andric     }
3815f757f3fSDimitry Andric   }
3825f757f3fSDimitry Andric 
3835f757f3fSDimitry Andric   void addTypeEntries(DWARF5AccelTable &Table) {
3845f757f3fSDimitry Andric     for (auto &Entry : Table.getEntries()) {
3851db9f3b2SDimitry Andric       for (auto *Data : Entry.second.getValues<DWARF5AccelTableData *>()) {
3867a6dacacSDimitry Andric         addName(Entry.second.Name, Data->getDieOffset(),
3877a6dacacSDimitry Andric                 Data->getParentDieOffset(), Data->getDieTag(),
3885f757f3fSDimitry Andric                 Data->getUnitID(), true);
3895f757f3fSDimitry Andric       }
3905f757f3fSDimitry Andric     }
3915f757f3fSDimitry Andric   }
3920b57cec5SDimitry Andric };
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric void emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
3950b57cec5SDimitry Andric                              StringRef Prefix, const MCSymbol *SecBegin,
3960b57cec5SDimitry Andric                              ArrayRef<AppleAccelTableData::Atom> Atoms);
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric /// Emit an Apple Accelerator Table consisting of entries in the specified
3990b57cec5SDimitry Andric /// AccelTable. The DataT template parameter should be derived from
4000b57cec5SDimitry Andric /// AppleAccelTableData.
4010b57cec5SDimitry Andric template <typename DataT>
4020b57cec5SDimitry Andric void emitAppleAccelTable(AsmPrinter *Asm, AccelTable<DataT> &Contents,
4030b57cec5SDimitry Andric                          StringRef Prefix, const MCSymbol *SecBegin) {
404bdd1243dSDimitry Andric   static_assert(std::is_convertible<DataT *, AppleAccelTableData *>::value);
4050b57cec5SDimitry Andric   emitAppleAccelTableImpl(Asm, Contents, Prefix, SecBegin, DataT::Atoms);
4060b57cec5SDimitry Andric }
4070b57cec5SDimitry Andric 
4085f757f3fSDimitry Andric void emitDWARF5AccelTable(AsmPrinter *Asm, DWARF5AccelTable &Contents,
4090b57cec5SDimitry Andric                           const DwarfDebug &DD,
4100b57cec5SDimitry Andric                           ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs);
4110b57cec5SDimitry Andric 
4125f757f3fSDimitry Andric /// Emit a DWARFv5 Accelerator Table consisting of entries in the specified
4135f757f3fSDimitry Andric /// AccelTable. The \p CUs contains either symbols keeping offsets to the
4145f757f3fSDimitry Andric /// start of compilation unit, either offsets to the start of compilation
4155f757f3fSDimitry Andric /// unit themselves.
4160b57cec5SDimitry Andric void emitDWARF5AccelTable(
4175f757f3fSDimitry Andric     AsmPrinter *Asm, DWARF5AccelTable &Contents,
4185f757f3fSDimitry Andric     ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
4195f757f3fSDimitry Andric     llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
4205f757f3fSDimitry Andric         const DWARF5AccelTableData &)>
4215f757f3fSDimitry Andric         getIndexForEntry);
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric /// Accelerator table data implementation for simple Apple accelerator tables
4240b57cec5SDimitry Andric /// with just a DIE reference.
4250b57cec5SDimitry Andric class AppleAccelTableOffsetData : public AppleAccelTableData {
4260b57cec5SDimitry Andric public:
4270b57cec5SDimitry Andric   AppleAccelTableOffsetData(const DIE &D) : Die(D) {}
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric   void emit(AsmPrinter *Asm) const override;
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   static constexpr Atom Atoms[] = {
4320b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric #ifndef NDEBUG
4350b57cec5SDimitry Andric   void print(raw_ostream &OS) const override;
4360b57cec5SDimitry Andric #endif
4370b57cec5SDimitry Andric protected:
4380b57cec5SDimitry Andric   uint64_t order() const override { return Die.getOffset(); }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric   const DIE &Die;
4410b57cec5SDimitry Andric };
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric /// Accelerator table data implementation for Apple type accelerator tables.
4440b57cec5SDimitry Andric class AppleAccelTableTypeData : public AppleAccelTableOffsetData {
4450b57cec5SDimitry Andric public:
4460b57cec5SDimitry Andric   AppleAccelTableTypeData(const DIE &D) : AppleAccelTableOffsetData(D) {}
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric   void emit(AsmPrinter *Asm) const override;
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric   static constexpr Atom Atoms[] = {
4510b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
4520b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
4530b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric #ifndef NDEBUG
4560b57cec5SDimitry Andric   void print(raw_ostream &OS) const override;
4570b57cec5SDimitry Andric #endif
4580b57cec5SDimitry Andric };
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric /// Accelerator table data implementation for simple Apple accelerator tables
4610b57cec5SDimitry Andric /// with a DIE offset but no actual DIE pointer.
4620b57cec5SDimitry Andric class AppleAccelTableStaticOffsetData : public AppleAccelTableData {
4630b57cec5SDimitry Andric public:
4640b57cec5SDimitry Andric   AppleAccelTableStaticOffsetData(uint32_t Offset) : Offset(Offset) {}
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric   void emit(AsmPrinter *Asm) const override;
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   static constexpr Atom Atoms[] = {
4690b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric #ifndef NDEBUG
4720b57cec5SDimitry Andric   void print(raw_ostream &OS) const override;
4730b57cec5SDimitry Andric #endif
4740b57cec5SDimitry Andric protected:
4750b57cec5SDimitry Andric   uint64_t order() const override { return Offset; }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   uint32_t Offset;
4780b57cec5SDimitry Andric };
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric /// Accelerator table data implementation for type accelerator tables with
4810b57cec5SDimitry Andric /// a DIE offset but no actual DIE pointer.
4820b57cec5SDimitry Andric class AppleAccelTableStaticTypeData : public AppleAccelTableStaticOffsetData {
4830b57cec5SDimitry Andric public:
4840b57cec5SDimitry Andric   AppleAccelTableStaticTypeData(uint32_t Offset, uint16_t Tag,
4850b57cec5SDimitry Andric                                 bool ObjCClassIsImplementation,
4860b57cec5SDimitry Andric                                 uint32_t QualifiedNameHash)
4870b57cec5SDimitry Andric       : AppleAccelTableStaticOffsetData(Offset),
4880b57cec5SDimitry Andric         QualifiedNameHash(QualifiedNameHash), Tag(Tag),
4890b57cec5SDimitry Andric         ObjCClassIsImplementation(ObjCClassIsImplementation) {}
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric   void emit(AsmPrinter *Asm) const override;
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   static constexpr Atom Atoms[] = {
4940b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
4950b57cec5SDimitry Andric       Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
4960b57cec5SDimitry Andric       Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric #ifndef NDEBUG
4990b57cec5SDimitry Andric   void print(raw_ostream &OS) const override;
5000b57cec5SDimitry Andric #endif
5010b57cec5SDimitry Andric protected:
5020b57cec5SDimitry Andric   uint64_t order() const override { return Offset; }
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric   uint32_t QualifiedNameHash;
5050b57cec5SDimitry Andric   uint16_t Tag;
5060b57cec5SDimitry Andric   bool ObjCClassIsImplementation;
5070b57cec5SDimitry Andric };
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric } // end namespace llvm
5100b57cec5SDimitry Andric 
511fe6060f1SDimitry Andric #endif // LLVM_CODEGEN_ACCELTABLE_H
512