[RISCV] Fix mgather -> riscv.masked.strided.load combine not extending indices (...
[llvm-project.git] / llvm / lib / CodeGen / AsmPrinter / AccelTable.cpp
blob1024aabf2ab0f6786ff263f60c7abbb0cecd3778
1 //===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains support for writing accelerator tables.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/CodeGen/AccelTable.h"
14 #include "DwarfCompileUnit.h"
15 #include "DwarfUnit.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/BinaryFormat/Dwarf.h"
20 #include "llvm/CodeGen/AsmPrinter.h"
21 #include "llvm/CodeGen/DIE.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/MCSymbol.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include "llvm/Target/TargetLoweringObjectFile.h"
26 #include <algorithm>
27 #include <cstddef>
28 #include <cstdint>
29 #include <limits>
30 #include <vector>
32 using namespace llvm;
34 void AccelTableBase::computeBucketCount() {
35 // First get the number of unique hashes.
36 std::vector<uint32_t> Uniques;
37 Uniques.reserve(Entries.size());
38 for (const auto &E : Entries)
39 Uniques.push_back(E.second.HashValue);
40 array_pod_sort(Uniques.begin(), Uniques.end());
41 std::vector<uint32_t>::iterator P =
42 std::unique(Uniques.begin(), Uniques.end());
44 UniqueHashCount = std::distance(Uniques.begin(), P);
46 if (UniqueHashCount > 1024)
47 BucketCount = UniqueHashCount / 4;
48 else if (UniqueHashCount > 16)
49 BucketCount = UniqueHashCount / 2;
50 else
51 BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
54 void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
55 // Create the individual hash data outputs.
56 for (auto &E : Entries) {
57 // Unique the entries.
58 llvm::stable_sort(E.second.Values,
59 [](const AccelTableData *A, const AccelTableData *B) {
60 return *A < *B;
61 });
62 E.second.Values.erase(
63 std::unique(E.second.Values.begin(), E.second.Values.end()),
64 E.second.Values.end());
67 // Figure out how many buckets we need, then compute the bucket contents and
68 // the final ordering. The hashes and offsets can be emitted by walking these
69 // data structures. We add temporary symbols to the data so they can be
70 // referenced when emitting the offsets.
71 computeBucketCount();
73 // Compute bucket contents and final ordering.
74 Buckets.resize(BucketCount);
75 for (auto &E : Entries) {
76 uint32_t Bucket = E.second.HashValue % BucketCount;
77 Buckets[Bucket].push_back(&E.second);
78 E.second.Sym = Asm->createTempSymbol(Prefix);
81 // Sort the contents of the buckets by hash value so that hash collisions end
82 // up together. Stable sort makes testing easier and doesn't cost much more.
83 for (auto &Bucket : Buckets)
84 llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
85 return LHS->HashValue < RHS->HashValue;
86 });
89 namespace {
90 /// Base class for writing out Accelerator tables. It holds the common
91 /// functionality for the two Accelerator table types.
92 class AccelTableWriter {
93 protected:
94 AsmPrinter *const Asm; ///< Destination.
95 const AccelTableBase &Contents; ///< Data to emit.
97 /// Controls whether to emit duplicate hash and offset table entries for names
98 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
99 /// tables do.
100 const bool SkipIdenticalHashes;
102 void emitHashes() const;
104 /// Emit offsets to lists of entries with identical names. The offsets are
105 /// relative to the Base argument.
106 void emitOffsets(const MCSymbol *Base) const;
108 public:
109 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
110 bool SkipIdenticalHashes)
111 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
115 class AppleAccelTableWriter : public AccelTableWriter {
116 using Atom = AppleAccelTableData::Atom;
118 /// The fixed header of an Apple Accelerator Table.
119 struct Header {
120 uint32_t Magic = MagicHash;
121 uint16_t Version = 1;
122 uint16_t HashFunction = dwarf::DW_hash_function_djb;
123 uint32_t BucketCount;
124 uint32_t HashCount;
125 uint32_t HeaderDataLength;
127 /// 'HASH' magic value to detect endianness.
128 static const uint32_t MagicHash = 0x48415348;
130 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
131 : BucketCount(BucketCount), HashCount(UniqueHashCount),
132 HeaderDataLength(DataLength) {}
134 void emit(AsmPrinter *Asm) const;
135 #ifndef NDEBUG
136 void print(raw_ostream &OS) const;
137 void dump() const { print(dbgs()); }
138 #endif
141 /// The HeaderData describes the structure of an Apple accelerator table
142 /// through a list of Atoms.
143 struct HeaderData {
144 /// In the case of data that is referenced via DW_FORM_ref_* the offset
145 /// base is used to describe the offset for all forms in the list of atoms.
146 uint32_t DieOffsetBase;
148 const SmallVector<Atom, 4> Atoms;
150 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
151 : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
153 void emit(AsmPrinter *Asm) const;
154 #ifndef NDEBUG
155 void print(raw_ostream &OS) const;
156 void dump() const { print(dbgs()); }
157 #endif
160 Header Header;
161 HeaderData HeaderData;
162 const MCSymbol *SecBegin;
164 void emitBuckets() const;
165 void emitData() const;
167 public:
168 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
169 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
170 : AccelTableWriter(Asm, Contents, true),
171 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
172 8 + (Atoms.size() * 4)),
173 HeaderData(Atoms), SecBegin(SecBegin) {}
175 void emit() const;
177 #ifndef NDEBUG
178 void print(raw_ostream &OS) const;
179 void dump() const { print(dbgs()); }
180 #endif
183 /// Class responsible for emitting a DWARF v5 Accelerator Table. The only
184 /// public function is emit(), which performs the actual emission.
186 /// A callback abstracts the logic to provide a CU index for a given entry.
187 class Dwarf5AccelTableWriter : public AccelTableWriter {
188 struct Header {
189 uint16_t Version = 5;
190 uint16_t Padding = 0;
191 uint32_t CompUnitCount;
192 uint32_t LocalTypeUnitCount = 0;
193 uint32_t ForeignTypeUnitCount = 0;
194 uint32_t BucketCount = 0;
195 uint32_t NameCount = 0;
196 uint32_t AbbrevTableSize = 0;
197 uint32_t AugmentationStringSize = sizeof(AugmentationString);
198 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
200 Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
201 uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
202 uint32_t NameCount)
203 : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
204 ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
205 NameCount(NameCount) {}
207 void emit(Dwarf5AccelTableWriter &Ctx);
210 Header Header;
211 DenseMap<uint32_t, SmallVector<DWARF5AccelTableData::AttributeEncoding, 3>>
212 Abbreviations;
213 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits;
214 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits;
215 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
216 const DWARF5AccelTableData &)>
217 getIndexForEntry;
218 MCSymbol *ContributionEnd = nullptr;
219 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
220 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
221 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
222 // Indicates if this module is built with Split Dwarf enabled.
223 bool IsSplitDwarf = false;
224 /// Stores the DIE offsets which are indexed by this table.
225 DenseSet<OffsetAndUnitID> IndexedOffsets;
227 void populateAbbrevsMap();
229 void emitCUList() const;
230 void emitTUList() const;
231 void emitBuckets() const;
232 void emitStringOffsets() const;
233 void emitAbbrevs() const;
234 void emitEntry(
235 const DWARF5AccelTableData &Entry,
236 const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
237 DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) const;
238 void emitData();
240 public:
241 Dwarf5AccelTableWriter(
242 AsmPrinter *Asm, const AccelTableBase &Contents,
243 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
244 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
245 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
246 const DWARF5AccelTableData &)>
247 getIndexForEntry,
248 bool IsSplitDwarf);
250 void emit();
252 } // namespace
254 void AccelTableWriter::emitHashes() const {
255 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
256 unsigned BucketIdx = 0;
257 for (const auto &Bucket : Contents.getBuckets()) {
258 for (const auto &Hash : Bucket) {
259 uint32_t HashValue = Hash->HashValue;
260 if (SkipIdenticalHashes && PrevHash == HashValue)
261 continue;
262 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
263 Asm->emitInt32(HashValue);
264 PrevHash = HashValue;
266 BucketIdx++;
270 void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
271 const auto &Buckets = Contents.getBuckets();
272 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
273 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
274 for (auto *Hash : Buckets[i]) {
275 uint32_t HashValue = Hash->HashValue;
276 if (SkipIdenticalHashes && PrevHash == HashValue)
277 continue;
278 PrevHash = HashValue;
279 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
280 Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
285 void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
286 Asm->OutStreamer->AddComment("Header Magic");
287 Asm->emitInt32(Magic);
288 Asm->OutStreamer->AddComment("Header Version");
289 Asm->emitInt16(Version);
290 Asm->OutStreamer->AddComment("Header Hash Function");
291 Asm->emitInt16(HashFunction);
292 Asm->OutStreamer->AddComment("Header Bucket Count");
293 Asm->emitInt32(BucketCount);
294 Asm->OutStreamer->AddComment("Header Hash Count");
295 Asm->emitInt32(HashCount);
296 Asm->OutStreamer->AddComment("Header Data Length");
297 Asm->emitInt32(HeaderDataLength);
300 void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
301 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
302 Asm->emitInt32(DieOffsetBase);
303 Asm->OutStreamer->AddComment("HeaderData Atom Count");
304 Asm->emitInt32(Atoms.size());
306 for (const Atom &A : Atoms) {
307 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
308 Asm->emitInt16(A.Type);
309 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
310 Asm->emitInt16(A.Form);
314 void AppleAccelTableWriter::emitBuckets() const {
315 const auto &Buckets = Contents.getBuckets();
316 unsigned index = 0;
317 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
318 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
319 if (!Buckets[i].empty())
320 Asm->emitInt32(index);
321 else
322 Asm->emitInt32(std::numeric_limits<uint32_t>::max());
323 // Buckets point in the list of hashes, not to the data. Do not increment
324 // the index multiple times in case of hash collisions.
325 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
326 for (auto *HD : Buckets[i]) {
327 uint32_t HashValue = HD->HashValue;
328 if (PrevHash != HashValue)
329 ++index;
330 PrevHash = HashValue;
335 void AppleAccelTableWriter::emitData() const {
336 const auto &Buckets = Contents.getBuckets();
337 for (const AccelTableBase::HashList &Bucket : Buckets) {
338 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
339 for (const auto &Hash : Bucket) {
340 // Terminate the previous entry if there is no hash collision with the
341 // current one.
342 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
343 PrevHash != Hash->HashValue)
344 Asm->emitInt32(0);
345 // Remember to emit the label for our offset.
346 Asm->OutStreamer->emitLabel(Hash->Sym);
347 Asm->OutStreamer->AddComment(Hash->Name.getString());
348 Asm->emitDwarfStringOffset(Hash->Name);
349 Asm->OutStreamer->AddComment("Num DIEs");
350 Asm->emitInt32(Hash->Values.size());
351 for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
352 V->emit(Asm);
353 PrevHash = Hash->HashValue;
355 // Emit the final end marker for the bucket.
356 if (!Bucket.empty())
357 Asm->emitInt32(0);
361 void AppleAccelTableWriter::emit() const {
362 Header.emit(Asm);
363 HeaderData.emit(Asm);
364 emitBuckets();
365 emitHashes();
366 emitOffsets(SecBegin);
367 emitData();
370 DWARF5AccelTableData::DWARF5AccelTableData(const DIE &Die,
371 const uint32_t UnitID,
372 const bool IsTU)
373 : OffsetVal(&Die), DieTag(Die.getTag()), UnitID(UnitID), IsTU(IsTU) {}
375 void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
376 assert(CompUnitCount > 0 && "Index must have at least one CU.");
378 AsmPrinter *Asm = Ctx.Asm;
379 Ctx.ContributionEnd =
380 Asm->emitDwarfUnitLength("names", "Header: unit length");
381 Asm->OutStreamer->AddComment("Header: version");
382 Asm->emitInt16(Version);
383 Asm->OutStreamer->AddComment("Header: padding");
384 Asm->emitInt16(Padding);
385 Asm->OutStreamer->AddComment("Header: compilation unit count");
386 Asm->emitInt32(CompUnitCount);
387 Asm->OutStreamer->AddComment("Header: local type unit count");
388 Asm->emitInt32(LocalTypeUnitCount);
389 Asm->OutStreamer->AddComment("Header: foreign type unit count");
390 Asm->emitInt32(ForeignTypeUnitCount);
391 Asm->OutStreamer->AddComment("Header: bucket count");
392 Asm->emitInt32(BucketCount);
393 Asm->OutStreamer->AddComment("Header: name count");
394 Asm->emitInt32(NameCount);
395 Asm->OutStreamer->AddComment("Header: abbreviation table size");
396 Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
397 Asm->OutStreamer->AddComment("Header: augmentation string size");
398 assert(AugmentationStringSize % 4 == 0);
399 Asm->emitInt32(AugmentationStringSize);
400 Asm->OutStreamer->AddComment("Header: augmentation string");
401 Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
404 std::optional<uint64_t>
405 DWARF5AccelTableData::getDefiningParentDieOffset(const DIE &Die) {
406 if (auto *Parent = Die.getParent();
407 Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
408 return Parent->getOffset();
409 return {};
412 enum IdxParentEncoding : uint8_t {
413 NoIndexedParent = 0, /// Parent information present but parent isn't indexed.
414 Ref4 = 1, /// Parent information present and parent is indexed.
415 NoParent = 2, /// Parent information missing.
418 static uint32_t constexpr NumBitsIdxParent = 2;
420 uint8_t encodeIdxParent(const std::optional<dwarf::Form> MaybeParentForm) {
421 if (!MaybeParentForm)
422 return NoParent;
423 switch (*MaybeParentForm) {
424 case dwarf::Form::DW_FORM_flag_present:
425 return NoIndexedParent;
426 case dwarf::Form::DW_FORM_ref4:
427 return Ref4;
428 default:
429 // This is not crashing on bad input: we should only reach this if the
430 // internal compiler logic is faulty; see getFormForIdxParent.
431 llvm_unreachable("Bad form for IDX_parent");
435 static uint32_t constexpr ParentBitOffset = dwarf::DW_IDX_type_hash;
436 static uint32_t constexpr TagBitOffset = ParentBitOffset + NumBitsIdxParent;
437 static uint32_t getTagFromAbbreviationTag(const uint32_t AbbrvTag) {
438 return AbbrvTag >> TagBitOffset;
441 /// Constructs a unique AbbrevTag that captures what a DIE accesses.
442 /// Using this tag we can emit a unique abbreviation for each DIE.
443 static uint32_t constructAbbreviationTag(
444 const unsigned Tag,
445 const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> &EntryRet,
446 std::optional<dwarf::Form> MaybeParentForm) {
447 uint32_t AbbrvTag = 0;
448 if (EntryRet)
449 AbbrvTag |= 1 << EntryRet->Encoding.Index;
450 AbbrvTag |= 1 << dwarf::DW_IDX_die_offset;
451 AbbrvTag |= 1 << dwarf::DW_IDX_parent;
452 AbbrvTag |= encodeIdxParent(MaybeParentForm) << ParentBitOffset;
453 AbbrvTag |= Tag << TagBitOffset;
454 return AbbrvTag;
457 static std::optional<dwarf::Form>
458 getFormForIdxParent(const DenseSet<OffsetAndUnitID> &IndexedOffsets,
459 std::optional<OffsetAndUnitID> ParentOffset) {
460 // No parent information
461 if (!ParentOffset)
462 return std::nullopt;
463 // Parent is indexed by this table.
464 if (IndexedOffsets.contains(*ParentOffset))
465 return dwarf::Form::DW_FORM_ref4;
466 // Parent is not indexed by this table.
467 return dwarf::Form::DW_FORM_flag_present;
470 void Dwarf5AccelTableWriter::populateAbbrevsMap() {
471 for (auto &Bucket : Contents.getBuckets()) {
472 for (auto *Hash : Bucket) {
473 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
474 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
475 getIndexForEntry(*Value);
476 unsigned Tag = Value->getDieTag();
477 std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
478 IndexedOffsets, Value->getParentDieOffsetAndUnitID());
479 uint32_t AbbrvTag =
480 constructAbbreviationTag(Tag, EntryRet, MaybeParentForm);
481 if (Abbreviations.count(AbbrvTag) == 0) {
482 SmallVector<DWARF5AccelTableData::AttributeEncoding, 3> UA;
483 if (EntryRet)
484 UA.push_back(EntryRet->Encoding);
485 UA.push_back({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
486 if (MaybeParentForm)
487 UA.push_back({dwarf::DW_IDX_parent, *MaybeParentForm});
488 Abbreviations.try_emplace(AbbrvTag, UA);
495 void Dwarf5AccelTableWriter::emitCUList() const {
496 for (const auto &CU : enumerate(CompUnits)) {
497 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
498 if (std::holds_alternative<MCSymbol *>(CU.value()))
499 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
500 else
501 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
505 void Dwarf5AccelTableWriter::emitTUList() const {
506 for (const auto &TU : enumerate(TypeUnits)) {
507 Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
508 if (std::holds_alternative<MCSymbol *>(TU.value()))
509 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
510 else if (IsSplitDwarf)
511 Asm->emitInt64(std::get<uint64_t>(TU.value()));
512 else
513 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
517 void Dwarf5AccelTableWriter::emitBuckets() const {
518 uint32_t Index = 1;
519 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
520 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
521 Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
522 Index += Bucket.value().size();
526 void Dwarf5AccelTableWriter::emitStringOffsets() const {
527 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
528 for (auto *Hash : Bucket.value()) {
529 DwarfStringPoolEntryRef String = Hash->Name;
530 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
531 ": " + String.getString());
532 Asm->emitDwarfStringOffset(String);
537 void Dwarf5AccelTableWriter::emitAbbrevs() const {
538 Asm->OutStreamer->emitLabel(AbbrevStart);
539 for (const auto &Abbrev : Abbreviations) {
540 Asm->OutStreamer->AddComment("Abbrev code");
541 uint32_t Tag = getTagFromAbbreviationTag(Abbrev.first);
542 assert(Tag != 0);
543 Asm->emitULEB128(Abbrev.first);
544 Asm->OutStreamer->AddComment(dwarf::TagString(Tag));
545 Asm->emitULEB128(Tag);
546 for (const auto &AttrEnc : Abbrev.second) {
547 Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
548 Asm->emitULEB128(AttrEnc.Form,
549 dwarf::FormEncodingString(AttrEnc.Form).data());
551 Asm->emitULEB128(0, "End of abbrev");
552 Asm->emitULEB128(0, "End of abbrev");
554 Asm->emitULEB128(0, "End of abbrev list");
555 Asm->OutStreamer->emitLabel(AbbrevEnd);
558 void Dwarf5AccelTableWriter::emitEntry(
559 const DWARF5AccelTableData &Entry,
560 const DenseMap<OffsetAndUnitID, MCSymbol *> &DIEOffsetToAccelEntryLabel,
561 DenseSet<MCSymbol *> &EmittedAccelEntrySymbols) const {
562 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
563 getIndexForEntry(Entry);
564 std::optional<OffsetAndUnitID> MaybeParentOffset =
565 Entry.getParentDieOffsetAndUnitID();
566 std::optional<dwarf::Form> MaybeParentForm =
567 getFormForIdxParent(IndexedOffsets, MaybeParentOffset);
568 uint32_t AbbrvTag =
569 constructAbbreviationTag(Entry.getDieTag(), EntryRet, MaybeParentForm);
570 auto AbbrevIt = Abbreviations.find(AbbrvTag);
571 assert(AbbrevIt != Abbreviations.end() &&
572 "Why wasn't this abbrev generated?");
573 assert(getTagFromAbbreviationTag(AbbrevIt->first) == Entry.getDieTag() &&
574 "Invalid Tag");
576 auto EntrySymbolIt =
577 DIEOffsetToAccelEntryLabel.find(Entry.getDieOffsetAndUnitID());
578 assert(EntrySymbolIt != DIEOffsetToAccelEntryLabel.end());
579 MCSymbol *EntrySymbol = EntrySymbolIt->getSecond();
581 // Emit the label for this Entry, so that IDX_parents may refer to it.
582 // Note: a DIE may have multiple accelerator Entries; this check avoids
583 // creating/emitting multiple labels for the same DIE.
584 if (EmittedAccelEntrySymbols.insert(EntrySymbol).second)
585 Asm->OutStreamer->emitLabel(EntrySymbol);
587 Asm->emitULEB128(AbbrevIt->first, "Abbreviation code");
589 for (const auto &AttrEnc : AbbrevIt->second) {
590 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
591 switch (AttrEnc.Index) {
592 case dwarf::DW_IDX_compile_unit:
593 case dwarf::DW_IDX_type_unit: {
594 DIEInteger ID(EntryRet->Index);
595 ID.emitValue(Asm, AttrEnc.Form);
596 break;
598 case dwarf::DW_IDX_die_offset:
599 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
600 Asm->emitInt32(Entry.getDieOffset());
601 break;
602 case dwarf::DW_IDX_parent: {
603 if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
604 break;
605 auto ParentSymbolIt = DIEOffsetToAccelEntryLabel.find(*MaybeParentOffset);
606 assert(ParentSymbolIt != DIEOffsetToAccelEntryLabel.end());
607 Asm->emitLabelDifference(ParentSymbolIt->getSecond(), EntryPool, 4);
608 break;
610 default:
611 llvm_unreachable("Unexpected index attribute!");
616 void Dwarf5AccelTableWriter::emitData() {
617 DenseMap<OffsetAndUnitID, MCSymbol *> DIEOffsetToAccelEntryLabel;
619 for (OffsetAndUnitID Offset : IndexedOffsets)
620 DIEOffsetToAccelEntryLabel.insert({Offset, Asm->createTempSymbol("")});
622 Asm->OutStreamer->emitLabel(EntryPool);
623 DenseSet<MCSymbol *> EmittedAccelEntrySymbols;
624 for (auto &Bucket : Contents.getBuckets()) {
625 for (auto *Hash : Bucket) {
626 // Remember to emit the label for our offset.
627 Asm->OutStreamer->emitLabel(Hash->Sym);
628 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
629 emitEntry(*Value, DIEOffsetToAccelEntryLabel, EmittedAccelEntrySymbols);
630 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
631 Asm->emitInt8(0);
636 Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
637 AsmPrinter *Asm, const AccelTableBase &Contents,
638 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
639 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
640 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
641 const DWARF5AccelTableData &)>
642 getIndexForEntry,
643 bool IsSplitDwarf)
644 : AccelTableWriter(Asm, Contents, false),
645 Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
646 IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
647 Contents.getUniqueNameCount()),
648 CompUnits(CompUnits), TypeUnits(TypeUnits),
649 getIndexForEntry(std::move(getIndexForEntry)),
650 IsSplitDwarf(IsSplitDwarf) {
652 for (auto &Bucket : Contents.getBuckets())
653 for (auto *Hash : Bucket)
654 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
655 IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
657 populateAbbrevsMap();
660 void Dwarf5AccelTableWriter::emit() {
661 Header.emit(*this);
662 emitCUList();
663 emitTUList();
664 emitBuckets();
665 emitHashes();
666 emitStringOffsets();
667 emitOffsets(EntryPool);
668 emitAbbrevs();
669 emitData();
670 Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
671 Asm->OutStreamer->emitLabel(ContributionEnd);
674 void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
675 StringRef Prefix, const MCSymbol *SecBegin,
676 ArrayRef<AppleAccelTableData::Atom> Atoms) {
677 Contents.finalize(Asm, Prefix);
678 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
681 void llvm::emitDWARF5AccelTable(
682 AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
683 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
684 TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
685 std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
686 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
687 SmallVector<unsigned, 1> CUIndex(CUs.size());
688 DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
689 int CUCount = 0;
690 int TUCount = 0;
691 for (const auto &CU : enumerate(CUs)) {
692 switch (CU.value()->getCUNode()->getNameTableKind()) {
693 case DICompileUnit::DebugNameTableKind::Default:
694 case DICompileUnit::DebugNameTableKind::Apple:
695 break;
696 default:
697 continue;
699 CUIndex[CU.index()] = CUCount++;
700 assert(CU.index() == CU.value()->getUniqueID());
701 const DwarfCompileUnit *MainCU =
702 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
703 CompUnits.push_back(MainCU->getLabelBegin());
706 for (const auto &TU : TUSymbols) {
707 TUIndex[TU.UniqueID] = TUCount++;
708 if (DD.useSplitDwarf())
709 TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
710 else
711 TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
714 if (CompUnits.empty())
715 return;
717 Asm->OutStreamer->switchSection(
718 Asm->getObjFileLowering().getDwarfDebugNamesSection());
720 Contents.finalize(Asm, "names");
721 dwarf::Form CUIndexForm =
722 DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
723 dwarf::Form TUIndexForm =
724 DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
725 Dwarf5AccelTableWriter(
726 Asm, Contents, CompUnits, TypeUnits,
727 [&](const DWARF5AccelTableData &Entry)
728 -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
729 if (Entry.isTU())
730 return {{TUIndex[Entry.getUnitID()],
731 {dwarf::DW_IDX_type_unit, TUIndexForm}}};
732 if (CUIndex.size() > 1)
733 return {{CUIndex[Entry.getUnitID()],
734 {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
735 return std::nullopt;
737 DD.useSplitDwarf())
738 .emit();
741 void DWARF5AccelTable::addTypeUnitSymbol(DwarfTypeUnit &U) {
742 TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
745 void DWARF5AccelTable::addTypeUnitSignature(DwarfTypeUnit &U) {
746 TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
749 void llvm::emitDWARF5AccelTable(
750 AsmPrinter *Asm, DWARF5AccelTable &Contents,
751 ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
752 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
753 const DWARF5AccelTableData &)>
754 getIndexForEntry) {
755 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
756 Contents.finalize(Asm, "names");
757 Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
758 .emit();
761 void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
762 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
763 "The section offset exceeds the limit.");
764 Asm->emitInt32(Die.getDebugSectionOffset());
767 void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
768 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
769 "The section offset exceeds the limit.");
770 Asm->emitInt32(Die.getDebugSectionOffset());
771 Asm->emitInt16(Die.getTag());
772 Asm->emitInt8(0);
775 void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
776 Asm->emitInt32(Offset);
779 void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
780 Asm->emitInt32(Offset);
781 Asm->emitInt16(Tag);
782 Asm->emitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
783 : 0);
784 Asm->emitInt32(QualifiedNameHash);
787 constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
788 constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
789 constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
790 constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
792 #ifndef NDEBUG
793 void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
794 OS << "Magic: " << format("0x%x", Magic) << "\n"
795 << "Version: " << Version << "\n"
796 << "Hash Function: " << HashFunction << "\n"
797 << "Bucket Count: " << BucketCount << "\n"
798 << "Header Data Length: " << HeaderDataLength << "\n";
801 void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
802 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
803 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
806 void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
807 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
808 for (auto Atom : Atoms)
809 Atom.print(OS);
812 void AppleAccelTableWriter::print(raw_ostream &OS) const {
813 Header.print(OS);
814 HeaderData.print(OS);
815 Contents.print(OS);
816 SecBegin->print(OS, nullptr);
819 void AccelTableBase::HashData::print(raw_ostream &OS) const {
820 OS << "Name: " << Name.getString() << "\n";
821 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
822 OS << " Symbol: ";
823 if (Sym)
824 OS << *Sym;
825 else
826 OS << "<none>";
827 OS << "\n";
828 for (auto *Value : Values)
829 Value->print(OS);
832 void AccelTableBase::print(raw_ostream &OS) const {
833 // Print Content.
834 OS << "Entries: \n";
835 for (const auto &[Name, Data] : Entries) {
836 OS << "Name: " << Name << "\n";
837 for (auto *V : Data.Values)
838 V->print(OS);
841 OS << "Buckets and Hashes: \n";
842 for (const auto &Bucket : Buckets)
843 for (const auto &Hash : Bucket)
844 Hash->print(OS);
846 OS << "Data: \n";
847 for (const auto &E : Entries)
848 E.second.print(OS);
851 void DWARF5AccelTableData::print(raw_ostream &OS) const {
852 OS << " Offset: " << getDieOffset() << "\n";
853 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
856 void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
857 OS << " Offset: " << Die.getOffset() << "\n";
860 void AppleAccelTableTypeData::print(raw_ostream &OS) const {
861 OS << " Offset: " << Die.getOffset() << "\n";
862 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
865 void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
866 OS << " Static Offset: " << Offset << "\n";
869 void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
870 OS << " Static Offset: " << Offset << "\n";
871 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
872 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
873 OS << " ObjCClassIsImplementation: "
874 << (ObjCClassIsImplementation ? "true" : "false");
875 OS << "\n";
877 #endif