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 AbbrevTableSize = 0;
191 uint32_t AugmentationStringSize = sizeof(AugmentationString);
192 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
193
194 Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
195 uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
196 uint32_t NameCount)
197 : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
198 ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
199 NameCount(NameCount) {}
200
201 void emit(Dwarf5AccelTableWriter &Ctx);
202 };
203
204 Header Header;
205 /// FoldingSet that uniques the abbreviations.
206 FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
207 /// Vector containing DebugNames abbreviations for iteration in order.
208 SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
209 /// The bump allocator to use when creating DIEAbbrev objects in the uniqued
210 /// storage container.
214 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
215 const DWARF5AccelTableData &)>
216 getIndexForEntry;
217 MCSymbol *ContributionEnd = nullptr;
218 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
219 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
220 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
221 // Indicates if this module is built with Split Dwarf enabled.
222 bool IsSplitDwarf = false;
223 /// Stores the DIE offsets which are indexed by this table.
224 DenseSet<OffsetAndUnitID> IndexedOffsets;
225
226 void populateAbbrevsMap();
227
228 void emitCUList() const;
229 void emitTUList() const;
230 void emitBuckets() const;
231 void emitStringOffsets() const;
232 void emitAbbrevs() const;
233 void emitEntry(
234 const DWARF5AccelTableData &Entry,
235 const DenseMap<OffsetAndUnitID, uint64_t> &DIEOffsetToAccelEntryOffset);
236 uint64_t getEntrySize(const DWARF5AccelTableData &Entry) const;
237 void emitData();
238
239public:
240 Dwarf5AccelTableWriter(
241 AsmPrinter *Asm, const AccelTableBase &Contents,
242 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
243 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
244 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
245 const DWARF5AccelTableData &)>
246 getIndexForEntry,
247 bool IsSplitDwarf);
248 ~Dwarf5AccelTableWriter() {
249 for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
250 Abbrev->~DebugNamesAbbrev();
251 }
252 void emit();
253};
254} // namespace
255
256void AccelTableWriter::emitHashes() const {
257 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
258 unsigned BucketIdx = 0;
259 for (const auto &Bucket : Contents.getBuckets()) {
260 for (const auto &Hash : Bucket) {
261 uint32_t HashValue = Hash->HashValue;
262 if (SkipIdenticalHashes && PrevHash == HashValue)
263 continue;
264 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
265 Asm->emitInt32(HashValue);
266 PrevHash = HashValue;
267 }
268 BucketIdx++;
269 }
270}
271
272void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
273 const auto &Buckets = Contents.getBuckets();
274 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
275 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
276 for (auto *Hash : Buckets[i]) {
277 uint32_t HashValue = Hash->HashValue;
278 if (SkipIdenticalHashes && PrevHash == HashValue)
279 continue;
280 PrevHash = HashValue;
281 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
282 Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
283 }
284 }
285}
286
287void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
288 Asm->OutStreamer->AddComment("Header Magic");
289 Asm->emitInt32(Magic);
290 Asm->OutStreamer->AddComment("Header Version");
291 Asm->emitInt16(Version);
292 Asm->OutStreamer->AddComment("Header Hash Function");
293 Asm->emitInt16(HashFunction);
294 Asm->OutStreamer->AddComment("Header Bucket Count");
295 Asm->emitInt32(BucketCount);
296 Asm->OutStreamer->AddComment("Header Hash Count");
297 Asm->emitInt32(HashCount);
298 Asm->OutStreamer->AddComment("Header Data Length");
299 Asm->emitInt32(HeaderDataLength);
300}
301
302void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
303 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
304 Asm->emitInt32(DieOffsetBase);
305 Asm->OutStreamer->AddComment("HeaderData Atom Count");
306 Asm->emitInt32(Atoms.size());
307
308 for (const Atom &A : Atoms) {
309 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
310 Asm->emitInt16(A.Type);
311 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
312 Asm->emitInt16(A.Form);
313 }
314}
315
316void AppleAccelTableWriter::emitBuckets() const {
317 const auto &Buckets = Contents.getBuckets();
318 unsigned index = 0;
319 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
320 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
321 if (!Buckets[i].empty())
322 Asm->emitInt32(index);
323 else
324 Asm->emitInt32(std::numeric_limits<uint32_t>::max());
325 // Buckets point in the list of hashes, not to the data. Do not increment
326 // the index multiple times in case of hash collisions.
327 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
328 for (auto *HD : Buckets[i]) {
329 uint32_t HashValue = HD->HashValue;
330 if (PrevHash != HashValue)
331 ++index;
332 PrevHash = HashValue;
333 }
334 }
335}
336
337void AppleAccelTableWriter::emitData() const {
338 const auto &Buckets = Contents.getBuckets();
339 for (const AccelTableBase::HashList &Bucket : Buckets) {
340 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
341 for (const auto &Hash : Bucket) {
342 // Terminate the previous entry if there is no hash collision with the
343 // current one.
344 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
345 PrevHash != Hash->HashValue)
346 Asm->emitInt32(0);
347 // Remember to emit the label for our offset.
348 Asm->OutStreamer->emitLabel(Hash->Sym);
349 Asm->OutStreamer->AddComment(Hash->Name.getString());
350 Asm->emitDwarfStringOffset(Hash->Name);
351 Asm->OutStreamer->AddComment("Num DIEs");
352 Asm->emitInt32(Hash->Values.size());
353 for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
354 V->emit(Asm);
355 PrevHash = Hash->HashValue;
356 }
357 // Emit the final end marker for the bucket.
358 if (!Bucket.empty())
359 Asm->emitInt32(0);
360 }
361}
362
363void AppleAccelTableWriter::emit() const {
364 Header.emit(Asm);
365 HeaderData.emit(Asm);
366 emitBuckets();
367 emitHashes();
368 emitOffsets(SecBegin);
369 emitData();
370}
371
373 const uint32_t UnitID,
374 const bool IsTU)
375 : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
376 UnitID(UnitID) {}
377
378void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
379 assert(CompUnitCount > 0 && "Index must have at least one CU.");
380
381 AsmPrinter *Asm = Ctx.Asm;
382 Ctx.ContributionEnd =
383 Asm->emitDwarfUnitLength("names", "Header: unit length");
384 Asm->OutStreamer->AddComment("Header: version");
385 Asm->emitInt16(Version);
386 Asm->OutStreamer->AddComment("Header: padding");
387 Asm->emitInt16(Padding);
388 Asm->OutStreamer->AddComment("Header: compilation unit count");
389 Asm->emitInt32(CompUnitCount);
390 Asm->OutStreamer->AddComment("Header: local type unit count");
391 Asm->emitInt32(LocalTypeUnitCount);
392 Asm->OutStreamer->AddComment("Header: foreign type unit count");
393 Asm->emitInt32(ForeignTypeUnitCount);
394 Asm->OutStreamer->AddComment("Header: bucket count");
395 Asm->emitInt32(BucketCount);
396 Asm->OutStreamer->AddComment("Header: name count");
397 Asm->emitInt32(NameCount);
398 Asm->OutStreamer->AddComment("Header: abbreviation table size");
399 Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
400 Asm->OutStreamer->AddComment("Header: augmentation string size");
401 assert(AugmentationStringSize % 4 == 0);
402 Asm->emitInt32(AugmentationStringSize);
403 Asm->OutStreamer->AddComment("Header: augmentation string");
404 Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
405}
406
407std::optional<uint64_t>
409 if (auto *Parent = Die.getParent();
410 Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
411 return Parent->getOffset();
412 return {};
413}
414
415static std::optional<dwarf::Form>
417 std::optional<OffsetAndUnitID> ParentOffset) {
418 // No parent information
419 if (!ParentOffset)
420 return std::nullopt;
421 // Parent is indexed by this table.
422 if (IndexedOffsets.contains(*ParentOffset))
423 return dwarf::Form::DW_FORM_ref4;
424 // Parent is not indexed by this table.
425 return dwarf::Form::DW_FORM_flag_present;
426}
427
429 ID.AddInteger(DieTag);
430 for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
431 ID.AddInteger(Enc.Index);
432 ID.AddInteger(Enc.Form);
433 }
434}
435
436void Dwarf5AccelTableWriter::populateAbbrevsMap() {
437 for (auto &Bucket : Contents.getBuckets()) {
438 for (auto *Hash : Bucket) {
439 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
440 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
441 getIndexForEntry(*Value);
442 std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
443 IndexedOffsets, Value->getParentDieOffsetAndUnitID());
444 DebugNamesAbbrev Abbrev(Value->getDieTag());
445 if (EntryRet)
446 Abbrev.addAttribute(EntryRet->Encoding);
447 Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
448 if (MaybeParentForm)
449 Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
451 Abbrev.Profile(ID);
453 if (DebugNamesAbbrev *Existing = AbbreviationsSet.lookup(ID, Token)) {
454 Value->setAbbrevNumber(Existing->getNumber());
455 continue;
456 }
457 DebugNamesAbbrev *NewAbbrev =
458 new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
459 AbbreviationsVector.push_back(NewAbbrev);
460 NewAbbrev->setNumber(AbbreviationsVector.size());
461 AbbreviationsSet.insert(NewAbbrev, Token);
462 Value->setAbbrevNumber(NewAbbrev->getNumber());
463 }
464 }
465 }
466}
467
468void Dwarf5AccelTableWriter::emitCUList() const {
469 for (const auto &CU : enumerate(CompUnits)) {
470 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
471 if (std::holds_alternative<MCSymbol *>(CU.value()))
472 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
473 else
474 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
475 }
476}
477
478void Dwarf5AccelTableWriter::emitTUList() const {
479 for (const auto &TU : enumerate(TypeUnits)) {
480 Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
481 if (std::holds_alternative<MCSymbol *>(TU.value()))
482 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
483 else if (IsSplitDwarf)
484 Asm->emitInt64(std::get<uint64_t>(TU.value()));
485 else
486 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
487 }
488}
489
490void Dwarf5AccelTableWriter::emitBuckets() const {
491 uint32_t Index = 1;
492 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
493 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
494 Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
495 Index += Bucket.value().size();
496 }
497}
498
499void Dwarf5AccelTableWriter::emitStringOffsets() const {
500 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
501 for (auto *Hash : Bucket.value()) {
502 DwarfStringPoolEntryRef String = Hash->Name;
503 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
504 ": " + String.getString());
505 Asm->emitDwarfStringOffset(String);
506 }
507 }
508}
509
510void Dwarf5AccelTableWriter::emitAbbrevs() const {
511 Asm->OutStreamer->emitLabel(AbbrevStart);
512 for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
513 Asm->OutStreamer->AddComment("Abbrev code");
514 Asm->emitULEB128(Abbrev->getNumber());
515 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
516 Asm->emitULEB128(Abbrev->getDieTag());
517 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
518 Abbrev->getAttributes()) {
519 Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
520 Asm->emitULEB128(AttrEnc.Form,
521 dwarf::FormEncodingString(AttrEnc.Form).data());
522 }
523 Asm->emitULEB128(0, "End of abbrev");
524 Asm->emitULEB128(0, "End of abbrev");
525 }
526 Asm->emitULEB128(0, "End of abbrev list");
527 Asm->OutStreamer->emitLabel(AbbrevEnd);
528}
529
530void Dwarf5AccelTableWriter::emitEntry(
531 const DWARF5AccelTableData &Entry,
532 const DenseMap<OffsetAndUnitID, uint64_t> &DIEOffsetToAccelEntryOffset) {
533 unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
534 assert(AbbrevIndex < AbbreviationsVector.size() &&
535 "Entry abbrev index is outside of abbreviations vector range.");
536 DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
537 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
538 getIndexForEntry(Entry);
539 std::optional<OffsetAndUnitID> MaybeParentOffset =
540 Entry.getParentDieOffsetAndUnitID();
541
542 Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
543
544 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
545 Abbrev->getAttributes()) {
546 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
547 switch (AttrEnc.Index) {
548 case dwarf::DW_IDX_compile_unit:
549 case dwarf::DW_IDX_type_unit: {
550 DIEInteger ID(EntryRet->Index);
551 ID.emitValue(Asm, AttrEnc.Form);
552 break;
553 }
554 case dwarf::DW_IDX_die_offset:
555 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
556 Asm->emitInt32(Entry.getDieOffset());
557 break;
558 case dwarf::DW_IDX_parent: {
559 if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
560 break;
561 auto It = DIEOffsetToAccelEntryOffset.find(*MaybeParentOffset);
562 assert(It != DIEOffsetToAccelEntryOffset.end());
563 Asm->emitInt32(It->second);
564 break;
565 }
566 default:
567 llvm_unreachable("Unexpected index attribute!");
568 }
569 }
570}
571
573Dwarf5AccelTableWriter::getEntrySize(const DWARF5AccelTableData &Entry) const {
574 unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
575 assert(AbbrevIndex < AbbreviationsVector.size());
576 DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
577 uint64_t Size = getULEB128Size(Entry.getAbbrevNumber());
578 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
579 getIndexForEntry(Entry);
580 for (const auto &AttrEnc : Abbrev->getAttributes()) {
581 switch (AttrEnc.Index) {
582 case dwarf::DW_IDX_compile_unit:
583 case dwarf::DW_IDX_type_unit:
584 Size += DIEInteger(EntryRet->Index)
585 .sizeOf(Asm->getDwarfFormParams(), AttrEnc.Form);
586 break;
587 case dwarf::DW_IDX_die_offset:
588 Size += 4;
589 break;
590 case dwarf::DW_IDX_parent:
591 if (AttrEnc.Form != dwarf::Form::DW_FORM_flag_present)
592 Size += 4;
593 break;
594 default:
595 llvm_unreachable("Unexpected index attribute!");
596 }
597 }
598 return Size;
599}
600
601void Dwarf5AccelTableWriter::emitData() {
602 // Pre-compute entry pool offsets for DW_IDX_parent references.
603 DenseMap<OffsetAndUnitID, uint64_t> DIEOffsetToAccelEntryOffset;
604 uint64_t Offset = 0;
605 for (auto &Bucket : Contents.getBuckets()) {
606 for (auto *Hash : Bucket) {
607 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
608 DIEOffsetToAccelEntryOffset.try_emplace(Value->getDieOffsetAndUnitID(),
609 Offset);
610 Offset += getEntrySize(*Value);
611 }
612 Offset += 1; // End of list
613 }
614 }
615
616 Asm->OutStreamer->emitLabel(EntryPool);
617 for (auto &Bucket : Contents.getBuckets()) {
618 for (auto *Hash : Bucket) {
619 // Remember to emit the label for our offset.
620 Asm->OutStreamer->emitLabel(Hash->Sym);
621 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
622 emitEntry(*Value, DIEOffsetToAccelEntryOffset);
623 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
624 Asm->emitInt8(0);
625 }
626 }
627}
628
629Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
630 AsmPrinter *Asm, const AccelTableBase &Contents,
631 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
632 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
633 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
634 const DWARF5AccelTableData &)>
635 getIndexForEntry,
636 bool IsSplitDwarf)
637 : AccelTableWriter(Asm, Contents, false),
638 Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
639 IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
640 Contents.getUniqueNameCount()),
641 CompUnits(CompUnits), TypeUnits(TypeUnits),
642 getIndexForEntry(std::move(getIndexForEntry)),
643 IsSplitDwarf(IsSplitDwarf) {
644
645 for (auto &Bucket : Contents.getBuckets())
646 for (auto *Hash : Bucket)
647 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
648 IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
649
650 populateAbbrevsMap();
651}
652
653void Dwarf5AccelTableWriter::emit() {
654 Header.emit(*this);
655 emitCUList();
656 emitTUList();
657 emitBuckets();
658 emitHashes();
659 emitStringOffsets();
660 emitOffsets(EntryPool);
661 emitAbbrevs();
662 emitData();
663 Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
664 Asm->OutStreamer->emitLabel(ContributionEnd);
665}
666
668 StringRef Prefix, const MCSymbol *SecBegin,
670 Contents.finalize(Asm, Prefix);
671 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
672}
673
675 AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
676 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
677 TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
678 std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
679 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
680 SmallVector<unsigned, 1> CUIndex(CUs.size());
681 DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
682 int CUCount = 0;
683 int TUCount = 0;
684 for (const auto &CU : enumerate(CUs)) {
685 switch (CU.value()->getCUNode()->getNameTableKind()) {
688 break;
689 default:
690 continue;
691 }
692 CUIndex[CU.index()] = CUCount++;
693 assert(CU.index() == CU.value()->getUniqueID());
694 const DwarfCompileUnit *MainCU =
695 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
696 CompUnits.push_back(MainCU->getLabelBegin());
697 }
698
699 for (const auto &TU : TUSymbols) {
700 TUIndex[TU.UniqueID] = TUCount++;
701 if (DD.useSplitDwarf())
702 TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
703 else
704 TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
705 }
706
707 if (CompUnits.empty())
708 return;
709
710 Asm->OutStreamer->switchSection(
711 Asm->getObjFileLowering().getDwarfDebugNamesSection());
712
713 Contents.finalize(Asm, "names");
714 dwarf::Form CUIndexForm =
715 DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
716 dwarf::Form TUIndexForm =
717 DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
718 Dwarf5AccelTableWriter(
719 Asm, Contents, CompUnits, TypeUnits,
720 [&](const DWARF5AccelTableData &Entry)
721 -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
722 if (Entry.isTU())
723 return {{TUIndex[Entry.getUnitID()],
724 {dwarf::DW_IDX_type_unit, TUIndexForm}}};
725 if (CUIndex.size() > 1)
726 return {{CUIndex[Entry.getUnitID()],
727 {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
728 return std::nullopt;
729 },
730 DD.useSplitDwarf())
731 .emit();
732}
733
735 TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
736}
737
739 TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
740}
741
743 AsmPrinter *Asm, DWARF5AccelTable &Contents,
744 ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
745 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
746 const DWARF5AccelTableData &)>
747 getIndexForEntry) {
748 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
749 Contents.finalize(Asm, "names");
750 Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
751 .emit();
752}
753
755 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
756 "The section offset exceeds the limit.");
757 Asm->emitInt32(Die.getDebugSectionOffset());
758}
759
761 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
762 "The section offset exceeds the limit.");
763 Asm->emitInt32(Die.getDebugSectionOffset());
764 Asm->emitInt16(Die.getTag());
765 Asm->emitInt8(0);
766}
767
769 Asm->emitInt32(Offset);
770}
771
773 Asm->emitInt32(Offset);
774 Asm->emitInt16(Tag);
776 : 0);
777 Asm->emitInt32(QualifiedNameHash);
778}
779
780#ifndef NDEBUG
781void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
782 OS << "Magic: " << format("0x%x", Magic) << "\n"
783 << "Version: " << Version << "\n"
784 << "Hash Function: " << HashFunction << "\n"
785 << "Bucket Count: " << BucketCount << "\n"
786 << "Header Data Length: " << HeaderDataLength << "\n";
787}
788
790 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
791 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
792}
793
794void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
795 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
796 for (auto Atom : Atoms)
797 Atom.print(OS);
798}
799
800void AppleAccelTableWriter::print(raw_ostream &OS) const {
801 Header.print(OS);
802 HeaderData.print(OS);
803 Contents.print(OS);
804 SecBegin->print(OS, nullptr);
805}
806
808 OS << "Name: " << Name.getString() << "\n";
809 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
810 OS << " Symbol: ";
811 if (Sym)
812 OS << *Sym;
813 else
814 OS << "<none>";
815 OS << "\n";
816 for (auto *Value : Values)
817 Value->print(OS);
818}
819
821 // Print Content.
822 OS << "Entries: \n";
823 for (const auto &[Name, Data] : Entries) {
824 OS << "Name: " << Name << "\n";
825 for (auto *V : Data.Values)
826 V->print(OS);
827 }
828
829 OS << "Buckets and Hashes: \n";
830 for (const auto &Bucket : Buckets)
831 for (const auto &Hash : Bucket)
832 Hash->print(OS);
833
834 OS << "Data: \n";
835 for (const auto &E : Entries)
836 E.second.print(OS);
837}
838
840 OS << " Offset: " << getDieOffset() << "\n";
841 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
842}
843
845 OS << " Offset: " << Die.getOffset() << "\n";
846}
847
849 OS << " Offset: " << Die.getOffset() << "\n";
850 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
851}
852
854 OS << " Static Offset: " << Offset << "\n";
855}
856
858 OS << " Static Offset: " << Offset << "\n";
859 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
860 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
861 OS << " ObjCClassIsImplementation: "
862 << (ObjCClassIsImplementation ? "true" : "false");
863 OS << "\n";
864}
865#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:233
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:842
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:287
void print(raw_ostream &OS) const override
unsigned getDieTag() const
Definition AccelTable.h:313
std::variant< const DIE *, uint64_t > OffsetVal
Definition AccelTable.h:351
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:304
LLVM_ABI void addTypeUnitSignature(DwarfTypeUnit &U)
Add a type unit Signature.
const TUVectorTy & getTypeUnitsSymbols()
Returns type units that were constructed.
Definition AccelTable.h:407
LLVM_ABI void addTypeUnitSymbol(DwarfTypeUnit &U)
Add a type unit start symbol.
void setNumber(uint32_t AbbrevNumber)
Set abbreviation tag index.
Definition AccelTable.h:374
const SmallVector< AttributeEncoding, 1 > & getAttributes() const
Returns attributes for an abbreviation.
Definition AccelTable.h:382
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:376
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
iterator end()
Definition DenseMap.h:141
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:875
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:954
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:1045
@ DW_FLAG_type_implementation
Definition Dwarf.h:1036
@ DW_hash_function_djb
Definition Dwarf.h:1041
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:2116
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:1669
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:2554
SmallVector< TypeUnitMetaInfo, 1 > TUVectorTy
Definition AccelTable.h:396
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2134
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:1636
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:1917
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:238
const uint16_t Form
DWARF Form.
Definition AccelTable.h:242
void print(raw_ostream &OS) const
const uint16_t Type
Atom Type.
Definition AccelTable.h:240