1eb11fae6SDimitry Andric //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
2eb11fae6SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6eb11fae6SDimitry Andric //
7eb11fae6SDimitry Andric //===----------------------------------------------------------------------===//
8eb11fae6SDimitry Andric //
9eb11fae6SDimitry Andric // This file contains support for writing accelerator tables.
10eb11fae6SDimitry Andric //
11eb11fae6SDimitry Andric //===----------------------------------------------------------------------===//
12eb11fae6SDimitry Andric
13eb11fae6SDimitry Andric #include "llvm/CodeGen/AccelTable.h"
14eb11fae6SDimitry Andric #include "DwarfCompileUnit.h"
15b1c73532SDimitry Andric #include "DwarfUnit.h"
164df029ccSDimitry Andric #include "llvm/ADT/DenseSet.h"
17eb11fae6SDimitry Andric #include "llvm/ADT/STLExtras.h"
18eb11fae6SDimitry Andric #include "llvm/ADT/Twine.h"
19eb11fae6SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
20eb11fae6SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
21eb11fae6SDimitry Andric #include "llvm/CodeGen/DIE.h"
22eb11fae6SDimitry Andric #include "llvm/MC/MCStreamer.h"
23eb11fae6SDimitry Andric #include "llvm/MC/MCSymbol.h"
24eb11fae6SDimitry Andric #include "llvm/Support/raw_ostream.h"
25d8e91e46SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
26eb11fae6SDimitry Andric #include <algorithm>
27eb11fae6SDimitry Andric #include <cstddef>
28eb11fae6SDimitry Andric #include <cstdint>
29eb11fae6SDimitry Andric #include <limits>
30eb11fae6SDimitry Andric #include <vector>
31eb11fae6SDimitry Andric
32eb11fae6SDimitry Andric using namespace llvm;
33eb11fae6SDimitry Andric
computeBucketCount()34eb11fae6SDimitry Andric void AccelTableBase::computeBucketCount() {
35ac9a064cSDimitry Andric SmallVector<uint32_t, 0> Uniques;
36eb11fae6SDimitry Andric Uniques.reserve(Entries.size());
37eb11fae6SDimitry Andric for (const auto &E : Entries)
38eb11fae6SDimitry Andric Uniques.push_back(E.second.HashValue);
39ac9a064cSDimitry Andric llvm::sort(Uniques);
40ac9a064cSDimitry Andric UniqueHashCount = llvm::unique(Uniques) - Uniques.begin();
41ac9a064cSDimitry Andric BucketCount = dwarf::getDebugNamesBucketCount(UniqueHashCount);
42eb11fae6SDimitry Andric }
43eb11fae6SDimitry Andric
finalize(AsmPrinter * Asm,StringRef Prefix)44eb11fae6SDimitry Andric void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
45eb11fae6SDimitry Andric // Create the individual hash data outputs.
46eb11fae6SDimitry Andric for (auto &E : Entries) {
47eb11fae6SDimitry Andric // Unique the entries.
48e6d15924SDimitry Andric llvm::stable_sort(E.second.Values,
49eb11fae6SDimitry Andric [](const AccelTableData *A, const AccelTableData *B) {
50eb11fae6SDimitry Andric return *A < *B;
51eb11fae6SDimitry Andric });
52ac9a064cSDimitry Andric E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end());
53eb11fae6SDimitry Andric }
54eb11fae6SDimitry Andric
55eb11fae6SDimitry Andric // Figure out how many buckets we need, then compute the bucket contents and
56eb11fae6SDimitry Andric // the final ordering. The hashes and offsets can be emitted by walking these
57eb11fae6SDimitry Andric // data structures. We add temporary symbols to the data so they can be
58eb11fae6SDimitry Andric // referenced when emitting the offsets.
59eb11fae6SDimitry Andric computeBucketCount();
60eb11fae6SDimitry Andric
61eb11fae6SDimitry Andric // Compute bucket contents and final ordering.
62eb11fae6SDimitry Andric Buckets.resize(BucketCount);
63eb11fae6SDimitry Andric for (auto &E : Entries) {
64eb11fae6SDimitry Andric uint32_t Bucket = E.second.HashValue % BucketCount;
65eb11fae6SDimitry Andric Buckets[Bucket].push_back(&E.second);
66eb11fae6SDimitry Andric E.second.Sym = Asm->createTempSymbol(Prefix);
67eb11fae6SDimitry Andric }
68eb11fae6SDimitry Andric
69eb11fae6SDimitry Andric // Sort the contents of the buckets by hash value so that hash collisions end
70eb11fae6SDimitry Andric // up together. Stable sort makes testing easier and doesn't cost much more.
71eb11fae6SDimitry Andric for (auto &Bucket : Buckets)
72e6d15924SDimitry Andric llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
73eb11fae6SDimitry Andric return LHS->HashValue < RHS->HashValue;
74eb11fae6SDimitry Andric });
75eb11fae6SDimitry Andric }
76eb11fae6SDimitry Andric
77eb11fae6SDimitry Andric namespace {
78eb11fae6SDimitry Andric /// Base class for writing out Accelerator tables. It holds the common
79eb11fae6SDimitry Andric /// functionality for the two Accelerator table types.
80eb11fae6SDimitry Andric class AccelTableWriter {
81eb11fae6SDimitry Andric protected:
82eb11fae6SDimitry Andric AsmPrinter *const Asm; ///< Destination.
83eb11fae6SDimitry Andric const AccelTableBase &Contents; ///< Data to emit.
84eb11fae6SDimitry Andric
85eb11fae6SDimitry Andric /// Controls whether to emit duplicate hash and offset table entries for names
86eb11fae6SDimitry Andric /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
87eb11fae6SDimitry Andric /// tables do.
88eb11fae6SDimitry Andric const bool SkipIdenticalHashes;
89eb11fae6SDimitry Andric
90eb11fae6SDimitry Andric void emitHashes() const;
91eb11fae6SDimitry Andric
92eb11fae6SDimitry Andric /// Emit offsets to lists of entries with identical names. The offsets are
93eb11fae6SDimitry Andric /// relative to the Base argument.
94eb11fae6SDimitry Andric void emitOffsets(const MCSymbol *Base) const;
95eb11fae6SDimitry Andric
96eb11fae6SDimitry Andric public:
AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,bool SkipIdenticalHashes)97eb11fae6SDimitry Andric AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
98eb11fae6SDimitry Andric bool SkipIdenticalHashes)
99eb11fae6SDimitry Andric : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
100eb11fae6SDimitry Andric }
101eb11fae6SDimitry Andric };
102eb11fae6SDimitry Andric
103eb11fae6SDimitry Andric class AppleAccelTableWriter : public AccelTableWriter {
104eb11fae6SDimitry Andric using Atom = AppleAccelTableData::Atom;
105eb11fae6SDimitry Andric
106eb11fae6SDimitry Andric /// The fixed header of an Apple Accelerator Table.
107eb11fae6SDimitry Andric struct Header {
108eb11fae6SDimitry Andric uint32_t Magic = MagicHash;
109eb11fae6SDimitry Andric uint16_t Version = 1;
110eb11fae6SDimitry Andric uint16_t HashFunction = dwarf::DW_hash_function_djb;
111eb11fae6SDimitry Andric uint32_t BucketCount;
112eb11fae6SDimitry Andric uint32_t HashCount;
113eb11fae6SDimitry Andric uint32_t HeaderDataLength;
114eb11fae6SDimitry Andric
115eb11fae6SDimitry Andric /// 'HASH' magic value to detect endianness.
116eb11fae6SDimitry Andric static const uint32_t MagicHash = 0x48415348;
117eb11fae6SDimitry Andric
Header__anon9fd034dd0311::AppleAccelTableWriter::Header118eb11fae6SDimitry Andric Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
119eb11fae6SDimitry Andric : BucketCount(BucketCount), HashCount(UniqueHashCount),
120eb11fae6SDimitry Andric HeaderDataLength(DataLength) {}
121eb11fae6SDimitry Andric
122eb11fae6SDimitry Andric void emit(AsmPrinter *Asm) const;
123eb11fae6SDimitry Andric #ifndef NDEBUG
124eb11fae6SDimitry Andric void print(raw_ostream &OS) const;
dump__anon9fd034dd0311::AppleAccelTableWriter::Header125eb11fae6SDimitry Andric void dump() const { print(dbgs()); }
126eb11fae6SDimitry Andric #endif
127eb11fae6SDimitry Andric };
128eb11fae6SDimitry Andric
129eb11fae6SDimitry Andric /// The HeaderData describes the structure of an Apple accelerator table
130eb11fae6SDimitry Andric /// through a list of Atoms.
131eb11fae6SDimitry Andric struct HeaderData {
132eb11fae6SDimitry Andric /// In the case of data that is referenced via DW_FORM_ref_* the offset
133eb11fae6SDimitry Andric /// base is used to describe the offset for all forms in the list of atoms.
134eb11fae6SDimitry Andric uint32_t DieOffsetBase;
135eb11fae6SDimitry Andric
136eb11fae6SDimitry Andric const SmallVector<Atom, 4> Atoms;
137eb11fae6SDimitry Andric
HeaderData__anon9fd034dd0311::AppleAccelTableWriter::HeaderData138eb11fae6SDimitry Andric HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
139eb11fae6SDimitry Andric : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
140eb11fae6SDimitry Andric
141eb11fae6SDimitry Andric void emit(AsmPrinter *Asm) const;
142eb11fae6SDimitry Andric #ifndef NDEBUG
143eb11fae6SDimitry Andric void print(raw_ostream &OS) const;
dump__anon9fd034dd0311::AppleAccelTableWriter::HeaderData144eb11fae6SDimitry Andric void dump() const { print(dbgs()); }
145eb11fae6SDimitry Andric #endif
146eb11fae6SDimitry Andric };
147eb11fae6SDimitry Andric
148eb11fae6SDimitry Andric Header Header;
149eb11fae6SDimitry Andric HeaderData HeaderData;
150eb11fae6SDimitry Andric const MCSymbol *SecBegin;
151eb11fae6SDimitry Andric
152eb11fae6SDimitry Andric void emitBuckets() const;
153eb11fae6SDimitry Andric void emitData() const;
154eb11fae6SDimitry Andric
155eb11fae6SDimitry Andric public:
AppleAccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<Atom> Atoms,const MCSymbol * SecBegin)156eb11fae6SDimitry Andric AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
157eb11fae6SDimitry Andric ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
158eb11fae6SDimitry Andric : AccelTableWriter(Asm, Contents, true),
159eb11fae6SDimitry Andric Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
160eb11fae6SDimitry Andric 8 + (Atoms.size() * 4)),
161eb11fae6SDimitry Andric HeaderData(Atoms), SecBegin(SecBegin) {}
162eb11fae6SDimitry Andric
163eb11fae6SDimitry Andric void emit() const;
164eb11fae6SDimitry Andric
165eb11fae6SDimitry Andric #ifndef NDEBUG
166eb11fae6SDimitry Andric void print(raw_ostream &OS) const;
dump() const167eb11fae6SDimitry Andric void dump() const { print(dbgs()); }
168eb11fae6SDimitry Andric #endif
169eb11fae6SDimitry Andric };
170eb11fae6SDimitry Andric
171eb11fae6SDimitry Andric /// Class responsible for emitting a DWARF v5 Accelerator Table. The only
172eb11fae6SDimitry Andric /// public function is emit(), which performs the actual emission.
173eb11fae6SDimitry Andric ///
174aca2e42cSDimitry Andric /// A callback abstracts the logic to provide a CU index for a given entry.
175eb11fae6SDimitry Andric class Dwarf5AccelTableWriter : public AccelTableWriter {
176eb11fae6SDimitry Andric struct Header {
177eb11fae6SDimitry Andric uint16_t Version = 5;
178eb11fae6SDimitry Andric uint16_t Padding = 0;
179eb11fae6SDimitry Andric uint32_t CompUnitCount;
180eb11fae6SDimitry Andric uint32_t LocalTypeUnitCount = 0;
181eb11fae6SDimitry Andric uint32_t ForeignTypeUnitCount = 0;
1827fa27ce4SDimitry Andric uint32_t BucketCount = 0;
1837fa27ce4SDimitry Andric uint32_t NameCount = 0;
184eb11fae6SDimitry Andric uint32_t AbbrevTableSize = 0;
185eb11fae6SDimitry Andric uint32_t AugmentationStringSize = sizeof(AugmentationString);
186eb11fae6SDimitry Andric char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
187eb11fae6SDimitry Andric
Header__anon9fd034dd0311::Dwarf5AccelTableWriter::Header188b1c73532SDimitry Andric Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
189b1c73532SDimitry Andric uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
190b1c73532SDimitry Andric uint32_t NameCount)
191b1c73532SDimitry Andric : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
192b1c73532SDimitry Andric ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
193eb11fae6SDimitry Andric NameCount(NameCount) {}
194eb11fae6SDimitry Andric
195344a3780SDimitry Andric void emit(Dwarf5AccelTableWriter &Ctx);
196eb11fae6SDimitry Andric };
197eb11fae6SDimitry Andric
198eb11fae6SDimitry Andric Header Header;
199ac9a064cSDimitry Andric /// FoldingSet that uniques the abbreviations.
200ac9a064cSDimitry Andric FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
201ac9a064cSDimitry Andric /// Vector containing DebugNames abbreviations for iteration in order.
202ac9a064cSDimitry Andric SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
203ac9a064cSDimitry Andric /// The bump allocator to use when creating DIEAbbrev objects in the uniqued
204ac9a064cSDimitry Andric /// storage container.
205ac9a064cSDimitry Andric BumpPtrAllocator Alloc;
206b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
207b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
208b1c73532SDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
209aca2e42cSDimitry Andric const DWARF5AccelTableData &)>
210b1c73532SDimitry Andric getIndexForEntry;
211344a3780SDimitry Andric MCSymbol *ContributionEnd = nullptr;
212eb11fae6SDimitry Andric MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
213eb11fae6SDimitry Andric MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
214eb11fae6SDimitry Andric MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
215b1c73532SDimitry Andric // Indicates if this module is built with Split Dwarf enabled.
216b1c73532SDimitry Andric bool IsSplitDwarf = false;
2174df029ccSDimitry Andric /// Stores the DIE offsets which are indexed by this table.
2184df029ccSDimitry Andric DenseSet<OffsetAndUnitID> IndexedOffsets;
219eb11fae6SDimitry Andric
220b1c73532SDimitry Andric void populateAbbrevsMap();
221eb11fae6SDimitry Andric
222eb11fae6SDimitry Andric void emitCUList() const;
223b1c73532SDimitry Andric void emitTUList() const;
224eb11fae6SDimitry Andric void emitBuckets() const;
225eb11fae6SDimitry Andric void emitStringOffsets() const;
226eb11fae6SDimitry Andric void emitAbbrevs() const;
2274df029ccSDimitry Andric void emitEntry(
2284df029ccSDimitry Andric const DWARF5AccelTableData &Entry,
2294df029ccSDimitry Andric const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
230ac9a064cSDimitry Andric DenseSet<MCSymbol *> &EmittedAccelEntrySymbols);
2314df029ccSDimitry Andric void emitData();
232eb11fae6SDimitry Andric
233eb11fae6SDimitry Andric public:
234eb11fae6SDimitry Andric Dwarf5AccelTableWriter(
235eb11fae6SDimitry Andric AsmPrinter *Asm, const AccelTableBase &Contents,
236b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
237b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
238aca2e42cSDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
239aca2e42cSDimitry Andric const DWARF5AccelTableData &)>
240b1c73532SDimitry Andric getIndexForEntry,
241b1c73532SDimitry Andric bool IsSplitDwarf);
~Dwarf5AccelTableWriter()242ac9a064cSDimitry Andric ~Dwarf5AccelTableWriter() {
243ac9a064cSDimitry Andric for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
244ac9a064cSDimitry Andric Abbrev->~DebugNamesAbbrev();
245ac9a064cSDimitry Andric }
246344a3780SDimitry Andric void emit();
247eb11fae6SDimitry Andric };
248eb11fae6SDimitry Andric } // namespace
249eb11fae6SDimitry Andric
emitHashes() const250eb11fae6SDimitry Andric void AccelTableWriter::emitHashes() const {
251eb11fae6SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
252eb11fae6SDimitry Andric unsigned BucketIdx = 0;
2534b4fe385SDimitry Andric for (const auto &Bucket : Contents.getBuckets()) {
2544b4fe385SDimitry Andric for (const auto &Hash : Bucket) {
255eb11fae6SDimitry Andric uint32_t HashValue = Hash->HashValue;
256eb11fae6SDimitry Andric if (SkipIdenticalHashes && PrevHash == HashValue)
257eb11fae6SDimitry Andric continue;
258eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
259eb11fae6SDimitry Andric Asm->emitInt32(HashValue);
260eb11fae6SDimitry Andric PrevHash = HashValue;
261eb11fae6SDimitry Andric }
262eb11fae6SDimitry Andric BucketIdx++;
263eb11fae6SDimitry Andric }
264eb11fae6SDimitry Andric }
265eb11fae6SDimitry Andric
emitOffsets(const MCSymbol * Base) const266eb11fae6SDimitry Andric void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
267eb11fae6SDimitry Andric const auto &Buckets = Contents.getBuckets();
268eb11fae6SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
269eb11fae6SDimitry Andric for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
270eb11fae6SDimitry Andric for (auto *Hash : Buckets[i]) {
271eb11fae6SDimitry Andric uint32_t HashValue = Hash->HashValue;
272eb11fae6SDimitry Andric if (SkipIdenticalHashes && PrevHash == HashValue)
273eb11fae6SDimitry Andric continue;
274eb11fae6SDimitry Andric PrevHash = HashValue;
275eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
276b60736ecSDimitry Andric Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
277eb11fae6SDimitry Andric }
278eb11fae6SDimitry Andric }
279eb11fae6SDimitry Andric }
280eb11fae6SDimitry Andric
emit(AsmPrinter * Asm) const281eb11fae6SDimitry Andric void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
282eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header Magic");
283eb11fae6SDimitry Andric Asm->emitInt32(Magic);
284eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header Version");
285eb11fae6SDimitry Andric Asm->emitInt16(Version);
286eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header Hash Function");
287eb11fae6SDimitry Andric Asm->emitInt16(HashFunction);
288eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header Bucket Count");
289eb11fae6SDimitry Andric Asm->emitInt32(BucketCount);
290eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header Hash Count");
291eb11fae6SDimitry Andric Asm->emitInt32(HashCount);
292eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header Data Length");
293eb11fae6SDimitry Andric Asm->emitInt32(HeaderDataLength);
294eb11fae6SDimitry Andric }
295eb11fae6SDimitry Andric
emit(AsmPrinter * Asm) const296eb11fae6SDimitry Andric void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
297eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
298eb11fae6SDimitry Andric Asm->emitInt32(DieOffsetBase);
299eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("HeaderData Atom Count");
300eb11fae6SDimitry Andric Asm->emitInt32(Atoms.size());
301eb11fae6SDimitry Andric
302eb11fae6SDimitry Andric for (const Atom &A : Atoms) {
303eb11fae6SDimitry Andric Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
304eb11fae6SDimitry Andric Asm->emitInt16(A.Type);
305eb11fae6SDimitry Andric Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
306eb11fae6SDimitry Andric Asm->emitInt16(A.Form);
307eb11fae6SDimitry Andric }
308eb11fae6SDimitry Andric }
309eb11fae6SDimitry Andric
emitBuckets() const310eb11fae6SDimitry Andric void AppleAccelTableWriter::emitBuckets() const {
311eb11fae6SDimitry Andric const auto &Buckets = Contents.getBuckets();
312eb11fae6SDimitry Andric unsigned index = 0;
313eb11fae6SDimitry Andric for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
314eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Bucket " + Twine(i));
315eb11fae6SDimitry Andric if (!Buckets[i].empty())
316eb11fae6SDimitry Andric Asm->emitInt32(index);
317eb11fae6SDimitry Andric else
318eb11fae6SDimitry Andric Asm->emitInt32(std::numeric_limits<uint32_t>::max());
319eb11fae6SDimitry Andric // Buckets point in the list of hashes, not to the data. Do not increment
320eb11fae6SDimitry Andric // the index multiple times in case of hash collisions.
321eb11fae6SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
322eb11fae6SDimitry Andric for (auto *HD : Buckets[i]) {
323eb11fae6SDimitry Andric uint32_t HashValue = HD->HashValue;
324eb11fae6SDimitry Andric if (PrevHash != HashValue)
325eb11fae6SDimitry Andric ++index;
326eb11fae6SDimitry Andric PrevHash = HashValue;
327eb11fae6SDimitry Andric }
328eb11fae6SDimitry Andric }
329eb11fae6SDimitry Andric }
330eb11fae6SDimitry Andric
emitData() const331eb11fae6SDimitry Andric void AppleAccelTableWriter::emitData() const {
332eb11fae6SDimitry Andric const auto &Buckets = Contents.getBuckets();
333344a3780SDimitry Andric for (const AccelTableBase::HashList &Bucket : Buckets) {
334eb11fae6SDimitry Andric uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
3354b4fe385SDimitry Andric for (const auto &Hash : Bucket) {
336eb11fae6SDimitry Andric // Terminate the previous entry if there is no hash collision with the
337eb11fae6SDimitry Andric // current one.
338eb11fae6SDimitry Andric if (PrevHash != std::numeric_limits<uint64_t>::max() &&
339eb11fae6SDimitry Andric PrevHash != Hash->HashValue)
340eb11fae6SDimitry Andric Asm->emitInt32(0);
341eb11fae6SDimitry Andric // Remember to emit the label for our offset.
342cfca06d7SDimitry Andric Asm->OutStreamer->emitLabel(Hash->Sym);
343eb11fae6SDimitry Andric Asm->OutStreamer->AddComment(Hash->Name.getString());
344eb11fae6SDimitry Andric Asm->emitDwarfStringOffset(Hash->Name);
345eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Num DIEs");
346eb11fae6SDimitry Andric Asm->emitInt32(Hash->Values.size());
347aca2e42cSDimitry Andric for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
348aca2e42cSDimitry Andric V->emit(Asm);
349eb11fae6SDimitry Andric PrevHash = Hash->HashValue;
350eb11fae6SDimitry Andric }
351eb11fae6SDimitry Andric // Emit the final end marker for the bucket.
352344a3780SDimitry Andric if (!Bucket.empty())
353eb11fae6SDimitry Andric Asm->emitInt32(0);
354eb11fae6SDimitry Andric }
355eb11fae6SDimitry Andric }
356eb11fae6SDimitry Andric
emit() const357eb11fae6SDimitry Andric void AppleAccelTableWriter::emit() const {
358eb11fae6SDimitry Andric Header.emit(Asm);
359eb11fae6SDimitry Andric HeaderData.emit(Asm);
360eb11fae6SDimitry Andric emitBuckets();
361eb11fae6SDimitry Andric emitHashes();
362eb11fae6SDimitry Andric emitOffsets(SecBegin);
363eb11fae6SDimitry Andric emitData();
364eb11fae6SDimitry Andric }
365eb11fae6SDimitry Andric
DWARF5AccelTableData(const DIE & Die,const uint32_t UnitID,const bool IsTU)366b1c73532SDimitry Andric DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
367b1c73532SDimitry Andric const uint32_t UnitID,
368b1c73532SDimitry Andric const bool IsTU)
369ac9a064cSDimitry Andric : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
370ac9a064cSDimitry Andric UnitID(UnitID) {}
371b1c73532SDimitry Andric
emit(Dwarf5AccelTableWriter & Ctx)372aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
373eb11fae6SDimitry Andric assert(CompUnitCount > 0 && "Index must have at least one CU.");
374eb11fae6SDimitry Andric
375eb11fae6SDimitry Andric AsmPrinter *Asm = Ctx.Asm;
376344a3780SDimitry Andric Ctx.ContributionEnd =
377344a3780SDimitry Andric Asm->emitDwarfUnitLength("names", "Header: unit length");
378eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: version");
379eb11fae6SDimitry Andric Asm->emitInt16(Version);
380eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: padding");
381eb11fae6SDimitry Andric Asm->emitInt16(Padding);
382eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: compilation unit count");
383eb11fae6SDimitry Andric Asm->emitInt32(CompUnitCount);
384eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: local type unit count");
385eb11fae6SDimitry Andric Asm->emitInt32(LocalTypeUnitCount);
386eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: foreign type unit count");
387eb11fae6SDimitry Andric Asm->emitInt32(ForeignTypeUnitCount);
388eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: bucket count");
389eb11fae6SDimitry Andric Asm->emitInt32(BucketCount);
390eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: name count");
391eb11fae6SDimitry Andric Asm->emitInt32(NameCount);
392eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: abbreviation table size");
393cfca06d7SDimitry Andric Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
394eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: augmentation string size");
395eb11fae6SDimitry Andric assert(AugmentationStringSize % 4 == 0);
396eb11fae6SDimitry Andric Asm->emitInt32(AugmentationStringSize);
397eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Header: augmentation string");
398cfca06d7SDimitry Andric Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
399eb11fae6SDimitry Andric }
400eb11fae6SDimitry Andric
4014df029ccSDimitry Andric std::optional<uint64_t>
getDefiningParentDieOffset(const DIE & Die)4024df029ccSDimitry Andric DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
4034df029ccSDimitry Andric if (auto *Parent = Die.getParent();
4044df029ccSDimitry Andric Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
4054df029ccSDimitry Andric return Parent->getOffset();
4064df029ccSDimitry Andric return {};
4074df029ccSDimitry Andric }
4084df029ccSDimitry Andric
4094df029ccSDimitry Andric static std::optional<dwarf::Form>
getFormForIdxParent(const DenseSet<OffsetAndUnitID> & IndexedOffsets,std::optional<OffsetAndUnitID> ParentOffset)4104df029ccSDimitry Andric getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
4114df029ccSDimitry Andric std::optional<OffsetAndUnitID> ParentOffset) {
4124df029ccSDimitry Andric // No parent information
4134df029ccSDimitry Andric if (!ParentOffset)
4144df029ccSDimitry Andric return std::nullopt;
4154df029ccSDimitry Andric // Parent is indexed by this table.
4164df029ccSDimitry Andric if (IndexedOffsets.contains(*ParentOffset))
4174df029ccSDimitry Andric return dwarf::Form::DW_FORM_ref4;
4184df029ccSDimitry Andric // Parent is not indexed by this table.
4194df029ccSDimitry Andric return dwarf::Form::DW_FORM_flag_present;
4204df029ccSDimitry Andric }
4214df029ccSDimitry Andric
Profile(FoldingSetNodeID & ID) const422ac9a064cSDimitry Andric void DebugNamesAbbrev::Profile(FoldingSetNodeID &ID) const {
423ac9a064cSDimitry Andric ID.AddInteger(DieTag);
424ac9a064cSDimitry Andric for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
425ac9a064cSDimitry Andric ID.AddInteger(Enc.Index);
426ac9a064cSDimitry Andric ID.AddInteger(Enc.Form);
427ac9a064cSDimitry Andric }
428ac9a064cSDimitry Andric }
429ac9a064cSDimitry Andric
populateAbbrevsMap()430aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::populateAbbrevsMap() {
431eb11fae6SDimitry Andric for (auto &Bucket : Contents.getBuckets()) {
432eb11fae6SDimitry Andric for (auto *Hash : Bucket) {
433aca2e42cSDimitry Andric for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
434b1c73532SDimitry Andric std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
435aca2e42cSDimitry Andric getIndexForEntry(*Value);
4364df029ccSDimitry Andric std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
4374df029ccSDimitry Andric IndexedOffsets, Value->getParentDieOffsetAndUnitID());
438ac9a064cSDimitry Andric DebugNamesAbbrev Abbrev(Value->getDieTag());
439b1c73532SDimitry Andric if (EntryRet)
440ac9a064cSDimitry Andric Abbrev.addAttribute(EntryRet->Encoding);
441ac9a064cSDimitry Andric Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
4424df029ccSDimitry Andric if (MaybeParentForm)
443ac9a064cSDimitry Andric Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
444ac9a064cSDimitry Andric FoldingSetNodeID ID;
445ac9a064cSDimitry Andric Abbrev.Profile(ID);
446ac9a064cSDimitry Andric void *InsertPos;
447ac9a064cSDimitry Andric if (DebugNamesAbbrev *Existing =
448ac9a064cSDimitry Andric AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
449ac9a064cSDimitry Andric Value->setAbbrevNumber(Existing->getNumber());
450ac9a064cSDimitry Andric continue;
451b1c73532SDimitry Andric }
452ac9a064cSDimitry Andric DebugNamesAbbrev *NewAbbrev =
453ac9a064cSDimitry Andric new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
454ac9a064cSDimitry Andric AbbreviationsVector.push_back(NewAbbrev);
455ac9a064cSDimitry Andric NewAbbrev->setNumber(AbbreviationsVector.size());
456ac9a064cSDimitry Andric AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);
457ac9a064cSDimitry Andric Value->setAbbrevNumber(NewAbbrev->getNumber());
458b1c73532SDimitry Andric }
459b1c73532SDimitry Andric }
460b1c73532SDimitry Andric }
461eb11fae6SDimitry Andric }
462eb11fae6SDimitry Andric
emitCUList() const463aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitCUList() const {
464eb11fae6SDimitry Andric for (const auto &CU : enumerate(CompUnits)) {
465eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
466b1c73532SDimitry Andric if (std::holds_alternative<MCSymbol *>(CU.value()))
467b1c73532SDimitry Andric Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
468b1c73532SDimitry Andric else
469b1c73532SDimitry Andric Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
470b1c73532SDimitry Andric }
471b1c73532SDimitry Andric }
472b1c73532SDimitry Andric
emitTUList() const473aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitTUList() const {
474b1c73532SDimitry Andric for (const auto &TU : enumerate(TypeUnits)) {
475b1c73532SDimitry Andric Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
476b1c73532SDimitry Andric if (std::holds_alternative<MCSymbol *>(TU.value()))
477b1c73532SDimitry Andric Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
478b1c73532SDimitry Andric else if (IsSplitDwarf)
479b1c73532SDimitry Andric Asm->emitInt64(std::get<uint64_t>(TU.value()));
480b1c73532SDimitry Andric else
481b1c73532SDimitry Andric Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
482eb11fae6SDimitry Andric }
483eb11fae6SDimitry Andric }
484eb11fae6SDimitry Andric
emitBuckets() const485aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitBuckets() const {
486eb11fae6SDimitry Andric uint32_t Index = 1;
487eb11fae6SDimitry Andric for (const auto &Bucket : enumerate(Contents.getBuckets())) {
488eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
489eb11fae6SDimitry Andric Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
490eb11fae6SDimitry Andric Index += Bucket.value().size();
491eb11fae6SDimitry Andric }
492eb11fae6SDimitry Andric }
493eb11fae6SDimitry Andric
emitStringOffsets() const494aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitStringOffsets() const {
495eb11fae6SDimitry Andric for (const auto &Bucket : enumerate(Contents.getBuckets())) {
496eb11fae6SDimitry Andric for (auto *Hash : Bucket.value()) {
497eb11fae6SDimitry Andric DwarfStringPoolEntryRef String = Hash->Name;
498eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
499eb11fae6SDimitry Andric ": " + String.getString());
500eb11fae6SDimitry Andric Asm->emitDwarfStringOffset(String);
501eb11fae6SDimitry Andric }
502eb11fae6SDimitry Andric }
503eb11fae6SDimitry Andric }
504eb11fae6SDimitry Andric
emitAbbrevs() const505aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitAbbrevs() const {
506cfca06d7SDimitry Andric Asm->OutStreamer->emitLabel(AbbrevStart);
507ac9a064cSDimitry Andric for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
508eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("Abbrev code");
509ac9a064cSDimitry Andric Asm->emitULEB128(Abbrev->getNumber());
510ac9a064cSDimitry Andric Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
511ac9a064cSDimitry Andric Asm->emitULEB128(Abbrev->getDieTag());
512ac9a064cSDimitry Andric for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
513ac9a064cSDimitry Andric Abbrev->getAttributes()) {
514cfca06d7SDimitry Andric Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
515cfca06d7SDimitry Andric Asm->emitULEB128(AttrEnc.Form,
516eb11fae6SDimitry Andric dwarf::FormEncodingString(AttrEnc.Form).data());
517eb11fae6SDimitry Andric }
518cfca06d7SDimitry Andric Asm->emitULEB128(0, "End of abbrev");
519cfca06d7SDimitry Andric Asm->emitULEB128(0, "End of abbrev");
520eb11fae6SDimitry Andric }
521cfca06d7SDimitry Andric Asm->emitULEB128(0, "End of abbrev list");
522cfca06d7SDimitry Andric Asm->OutStreamer->emitLabel(AbbrevEnd);
523eb11fae6SDimitry Andric }
524eb11fae6SDimitry Andric
emitEntry(const DWARF5AccelTableData & Entry,const DenseMap<OffsetAndUnitID,MCSymbol * > & DIEOffsetToAccelEntryLabel,DenseSet<MCSymbol * > & EmittedAccelEntrySymbols)525aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emitEntry(
5264df029ccSDimitry Andric const DWARF5AccelTableData &Entry,
5274df029ccSDimitry Andric const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
528ac9a064cSDimitry Andric DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) {
529ac9a064cSDimitry Andric unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
530ac9a064cSDimitry Andric assert(AbbrevIndex < AbbreviationsVector.size() &&
531ac9a064cSDimitry Andric "Entry abbrev index is outside of abbreviations vector range.");
532ac9a064cSDimitry Andric DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
533b1c73532SDimitry Andric std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
534b1c73532SDimitry Andric getIndexForEntry(Entry);
5354df029ccSDimitry Andric std::optional<OffsetAndUnitID> MaybeParentOffset =
5364df029ccSDimitry Andric Entry.getParentDieOffsetAndUnitID();
5374df029ccSDimitry Andric auto EntrySymbolIt =
5384df029ccSDimitry Andric DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
5394df029ccSDimitry Andric assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
5404df029ccSDimitry Andric MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
5414df029ccSDimitry Andric
5424df029ccSDimitry Andric // Emit the label for this Entry, so that IDX_parents may refer to it.
5434df029ccSDimitry Andric // Note: a DIE may have multiple accelerator Entries; this check avoids
5444df029ccSDimitry Andric // creating/emitting multiple labels for the same DIE.
5454df029ccSDimitry Andric if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
5464df029ccSDimitry Andric Asm->OutStreamer->emitLabel(EntrySymbol);
5474df029ccSDimitry Andric
548ac9a064cSDimitry Andric Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
549b1c73532SDimitry Andric
550ac9a064cSDimitry Andric for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
551ac9a064cSDimitry Andric Abbrev->getAttributes()) {
552eb11fae6SDimitry Andric Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
553eb11fae6SDimitry Andric switch (AttrEnc.Index) {
554b1c73532SDimitry Andric case dwarf::DW_IDX_compile_unit:
555b1c73532SDimitry Andric case dwarf::DW_IDX_type_unit: {
556b1c73532SDimitry Andric DIEInteger ID(EntryRet->Index);
557cfca06d7SDimitry Andric ID.emitValue(Asm, AttrEnc.Form);
558eb11fae6SDimitry Andric break;
559eb11fae6SDimitry Andric }
560eb11fae6SDimitry Andric case dwarf::DW_IDX_die_offset:
561eb11fae6SDimitry Andric assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
562eb11fae6SDimitry Andric Asm->emitInt32(Entry.getDieOffset());
563eb11fae6SDimitry Andric break;
5644df029ccSDimitry Andric case dwarf::DW_IDX_parent: {
5654df029ccSDimitry Andric if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
5664df029ccSDimitry Andric break;
5674df029ccSDimitry Andric auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
5684df029ccSDimitry Andric assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
5694df029ccSDimitry Andric Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
5704df029ccSDimitry Andric break;
5714df029ccSDimitry Andric }
572eb11fae6SDimitry Andric default:
573eb11fae6SDimitry Andric llvm_unreachable("Unexpected index attribute!");
574eb11fae6SDimitry Andric }
575eb11fae6SDimitry Andric }
576eb11fae6SDimitry Andric }
577eb11fae6SDimitry Andric
emitData()5784df029ccSDimitry Andric void Dwarf5AccelTableWriter::emitData() {
5794df029ccSDimitry Andric DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
5804df029ccSDimitry Andric
5814df029ccSDimitry Andric for (OffsetAndUnitID Offset : IndexedOffsets)
5824df029ccSDimitry Andric DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
5834df029ccSDimitry Andric
584cfca06d7SDimitry Andric Asm->OutStreamer->emitLabel(EntryPool);
5854df029ccSDimitry Andric DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
586eb11fae6SDimitry Andric for (auto &Bucket : Contents.getBuckets()) {
587eb11fae6SDimitry Andric for (auto *Hash : Bucket) {
588eb11fae6SDimitry Andric // Remember to emit the label for our offset.
589cfca06d7SDimitry Andric Asm->OutStreamer->emitLabel(Hash->Sym);
5904df029ccSDimitry Andric for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
5914df029ccSDimitry Andric emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
592eb11fae6SDimitry Andric Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
593b60736ecSDimitry Andric Asm->emitInt8(0);
594eb11fae6SDimitry Andric }
595eb11fae6SDimitry Andric }
596eb11fae6SDimitry Andric }
597eb11fae6SDimitry Andric
Dwarf5AccelTableWriter(AsmPrinter * Asm,const AccelTableBase & Contents,ArrayRef<std::variant<MCSymbol *,uint64_t>> CompUnits,ArrayRef<std::variant<MCSymbol *,uint64_t>> TypeUnits,llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding> (const DWARF5AccelTableData &)> getIndexForEntry,bool IsSplitDwarf)598aca2e42cSDimitry Andric Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
599eb11fae6SDimitry Andric AsmPrinter *Asm, const AccelTableBase &Contents,
600b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
601b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
602aca2e42cSDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
603aca2e42cSDimitry Andric const DWARF5AccelTableData &)>
604b1c73532SDimitry Andric getIndexForEntry,
605b1c73532SDimitry Andric bool IsSplitDwarf)
606eb11fae6SDimitry Andric : AccelTableWriter(Asm, Contents, false),
607b1c73532SDimitry Andric Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
608b1c73532SDimitry Andric IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
609eb11fae6SDimitry Andric Contents.getUniqueNameCount()),
610b1c73532SDimitry Andric CompUnits(CompUnits), TypeUnits(TypeUnits),
611b1c73532SDimitry Andric getIndexForEntry(std::move(getIndexForEntry)),
612b1c73532SDimitry Andric IsSplitDwarf(IsSplitDwarf) {
6134df029ccSDimitry Andric
6144df029ccSDimitry Andric for (auto &Bucket : Contents.getBuckets())
6154df029ccSDimitry Andric for (auto *Hash : Bucket)
6164df029ccSDimitry Andric for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
6174df029ccSDimitry Andric IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
6184df029ccSDimitry Andric
619b1c73532SDimitry Andric populateAbbrevsMap();
620eb11fae6SDimitry Andric }
621eb11fae6SDimitry Andric
emit()622aca2e42cSDimitry Andric void Dwarf5AccelTableWriter::emit() {
623eb11fae6SDimitry Andric Header.emit(*this);
624eb11fae6SDimitry Andric emitCUList();
625b1c73532SDimitry Andric emitTUList();
626eb11fae6SDimitry Andric emitBuckets();
627eb11fae6SDimitry Andric emitHashes();
628eb11fae6SDimitry Andric emitStringOffsets();
629eb11fae6SDimitry Andric emitOffsets(EntryPool);
630eb11fae6SDimitry Andric emitAbbrevs();
631eb11fae6SDimitry Andric emitData();
632e3b55780SDimitry Andric Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
633cfca06d7SDimitry Andric Asm->OutStreamer->emitLabel(ContributionEnd);
634eb11fae6SDimitry Andric }
635eb11fae6SDimitry Andric
emitAppleAccelTableImpl(AsmPrinter * Asm,AccelTableBase & Contents,StringRef Prefix,const MCSymbol * SecBegin,ArrayRef<AppleAccelTableData::Atom> Atoms)636eb11fae6SDimitry Andric void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
637eb11fae6SDimitry Andric StringRef Prefix, const MCSymbol *SecBegin,
638eb11fae6SDimitry Andric ArrayRef<AppleAccelTableData::Atom> Atoms) {
639eb11fae6SDimitry Andric Contents.finalize(Asm, Prefix);
640eb11fae6SDimitry Andric AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
641eb11fae6SDimitry Andric }
642eb11fae6SDimitry Andric
emitDWARF5AccelTable(AsmPrinter * Asm,DWARF5AccelTable & Contents,const DwarfDebug & DD,ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs)643eb11fae6SDimitry Andric void llvm::emitDWARF5AccelTable(
644b1c73532SDimitry Andric AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
645b1c73532SDimitry Andric ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
646b1c73532SDimitry Andric TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
647b1c73532SDimitry Andric std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
648b1c73532SDimitry Andric std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
649d8e91e46SDimitry Andric SmallVector<unsigned, 1> CUIndex(CUs.size());
650b1c73532SDimitry Andric DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
651b1c73532SDimitry Andric int CUCount = 0;
652b1c73532SDimitry Andric int TUCount = 0;
653eb11fae6SDimitry Andric for (const auto &CU : enumerate(CUs)) {
6547fa27ce4SDimitry Andric switch (CU.value()->getCUNode()->getNameTableKind()) {
6557fa27ce4SDimitry Andric case DICompileUnit::DebugNameTableKind::Default:
6567fa27ce4SDimitry Andric case DICompileUnit::DebugNameTableKind::Apple:
6577fa27ce4SDimitry Andric break;
6587fa27ce4SDimitry Andric default:
659d8e91e46SDimitry Andric continue;
6607fa27ce4SDimitry Andric }
661b1c73532SDimitry Andric CUIndex[CU.index()] = CUCount++;
662eb11fae6SDimitry Andric assert(CU.index() == CU.value()->getUniqueID());
663eb11fae6SDimitry Andric const DwarfCompileUnit *MainCU =
664eb11fae6SDimitry Andric DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
665eb11fae6SDimitry Andric CompUnits.push_back(MainCU->getLabelBegin());
666eb11fae6SDimitry Andric }
667eb11fae6SDimitry Andric
668b1c73532SDimitry Andric for (const auto &TU : TUSymbols) {
669b1c73532SDimitry Andric TUIndex[TU.UniqueID] = TUCount++;
670b1c73532SDimitry Andric if (DD.useSplitDwarf())
671b1c73532SDimitry Andric TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
672b1c73532SDimitry Andric else
673b1c73532SDimitry Andric TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
674b1c73532SDimitry Andric }
675b1c73532SDimitry Andric
676d8e91e46SDimitry Andric if (CompUnits.empty())
677d8e91e46SDimitry Andric return;
678d8e91e46SDimitry Andric
679145449b1SDimitry Andric Asm->OutStreamer->switchSection(
680d8e91e46SDimitry Andric Asm->getObjFileLowering().getDwarfDebugNamesSection());
681d8e91e46SDimitry Andric
682eb11fae6SDimitry Andric Contents.finalize(Asm, "names");
683b1c73532SDimitry Andric dwarf::Form CUIndexForm =
684b1c73532SDimitry Andric DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
685b1c73532SDimitry Andric dwarf::Form TUIndexForm =
686b1c73532SDimitry Andric DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
687aca2e42cSDimitry Andric Dwarf5AccelTableWriter(
688b1c73532SDimitry Andric Asm, Contents, CompUnits, TypeUnits,
689b1c73532SDimitry Andric [&](const DWARF5AccelTableData &Entry)
690b1c73532SDimitry Andric -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
691b1c73532SDimitry Andric if (Entry.isTU())
692b1c73532SDimitry Andric return {{TUIndex[Entry.getUnitID()],
693b1c73532SDimitry Andric {dwarf::DW_IDX_type_unit, TUIndexForm}}};
694b1c73532SDimitry Andric if (CUIndex.size() > 1)
695b1c73532SDimitry Andric return {{CUIndex[Entry.getUnitID()],
696b1c73532SDimitry Andric {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
697b1c73532SDimitry Andric return std::nullopt;
698b1c73532SDimitry Andric },
699b1c73532SDimitry Andric DD.useSplitDwarf())
700eb11fae6SDimitry Andric .emit();
701eb11fae6SDimitry Andric }
702eb11fae6SDimitry Andric
addTypeUnitSymbol(DwarfTypeUnit & U)703b1c73532SDimitry Andric void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
704b1c73532SDimitry Andric TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
705b1c73532SDimitry Andric }
706b1c73532SDimitry Andric
addTypeUnitSignature(DwarfTypeUnit & U)707b1c73532SDimitry Andric void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
708b1c73532SDimitry Andric TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
709b1c73532SDimitry Andric }
710b1c73532SDimitry Andric
emitDWARF5AccelTable(AsmPrinter * Asm,DWARF5AccelTable & Contents,ArrayRef<std::variant<MCSymbol *,uint64_t>> CUs,llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding> (const DWARF5AccelTableData &)> getIndexForEntry)711eb11fae6SDimitry Andric void llvm::emitDWARF5AccelTable(
712b1c73532SDimitry Andric AsmPrinter *Asm, DWARF5AccelTable &Contents,
713b1c73532SDimitry Andric ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
714b1c73532SDimitry Andric llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
715b1c73532SDimitry Andric const DWARF5AccelTableData &)>
716b1c73532SDimitry Andric getIndexForEntry) {
717b1c73532SDimitry Andric std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
718eb11fae6SDimitry Andric Contents.finalize(Asm, "names");
719aca2e42cSDimitry Andric Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
720eb11fae6SDimitry Andric .emit();
721eb11fae6SDimitry Andric }
722eb11fae6SDimitry Andric
emit(AsmPrinter * Asm) const723eb11fae6SDimitry Andric void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
724b60736ecSDimitry Andric assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
725b60736ecSDimitry Andric "The section offset exceeds the limit.");
726eb11fae6SDimitry Andric Asm->emitInt32(Die.getDebugSectionOffset());
727eb11fae6SDimitry Andric }
728eb11fae6SDimitry Andric
emit(AsmPrinter * Asm) const729eb11fae6SDimitry Andric void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
730b60736ecSDimitry Andric assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
731b60736ecSDimitry Andric "The section offset exceeds the limit.");
732eb11fae6SDimitry Andric Asm->emitInt32(Die.getDebugSectionOffset());
733eb11fae6SDimitry Andric Asm->emitInt16(Die.getTag());
734eb11fae6SDimitry Andric Asm->emitInt8(0);
735eb11fae6SDimitry Andric }
736eb11fae6SDimitry Andric
emit(AsmPrinter * Asm) const737eb11fae6SDimitry Andric void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
738eb11fae6SDimitry Andric Asm->emitInt32(Offset);
739eb11fae6SDimitry Andric }
740eb11fae6SDimitry Andric
emit(AsmPrinter * Asm) const741eb11fae6SDimitry Andric void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
742eb11fae6SDimitry Andric Asm->emitInt32(Offset);
743eb11fae6SDimitry Andric Asm->emitInt16(Tag);
744eb11fae6SDimitry Andric Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
745eb11fae6SDimitry Andric : 0);
746eb11fae6SDimitry Andric Asm->emitInt32(QualifiedNameHash);
747eb11fae6SDimitry Andric }
748eb11fae6SDimitry Andric
749eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
750eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
751eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
752eb11fae6SDimitry Andric constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
753eb11fae6SDimitry Andric
754eb11fae6SDimitry Andric #ifndef NDEBUG
print(raw_ostream & OS) const755eb11fae6SDimitry Andric void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
756eb11fae6SDimitry Andric OS << "Magic: " << format("0x%x", Magic) << "\n"
757eb11fae6SDimitry Andric << "Version: " << Version << "\n"
758eb11fae6SDimitry Andric << "Hash Function: " << HashFunction << "\n"
759eb11fae6SDimitry Andric << "Bucket Count: " << BucketCount << "\n"
760eb11fae6SDimitry Andric << "Header Data Length: " << HeaderDataLength << "\n";
761eb11fae6SDimitry Andric }
762eb11fae6SDimitry Andric
print(raw_ostream & OS) const763eb11fae6SDimitry Andric void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
764eb11fae6SDimitry Andric OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
765eb11fae6SDimitry Andric << "Form: " << dwarf::FormEncodingString(Form) << "\n";
766eb11fae6SDimitry Andric }
767eb11fae6SDimitry Andric
print(raw_ostream & OS) const768eb11fae6SDimitry Andric void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
769eb11fae6SDimitry Andric OS << "DIE Offset Base: " << DieOffsetBase << "\n";
770eb11fae6SDimitry Andric for (auto Atom : Atoms)
771eb11fae6SDimitry Andric Atom.print(OS);
772eb11fae6SDimitry Andric }
773eb11fae6SDimitry Andric
print(raw_ostream & OS) const774eb11fae6SDimitry Andric void AppleAccelTableWriter::print(raw_ostream &OS) const {
775eb11fae6SDimitry Andric Header.print(OS);
776eb11fae6SDimitry Andric HeaderData.print(OS);
777eb11fae6SDimitry Andric Contents.print(OS);
778eb11fae6SDimitry Andric SecBegin->print(OS, nullptr);
779eb11fae6SDimitry Andric }
780eb11fae6SDimitry Andric
print(raw_ostream & OS) const781eb11fae6SDimitry Andric void AccelTableBase::HashData::print(raw_ostream &OS) const {
782eb11fae6SDimitry Andric OS << "Name: " << Name.getString() << "\n";
783eb11fae6SDimitry Andric OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
784eb11fae6SDimitry Andric OS << " Symbol: ";
785eb11fae6SDimitry Andric if (Sym)
786eb11fae6SDimitry Andric OS << *Sym;
787eb11fae6SDimitry Andric else
788eb11fae6SDimitry Andric OS << "<none>";
789eb11fae6SDimitry Andric OS << "\n";
790eb11fae6SDimitry Andric for (auto *Value : Values)
791eb11fae6SDimitry Andric Value->print(OS);
792eb11fae6SDimitry Andric }
793eb11fae6SDimitry Andric
print(raw_ostream & OS) const794eb11fae6SDimitry Andric void AccelTableBase::print(raw_ostream &OS) const {
795eb11fae6SDimitry Andric // Print Content.
796eb11fae6SDimitry Andric OS << "Entries: \n";
7977fa27ce4SDimitry Andric for (const auto &[Name, Data] : Entries) {
7987fa27ce4SDimitry Andric OS << "Name: " << Name << "\n";
7997fa27ce4SDimitry Andric for (auto *V : Data.Values)
800eb11fae6SDimitry Andric V->print(OS);
801eb11fae6SDimitry Andric }
802eb11fae6SDimitry Andric
803eb11fae6SDimitry Andric OS << "Buckets and Hashes: \n";
8044b4fe385SDimitry Andric for (const auto &Bucket : Buckets)
8054b4fe385SDimitry Andric for (const auto &Hash : Bucket)
806eb11fae6SDimitry Andric Hash->print(OS);
807eb11fae6SDimitry Andric
808eb11fae6SDimitry Andric OS << "Data: \n";
8094b4fe385SDimitry Andric for (const auto &E : Entries)
810eb11fae6SDimitry Andric E.second.print(OS);
811eb11fae6SDimitry Andric }
812eb11fae6SDimitry Andric
print(raw_ostream & OS) const813eb11fae6SDimitry Andric void DWARF5AccelTableData::print(raw_ostream &OS) const {
814eb11fae6SDimitry Andric OS << " Offset: " << getDieOffset() << "\n";
815eb11fae6SDimitry Andric OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
816eb11fae6SDimitry Andric }
817eb11fae6SDimitry Andric
print(raw_ostream & OS) const818eb11fae6SDimitry Andric void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
819eb11fae6SDimitry Andric OS << " Offset: " << Die.getOffset() << "\n";
820eb11fae6SDimitry Andric }
821eb11fae6SDimitry Andric
print(raw_ostream & OS) const822eb11fae6SDimitry Andric void AppleAccelTableTypeData::print(raw_ostream &OS) const {
823eb11fae6SDimitry Andric OS << " Offset: " << Die.getOffset() << "\n";
824eb11fae6SDimitry Andric OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
825eb11fae6SDimitry Andric }
826eb11fae6SDimitry Andric
print(raw_ostream & OS) const827eb11fae6SDimitry Andric void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
828eb11fae6SDimitry Andric OS << " Static Offset: " << Offset << "\n";
829eb11fae6SDimitry Andric }
830eb11fae6SDimitry Andric
print(raw_ostream & OS) const831eb11fae6SDimitry Andric void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
832eb11fae6SDimitry Andric OS << " Static Offset: " << Offset << "\n";
833eb11fae6SDimitry Andric OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
834eb11fae6SDimitry Andric OS << " Tag: " << dwarf::TagString(Tag) << "\n";
835eb11fae6SDimitry Andric OS << " ObjCClassIsImplementation: "
836eb11fae6SDimitry Andric << (ObjCClassIsImplementation ? "true" : "false");
837eb11fae6SDimitry Andric OS << "\n";
838eb11fae6SDimitry Andric }
839eb11fae6SDimitry Andric #endif
840