LLVM 24.0.0git
AccelTable.cpp
Go to the documentation of this file.
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.
10//
11//===----------------------------------------------------------------------===//
12
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"
21#include "llvm/CodeGen/DIE.h"
22#include "llvm/MC/MCStreamer.h"
23#include "llvm/MC/MCSymbol.h"
24#include "llvm/Support/LEB128.h"
27#include <cstddef>
28#include <cstdint>
29#include <limits>
30#include <vector>
31
32using namespace llvm;
33
36 Uniques.reserve(Entries.size());
37 for (const auto &E : Entries)
38 Uniques.push_back(E.second.HashValue);
39 llvm::sort(Uniques);
40 UniqueHashCount = llvm::unique(Uniques) - Uniques.begin();
42}
43
45 // Create the individual hash data outputs.
46 for (auto &E : Entries) {
47 // Unique the entries.
48 llvm::stable_sort(E.second.Values,
49 [](const AccelTableData *A, const AccelTableData *B) {
50 return *A < *B;
51 });
52 E.second.Values.erase(llvm::unique(E.second.Values), E.second.Values.end());
53 }
54
55 // Figure out how many buckets we need, then compute the bucket contents and
56 // the final ordering. The hashes and offsets can be emitted by walking these
57 // data structures. We add temporary symbols to the data so they can be
58 // referenced when emitting the offsets.
60
61 // Compute bucket contents and final ordering.
62 Buckets.resize(BucketCount);
63 for (auto &E : Entries)
64 Buckets[E.second.HashValue % BucketCount].push_back(&E.second);
65
66 // Sort the contents of the buckets by hash value so that hash collisions end
67 // up together. Entries is keyed by name, so breaking ties by name yields a
68 // total order that does not depend on the order names were added in.
69 for (HashList &Bucket : Buckets)
70 llvm::sort(Bucket, [](const HashData *LHS, const HashData *RHS) {
71 if (LHS->HashValue != RHS->HashValue)
72 return LHS->HashValue < RHS->HashValue;
73 return LHS->Name.getString() < RHS->Name.getString();
74 });
75
76 // Create the labels in bucket order so that their numbering matches the
77 // order they are emitted in.
78 for (HashList &Bucket : Buckets)
79 for (HashData *Hash : Bucket)
80 Hash->Sym = Asm->createTempSymbol(Prefix);
81}
82
83namespace {
84/// Base class for writing out Accelerator tables. It holds the common
85/// functionality for the two Accelerator table types.
86class AccelTableWriter {
87protected:
88 AsmPrinter *const Asm; ///< Destination.
89 const AccelTableBase &Contents; ///< Data to emit.
90
91 /// Controls whether to emit duplicate hash and offset table entries for names
92 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
93 /// tables do.
94 const bool SkipIdenticalHashes;
95
96 void emitHashes() const;
97
98 /// Emit offsets to lists of entries with identical names. The offsets are
99 /// relative to the Base argument.
100 void emitOffsets(const MCSymbol *Base) const;
101
102public:
103 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
104 bool SkipIdenticalHashes)
105 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
106 }
107};
108
109class AppleAccelTableWriter : public AccelTableWriter {
110 using Atom = AppleAccelTableData::Atom;
111
112 /// The fixed header of an Apple Accelerator Table.
113 struct Header {
114 uint32_t Magic = MagicHash;
115 uint16_t Version = 1;
116 uint16_t HashFunction = dwarf::DW_hash_function_djb;
117 uint32_t BucketCount;
118 uint32_t HashCount;
119 uint32_t HeaderDataLength;
120
121 /// 'HASH' magic value to detect endianness.
122 static const uint32_t MagicHash = 0x48415348;
123
124 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
125 : BucketCount(BucketCount), HashCount(UniqueHashCount),
126 HeaderDataLength(DataLength) {}
127
128 void emit(AsmPrinter *Asm) const;
129#ifndef NDEBUG
130 void print(raw_ostream &OS) const;
131 void dump() const { print(dbgs()); }
132#endif
133 };
134
135 /// The HeaderData describes the structure of an Apple accelerator table
136 /// through a list of Atoms.
137 struct HeaderData {
138 /// In the case of data that is referenced via DW_FORM_ref_* the offset
139 /// base is used to describe the offset for all forms in the list of atoms.
140 uint32_t DieOffsetBase;
141
142 const SmallVector<Atom, 4> Atoms;
143
144 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
145 : DieOffsetBase(Offset), Atoms(AtomList) {}
146
147 void emit(AsmPrinter *Asm) const;
148#ifndef NDEBUG
149 void print(raw_ostream &OS) const;
150 void dump() const { print(dbgs()); }
151#endif
152 };
153
154 Header Header;
155 HeaderData HeaderData;
156 const MCSymbol *SecBegin;
157
158 void emitBuckets() const;
159 void emitData() const;
160
161public:
162 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
163 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
164 : AccelTableWriter(Asm, Contents, true),
165 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
166 8 + (Atoms.size() * 4)),
167 HeaderData(Atoms), SecBegin(SecBegin) {}
168
169 void emit() const;
170
171#ifndef NDEBUG
172 void print(raw_ostream &OS) const;
173 void dump() const { print(dbgs()); }
174#endif
175};
176
177/// Class responsible for emitting a DWARF v5 Accelerator Table. The only
178/// public function is emit(), which performs the actual emission.
179///
180/// A callback abstracts the logic to provide a CU index for a given entry.
181class Dwarf5AccelTableWriter : public AccelTableWriter {
182 struct Header {
183 uint16_t Version = 5;
184 uint16_t Padding = 0;
185 uint32_t CompUnitCount;
186 uint32_t LocalTypeUnitCount = 0;
187 uint32_t ForeignTypeUnitCount = 0;
188 uint32_t BucketCount = 0;
189 uint32_t NameCount = 0;
190 uint32_t AugmentationStringSize = sizeof(AugmentationString);
191 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
192
193 Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
194 uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
195 uint32_t NameCount)
196 : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
197 ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
198 NameCount(NameCount) {}
199
200 void emit(Dwarf5AccelTableWriter &Ctx);
201 };
202
203 Header Header;
204 /// FoldingSet that uniques the abbreviations.
205 FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
206 /// Vector containing DebugNames abbreviations for iteration in order.
207 SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
208 /// The bump allocator to use when creating DIEAbbrev objects in the uniqued
209 /// storage container.
213 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
214 const DWARF5AccelTableData &)>
215 getIndexForEntry;
216 MCSymbol *ContributionEnd = nullptr;
217 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
218 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
219 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
220 // Indicates if this module is built with Split Dwarf enabled.
221 bool IsSplitDwarf = false;
222 /// Stores the DIE offsets which are indexed by this table.
223 DenseSet<OffsetAndUnitID> IndexedOffsets;
224
225 void populateAbbrevsMap();
226
227 void emitCUList() const;
228 void emitTUList() const;
229 void emitBuckets() const;
230 void emitStringOffsets() const;
231 void emitAbbrevs() const;
232 void emitEntry(
233 const DWARF5AccelTableData &Entry,
234 const DenseMap<OffsetAndUnitID, uint64_t> &DIEOffsetToAccelEntryOffset);
235 uint64_t getEntrySize(const DWARF5AccelTableData &Entry) const;
236 void emitData();
237
238public:
239 Dwarf5AccelTableWriter(
240 AsmPrinter *Asm, const AccelTableBase &Contents,
241 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
242 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
243 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
244 const DWARF5AccelTableData &)>
245 getIndexForEntry,
246 bool IsSplitDwarf);
247 ~Dwarf5AccelTableWriter() {
248 for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
249 Abbrev->~DebugNamesAbbrev();
250 }
251 void emit();
252};
253} // namespace
254
255void AccelTableWriter::emitHashes() const {
256 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
257 unsigned BucketIdx = 0;
258 for (const auto &Bucket : Contents.getBuckets()) {
259 for (const auto &Hash : Bucket) {
260 uint32_t HashValue = Hash->HashValue;
261 if (SkipIdenticalHashes && PrevHash == HashValue)
262 continue;
263 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
264 Asm->emitInt32(HashValue);
265 PrevHash = HashValue;
266 }
267 BucketIdx++;
268 }
269}
270
271void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
272 const auto &Buckets = Contents.getBuckets();
273 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
274 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
275 for (auto *Hash : Buckets[i]) {
276 uint32_t HashValue = Hash->HashValue;
277 if (SkipIdenticalHashes && PrevHash == HashValue)
278 continue;
279 PrevHash = HashValue;
280 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
281 Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
282 }
283 }
284}
285
286void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
287 Asm->OutStreamer->AddComment("Header Magic");
288 Asm->emitInt32(Magic);
289 Asm->OutStreamer->AddComment("Header Version");
290 Asm->emitInt16(Version);
291 Asm->OutStreamer->AddComment("Header Hash Function");
292 Asm->emitInt16(HashFunction);
293 Asm->OutStreamer->AddComment("Header Bucket Count");
294 Asm->emitInt32(BucketCount);
295 Asm->OutStreamer->AddComment("Header Hash Count");
296 Asm->emitInt32(HashCount);
297 Asm->OutStreamer->AddComment("Header Data Length");
298 Asm->emitInt32(HeaderDataLength);
299}
300
301void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
302 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
303 Asm->emitInt32(DieOffsetBase);
304 Asm->OutStreamer->AddComment("HeaderData Atom Count");
305 Asm->emitInt32(Atoms.size());
306
307 for (const Atom &A : Atoms) {
308 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
309 Asm->emitInt16(A.Type);
310 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
311 Asm->emitInt16(A.Form);
312 }
313}
314
315void AppleAccelTableWriter::emitBuckets() const {
316 const auto &Buckets = Contents.getBuckets();
317 unsigned index = 0;
318 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
319 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
320 if (!Buckets[i].empty())
321 Asm->emitInt32(index);
322 else
323 Asm->emitInt32(std::numeric_limits<uint32_t>::max());
324 // Buckets point in the list of hashes, not to the data. Do not increment
325 // the index multiple times in case of hash collisions.
326 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
327 for (auto *HD : Buckets[i]) {
328 uint32_t HashValue = HD->HashValue;
329 if (PrevHash != HashValue)
330 ++index;
331 PrevHash = HashValue;
332 }
333 }
334}
335
336void AppleAccelTableWriter::emitData() const {
337 const auto &Buckets = Contents.getBuckets();
338 for (const AccelTableBase::HashList &Bucket : Buckets) {
339 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
340 for (const auto &Hash : Bucket) {
341 // Terminate the previous entry if there is no hash collision with the
342 // current one.
343 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
344 PrevHash != Hash->HashValue)
345 Asm->emitInt32(0);
346 // Remember to emit the label for our offset.
347 Asm->OutStreamer->emitLabel(Hash->Sym);
348 Asm->OutStreamer->AddComment(Hash->Name.getString());
349 Asm->emitDwarfStringOffset(Hash->Name);
350 Asm->OutStreamer->AddComment("Num DIEs");
351 Asm->emitInt32(Hash->Values.size());
352 for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
353 V->emit(Asm);
354 PrevHash = Hash->HashValue;
355 }
356 // Emit the final end marker for the bucket.
357 if (!Bucket.empty())
358 Asm->emitInt32(0);
359 }
360}
361
362void AppleAccelTableWriter::emit() const {
363 Header.emit(Asm);
364 HeaderData.emit(Asm);
365 emitBuckets();
366 emitHashes();
367 emitOffsets(SecBegin);
368 emitData();
369}
370
372 const uint32_t UnitID,
373 const bool IsTU)
374 : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
375 UnitID(UnitID) {}
376
377void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
378 assert(CompUnitCount > 0 && "Index must have at least one CU.");
379
380 AsmPrinter *Asm = Ctx.Asm;
381 Ctx.ContributionEnd =
382 Asm->emitDwarfUnitLength("names", "Header: unit length");
383 Asm->OutStreamer->AddComment("Header: version");
384 Asm->emitInt16(Version);
385 Asm->OutStreamer->AddComment("Header: padding");
386 Asm->emitInt16(Padding);
387 Asm->OutStreamer->AddComment("Header: compilation unit count");
388 Asm->emitInt32(CompUnitCount);
389 Asm->OutStreamer->AddComment("Header: local type unit count");
390 Asm->emitInt32(LocalTypeUnitCount);
391 Asm->OutStreamer->AddComment("Header: foreign type unit count");
392 Asm->emitInt32(ForeignTypeUnitCount);
393 Asm->OutStreamer->AddComment("Header: bucket count");
394 Asm->emitInt32(BucketCount);
395 Asm->OutStreamer->AddComment("Header: name count");
396 Asm->emitInt32(NameCount);
397 Asm->OutStreamer->AddComment("Header: abbreviation table size");
398 Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
399 Asm->OutStreamer->AddComment("Header: augmentation string size");
400 assert(AugmentationStringSize % 4 == 0);
401 Asm->emitInt32(AugmentationStringSize);
402 Asm->OutStreamer->AddComment("Header: augmentation string");
403 Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
404}
405
406std::optional<uint64_t>
408 if (auto *Parent = Die.getParent();
409 Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
410 return Parent->getOffset();
411 return {};
412}
413
414static std::optional<dwarf::Form>
416 std::optional<OffsetAndUnitID> ParentOffset) {
417 // No parent information
418 if (!ParentOffset)
419 return std::nullopt;
420 // Parent is indexed by this table.
421 if (IndexedOffsets.contains(*ParentOffset))
422 return dwarf::Form::DW_FORM_ref4;
423 // Parent is not indexed by this table.
424 return dwarf::Form::DW_FORM_flag_present;
425}
426
428 ID.AddInteger(DieTag);
429 for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
430 ID.AddInteger(Enc.Index);
431 ID.AddInteger(Enc.Form);
432 }
433}
434
435void Dwarf5AccelTableWriter::populateAbbrevsMap() {
436 for (auto &Bucket : Contents.getBuckets()) {
437 for (auto *Hash : Bucket) {
438 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
439 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
440 getIndexForEntry(*Value);
441 std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
442 IndexedOffsets, Value->getParentDieOffsetAndUnitID());
443 DebugNamesAbbrev Abbrev(Value->getDieTag());
444 if (EntryRet)
445 Abbrev.addAttribute(EntryRet->Encoding);
446 Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
447 if (MaybeParentForm)
448 Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
450 Abbrev.Profile(ID);
452 if (DebugNamesAbbrev *Existing = AbbreviationsSet.lookup(ID, Token)) {
453 Value->setAbbrevNumber(Existing->getNumber());
454 continue;
455 }
456 DebugNamesAbbrev *NewAbbrev =
457 new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
458 AbbreviationsVector.push_back(NewAbbrev);
459 NewAbbrev->setNumber(AbbreviationsVector.size());
460 AbbreviationsSet.insert(NewAbbrev, Token);
461 Value->setAbbrevNumber(NewAbbrev->getNumber());
462 }
463 }
464 }
465}
466
467void Dwarf5AccelTableWriter::emitCUList() const {
468 for (const auto &CU : enumerate(CompUnits)) {
469 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
470 if (std::holds_alternative<MCSymbol *>(CU.value()))
471 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
472 else
473 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
474 }
475}
476
477void Dwarf5AccelTableWriter::emitTUList() const {
478 for (const auto &TU : enumerate(TypeUnits)) {
479 Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
480 if (std::holds_alternative<MCSymbol *>(TU.value()))
481 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
482 else if (IsSplitDwarf)
483 Asm->emitInt64(std::get<uint64_t>(TU.value()));
484 else
485 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
486 }
487}
488
489void Dwarf5AccelTableWriter::emitBuckets() const {
490 uint32_t Index = 1;
491 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
492 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
493 Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
494 Index += Bucket.value().size();
495 }
496}
497
498void Dwarf5AccelTableWriter::emitStringOffsets() const {
499 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
500 for (auto *Hash : Bucket.value()) {
501 DwarfStringPoolEntryRef String = Hash->Name;
502 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
503 ": " + String.getString());
504 Asm->emitDwarfStringOffset(String);
505 }
506 }
507}
508
509void Dwarf5AccelTableWriter::emitAbbrevs() const {
510 Asm->OutStreamer->emitLabel(AbbrevStart);
511 for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
512 Asm->OutStreamer->AddComment("Abbrev code");
513 Asm->emitULEB128(Abbrev->getNumber());
514 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
515 Asm->emitULEB128(Abbrev->getDieTag());
516 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
517 Abbrev->getAttributes()) {
518 Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
519 Asm->emitULEB128(AttrEnc.Form,
520 dwarf::FormEncodingString(AttrEnc.Form).data());
521 }
522 Asm->emitULEB128(0, "End of abbrev");
523 Asm->emitULEB128(0, "End of abbrev");
524 }
525 Asm->emitULEB128(0, "End of abbrev list");
526 Asm->OutStreamer->emitLabel(AbbrevEnd);
527}
528
529void Dwarf5AccelTableWriter::emitEntry(
530 const DWARF5AccelTableData &Entry,
531 const DenseMap<OffsetAndUnitID, uint64_t> &DIEOffsetToAccelEntryOffset) {
532 unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
533 assert(AbbrevIndex < AbbreviationsVector.size() &&
534 "Entry abbrev index is outside of abbreviations vector range.");
535 DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
536 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
537 getIndexForEntry(Entry);
538 std::optional<OffsetAndUnitID> MaybeParentOffset =
539 Entry.getParentDieOffsetAndUnitID();
540
541 Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
542
543 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
544 Abbrev->getAttributes()) {
545 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
546 switch (AttrEnc.Index) {
547 case dwarf::DW_IDX_compile_unit:
548 case dwarf::DW_IDX_type_unit: {
549 DIEInteger ID(EntryRet->Index);
550 ID.emitValue(Asm, AttrEnc.Form);
551 break;
552 }
553 case dwarf::DW_IDX_die_offset:
554 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
555 Asm->emitInt32(Entry.getDieOffset());
556 break;
557 case dwarf::DW_IDX_parent: {
558 if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
559 break;
560 auto It = DIEOffsetToAccelEntryOffset.find(*MaybeParentOffset);
561 assert(It != DIEOffsetToAccelEntryOffset.end());
562 Asm->emitInt32(It->second);
563 break;
564 }
565 default:
566 llvm_unreachable("Unexpected index attribute!");
567 }
568 }
569}
570
572Dwarf5AccelTableWriter::getEntrySize(const DWARF5AccelTableData &Entry) const {
573 unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
574 assert(AbbrevIndex < AbbreviationsVector.size());
575 DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
576 uint64_t Size = getULEB128Size(Entry.getAbbrevNumber());
577 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
578 getIndexForEntry(Entry);
579 for (const auto &AttrEnc : Abbrev->getAttributes()) {
580 switch (AttrEnc.Index) {
581 case dwarf::DW_IDX_compile_unit:
582 case dwarf::DW_IDX_type_unit:
583 Size += DIEInteger(EntryRet->Index)
584 .sizeOf(Asm->getDwarfFormParams(), AttrEnc.Form);
585 break;
586 case dwarf::DW_IDX_die_offset:
587 Size += 4;
588 break;
589 case dwarf::DW_IDX_parent:
590 if (AttrEnc.Form != dwarf::Form::DW_FORM_flag_present)
591 Size += 4;
592 break;
593 default:
594 llvm_unreachable("Unexpected index attribute!");
595 }
596 }
597 return Size;
598}
599
600void Dwarf5AccelTableWriter::emitData() {
601 // Pre-compute entry pool offsets for DW_IDX_parent references.
602 DenseMap<OffsetAndUnitID, uint64_t> DIEOffsetToAccelEntryOffset;
603 uint64_t Offset = 0;
604 for (auto &Bucket : Contents.getBuckets()) {
605 for (auto *Hash : Bucket) {
606 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
607 DIEOffsetToAccelEntryOffset.try_emplace(Value->getDieOffsetAndUnitID(),
608 Offset);
609 Offset += getEntrySize(*Value);
610 }
611 Offset += 1; // End of list
612 }
613 }
614
615 Asm->OutStreamer->emitLabel(EntryPool);
616 for (auto &Bucket : Contents.getBuckets()) {
617 for (auto *Hash : Bucket) {
618 // Remember to emit the label for our offset.
619 Asm->OutStreamer->emitLabel(Hash->Sym);
620 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
621 emitEntry(*Value, DIEOffsetToAccelEntryOffset);
622 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
623 Asm->emitInt8(0);
624 }
625 }
626}
627
628Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
629 AsmPrinter *Asm, const AccelTableBase &Contents,
630 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
631 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
632 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
633 const DWARF5AccelTableData &)>
634 getIndexForEntry,
635 bool IsSplitDwarf)
636 : AccelTableWriter(Asm, Contents, false),
637 Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
638 IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
639 Contents.getUniqueNameCount()),
640 CompUnits(CompUnits), TypeUnits(TypeUnits),
641 getIndexForEntry(std::move(getIndexForEntry)),
642 IsSplitDwarf(IsSplitDwarf) {
643
644 for (auto &Bucket : Contents.getBuckets())
645 for (auto *Hash : Bucket)
646 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
647 IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
648
649 populateAbbrevsMap();
650}
651
652void Dwarf5AccelTableWriter::emit() {
653 Header.emit(*this);
654 emitCUList();
655 emitTUList();
656 emitBuckets();
657 emitHashes();
658 emitStringOffsets();
659 emitOffsets(EntryPool);
660 emitAbbrevs();
661 emitData();
662 Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
663 Asm->OutStreamer->emitLabel(ContributionEnd);
664}
665
667 StringRef Prefix, const MCSymbol *SecBegin,
669 Contents.finalize(Asm, Prefix);
670 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
671}
672
674 AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
675 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
676 TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
677 std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
678 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
679 SmallVector<unsigned, 1> CUIndex(CUs.size());
680 DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
681 int CUCount = 0;
682 int TUCount = 0;
683 for (const auto &CU : enumerate(CUs)) {
684 switch (CU.value()->getCUNode()->getNameTableKind()) {
687 break;
688 default:
689 continue;
690 }
691 CUIndex[CU.index()] = CUCount++;
692 assert(CU.index() == CU.value()->getUniqueID());
693 const DwarfCompileUnit *MainCU =
694 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
695 CompUnits.push_back(MainCU->getLabelBegin());
696 }
697
698 for (const auto &TU : TUSymbols) {
699 TUIndex[TU.UniqueID] = TUCount++;
700 if (DD.useSplitDwarf())
701 TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
702 else
703 TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
704 }
705
706 if (CompUnits.empty())
707 return;
708
709 Asm->OutStreamer->switchSection(
710 Asm->getObjFileLowering().getDwarfDebugNamesSection());
711
712 Contents.finalize(Asm, "names");
713 dwarf::Form CUIndexForm =
714 DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
715 dwarf::Form TUIndexForm =
716 DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
717 Dwarf5AccelTableWriter(
718 Asm, Contents, CompUnits, TypeUnits,
719 [&](const DWARF5AccelTableData &Entry)
720 -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
721 if (Entry.isTU())
722 return {{TUIndex[Entry.getUnitID()],
723 {dwarf::DW_IDX_type_unit, TUIndexForm}}};
724 if (CUIndex.size() > 1)
725 return {{CUIndex[Entry.getUnitID()],
726 {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
727 return std::nullopt;
728 },
729 DD.useSplitDwarf())
730 .emit();
731}
732
734 TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
735}
736
738 TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
739}
740
742 AsmPrinter *Asm, DWARF5AccelTable &Contents,
743 ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
744 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
745 const DWARF5AccelTableData &)>
746 getIndexForEntry) {
747 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
748 Contents.finalize(Asm, "names");
749 Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
750 .emit();
751}
752
754 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
755 "The section offset exceeds the limit.");
756 Asm->emitInt32(Die.getDebugSectionOffset());
757}
758
760 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
761 "The section offset exceeds the limit.");
762 Asm->emitInt32(Die.getDebugSectionOffset());
763 Asm->emitInt16(Die.getTag());
764 Asm->emitInt8(0);
765}
766
768 Asm->emitInt32(Offset);
769}
770
772 Asm->emitInt32(Offset);
773 Asm->emitInt16(Tag);
775 : 0);
776 Asm->emitInt32(QualifiedNameHash);
777}
778
779#ifndef NDEBUG
780void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
781 OS << "Magic: " << format("0x%x", Magic) << "\n"
782 << "Version: " << Version << "\n"
783 << "Hash Function: " << HashFunction << "\n"
784 << "Bucket Count: " << BucketCount << "\n"
785 << "Header Data Length: " << HeaderDataLength << "\n";
786}
787
789 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
790 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
791}
792
793void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
794 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
795 for (auto Atom : Atoms)
796 Atom.print(OS);
797}
798
799void AppleAccelTableWriter::print(raw_ostream &OS) const {
800 Header.print(OS);
801 HeaderData.print(OS);
802 Contents.print(OS);
803 SecBegin->print(OS, nullptr);
804}
805
807 OS << "Name: " << Name.getString() << "\n";
808 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
809 OS << " Symbol: ";
810 if (Sym)
811 OS << *Sym;
812 else
813 OS << "<none>";
814 OS << "\n";
815 for (auto *Value : Values)
816 Value->print(OS);
817}
818
820 // Print Content.
821 OS << "Entries: \n";
822 for (const auto &[Name, Data] : Entries) {
823 OS << "Name: " << Name << "\n";
824 for (auto *V : Data.Values)
825 V->print(OS);
826 }
827
828 OS << "Buckets and Hashes: \n";
829 for (const auto &Bucket : Buckets)
830 for (const auto &Hash : Bucket)
831 Hash->print(OS);
832
833 OS << "Data: \n";
834 for (const auto &E : Entries)
835 E.second.print(OS);
836}
837
839 OS << " Offset: " << getDieOffset() << "\n";
840 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
841}
842
844 OS << " Offset: " << Die.getOffset() << "\n";
845}
846
848 OS << " Offset: " << Die.getOffset() << "\n";
849 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
850}
851
853 OS << " Static Offset: " << Offset << "\n";
854}
855
857 OS << " Static Offset: " << Offset << "\n";
858 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
859 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
860 OS << " ObjCClassIsImplementation: "
861 << (ObjCClassIsImplementation ? "true" : "false");
862 OS << "\n";
863}
864#endif
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
static std::optional< unsigned > getTag(const TargetRegisterInfo *TRI, const MachineInstr &MI, const LoadInfo &LI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static std::optional< dwarf::Form > getFormForIdxParent(const DenseSet< OffsetAndUnitID > &IndexedOffsets, std::optional< OffsetAndUnitID > ParentOffset)
This file contains support for writing accelerator tables.
Function Alias Analysis false
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
basic Basic Alias true
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
This file contains constants used for implementing Dwarf debug support.
This file contains some templates that are useful if you are working with the STL at all.
A base class holding non-template-dependant functionality of the AccelTable class.
Definition AccelTable.h:136
std::vector< HashData * > HashList
Definition AccelTable.h:161
LLVM_ABI void computeBucketCount()
LLVM_ABI void finalize(AsmPrinter *Asm, StringRef Prefix)
void print(raw_ostream &OS) const
ArrayRef< HashList > getBuckets() const
Definition AccelTable.h:184
StringEntries Entries
Definition AccelTable.h:169
Interface which the different types of accelerator table data have to conform.
Definition AccelTable.h:115
A base class for different implementations of Data classes for Apple Accelerator Tables.
Definition AccelTable.h:232
void emit(AsmPrinter *Asm) const override
void print(raw_ostream &OS) const override
void emit(AsmPrinter *Asm) const override
void print(raw_ostream &OS) const override
void emit(AsmPrinter *Asm) const override
void print(raw_ostream &OS) const override
void print(raw_ostream &OS) const override
void emit(AsmPrinter *Asm) const override
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:91
An integer value DIE.
Definition DIE.h:169
LLVM_ABI unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const
sizeOf - Determine size of integer value in bytes.
Definition DIE.cpp:420
static dwarf::Form BestForm(bool IsSigned, uint64_t Int)
Choose the best form for integer.
Definition DIE.h:176
A structured debug information entry.
Definition DIE.h:835
LLVM_ABI DIEValue findAttribute(dwarf::Attribute Attribute) const
Find a value in the DIE with the attribute given.
Definition DIE.cpp:209
LLVM_ABI DIE * getParent() const
Definition DIE.cpp:171
The Data class implementation for DWARF v5 accelerator table.
Definition AccelTable.h:286
void print(raw_ostream &OS) const override
unsigned getDieTag() const
Definition AccelTable.h:312
std::variant< const DIE *, uint64_t > OffsetVal
Definition AccelTable.h:350
LLVM_ABI DWARF5AccelTableData(const DIE &Die, const uint32_t UnitID, const bool IsTU)
static LLVM_ABI std::optional< uint64_t > getDefiningParentDieOffset(const DIE &Die)
If Die has a non-null parent and the parent is not a declaration, return its offset.
uint64_t getDieOffset() const
Definition AccelTable.h:303
LLVM_ABI void addTypeUnitSignature(DwarfTypeUnit &U)
Add a type unit Signature.
const TUVectorTy & getTypeUnitsSymbols()
Returns type units that were constructed.
Definition AccelTable.h:406
LLVM_ABI void addTypeUnitSymbol(DwarfTypeUnit &U)
Add a type unit start symbol.
void setNumber(uint32_t AbbrevNumber)
Set abbreviation tag index.
Definition AccelTable.h:373
const SmallVector< AttributeEncoding, 1 > & getAttributes() const
Returns attributes for an abbreviation.
Definition AccelTable.h:381
LLVM_ABI void Profile(FoldingSetNodeID &ID) const
Used to gather unique data for the abbreviation folding set.
uint32_t getNumber() const
Get abbreviation tag index.
Definition AccelTable.h:375
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:258
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:348
iterator end()
Definition DenseMap.h:176
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Collects and handles dwarf debug information.
Definition DwarfDebug.h:352
bool useSplitDwarf() const
Returns whether or not to change the current debug info for split DWARF.
Definition DwarfDebug.h:872
DwarfStringPoolEntryRef: Dwarf string pool entry reference.
MCSymbol * getLabelBegin() const
Get the the symbol for start of the section for this unit.
Definition DwarfUnit.h:107
void insert(T *N, FoldingSetInsertToken Token)
Insert the specified node into the folding set, knowing that it is not already in the folding set.
Definition FoldingSet.h:529
T * lookup(const FoldingSetNodeID &ID, FoldingSetInsertToken &Token)
Look up the node specified by ID.
Definition FoldingSet.h:520
Insertion token: a failed lookup fills it in, the matching insert consumes it.
Definition FoldingSet.h:284
This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:162
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:59
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM Value Representation.
Definition Value.h:75
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
LLVM_ABI StringRef FormEncodingString(unsigned Encoding)
Definition Dwarf.cpp:105
LLVM_ABI StringRef IndexString(unsigned Idx)
Definition Dwarf.cpp:956
LLVM_ABI StringRef AtomTypeString(unsigned Atom)
Definition Dwarf.cpp:852
LLVM_ABI StringRef TagString(unsigned Tag)
Definition Dwarf.cpp:21
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
uint32_t getDebugNamesBucketCount(uint32_t UniqueHashCount)
Definition Dwarf.h:1052
@ DW_FLAG_type_implementation
Definition Dwarf.h:1043
@ DW_hash_function_djb
Definition Dwarf.h:1048
bool empty() const
Definition BasicBlock.h:101
constexpr uint16_t Magic
Definition SFrame.h:32
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition DWP.cpp:577
void stable_sort(R &&Range)
Definition STLExtras.h:2132
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
SmallVector< TypeUnitMetaInfo, 1 > TUVectorTy
Definition AccelTable.h:395
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2150
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI void emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, StringRef Prefix, const MCSymbol *SecBegin, ArrayRef< AppleAccelTableData::Atom > Atoms)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:102
LLVM_ABI unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition LEB128.cpp:19
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
LLVM_ABI void emitDWARF5AccelTable(AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD, ArrayRef< std::unique_ptr< DwarfCompileUnit > > CUs)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:390
FoldingSetImpl< T, Trait > FoldingSet
This template class is used to instantiate a specialized implementation of the folding set to the nod...
Definition FoldingSet.h:558
Represents a group of entries with identical name (and hence, hash value).
Definition AccelTable.h:141
void print(raw_ostream &OS) const
DwarfStringPoolEntryRef Name
Definition AccelTable.h:142
std::vector< AccelTableData * > Values
Definition AccelTable.h:144
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
An Atom defines the form of the data in an Apple accelerator table.
Definition AccelTable.h:237
const uint16_t Form
DWARF Form.
Definition AccelTable.h:241
void print(raw_ostream &OS) const
const uint16_t Type
Atom Type.
Definition AccelTable.h:239