LLVM 23.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 uint32_t Bucket = E.second.HashValue % BucketCount;
65 Buckets[Bucket].push_back(&E.second);
66 E.second.Sym = Asm->createTempSymbol(Prefix);
67 }
68
69 // Sort the contents of the buckets by hash value so that hash collisions end
70 // up together. Stable sort makes testing easier and doesn't cost much more.
71 for (auto &Bucket : Buckets)
72 llvm::stable_sort(Bucket, [](HashData *LHS, HashData *RHS) {
73 return LHS->HashValue < RHS->HashValue;
74 });
75}
76
77namespace {
78/// Base class for writing out Accelerator tables. It holds the common
79/// functionality for the two Accelerator table types.
80class AccelTableWriter {
81protected:
82 AsmPrinter *const Asm; ///< Destination.
83 const AccelTableBase &Contents; ///< Data to emit.
84
85 /// Controls whether to emit duplicate hash and offset table entries for names
86 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
87 /// tables do.
88 const bool SkipIdenticalHashes;
89
90 void emitHashes() const;
91
92 /// Emit offsets to lists of entries with identical names. The offsets are
93 /// relative to the Base argument.
94 void emitOffsets(const MCSymbol *Base) const;
95
96public:
97 AccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
98 bool SkipIdenticalHashes)
99 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
100 }
101};
102
103class AppleAccelTableWriter : public AccelTableWriter {
104 using Atom = AppleAccelTableData::Atom;
105
106 /// The fixed header of an Apple Accelerator Table.
107 struct Header {
108 uint32_t Magic = MagicHash;
109 uint16_t Version = 1;
110 uint16_t HashFunction = dwarf::DW_hash_function_djb;
111 uint32_t BucketCount;
112 uint32_t HashCount;
113 uint32_t HeaderDataLength;
114
115 /// 'HASH' magic value to detect endianness.
116 static const uint32_t MagicHash = 0x48415348;
117
118 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
119 : BucketCount(BucketCount), HashCount(UniqueHashCount),
120 HeaderDataLength(DataLength) {}
121
122 void emit(AsmPrinter *Asm) const;
123#ifndef NDEBUG
124 void print(raw_ostream &OS) const;
125 void dump() const { print(dbgs()); }
126#endif
127 };
128
129 /// The HeaderData describes the structure of an Apple accelerator table
130 /// through a list of Atoms.
131 struct HeaderData {
132 /// In the case of data that is referenced via DW_FORM_ref_* the offset
133 /// base is used to describe the offset for all forms in the list of atoms.
134 uint32_t DieOffsetBase;
135
136 const SmallVector<Atom, 4> Atoms;
137
138 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
139 : DieOffsetBase(Offset), Atoms(AtomList) {}
140
141 void emit(AsmPrinter *Asm) const;
142#ifndef NDEBUG
143 void print(raw_ostream &OS) const;
144 void dump() const { print(dbgs()); }
145#endif
146 };
147
148 Header Header;
149 HeaderData HeaderData;
150 const MCSymbol *SecBegin;
151
152 void emitBuckets() const;
153 void emitData() const;
154
155public:
156 AppleAccelTableWriter(AsmPrinter *Asm, const AccelTableBase &Contents,
157 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
158 : AccelTableWriter(Asm, Contents, true),
159 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
160 8 + (Atoms.size() * 4)),
161 HeaderData(Atoms), SecBegin(SecBegin) {}
162
163 void emit() const;
164
165#ifndef NDEBUG
166 void print(raw_ostream &OS) const;
167 void dump() const { print(dbgs()); }
168#endif
169};
170
171/// Class responsible for emitting a DWARF v5 Accelerator Table. The only
172/// public function is emit(), which performs the actual emission.
173///
174/// A callback abstracts the logic to provide a CU index for a given entry.
175class Dwarf5AccelTableWriter : public AccelTableWriter {
176 struct Header {
177 uint16_t Version = 5;
178 uint16_t Padding = 0;
179 uint32_t CompUnitCount;
180 uint32_t LocalTypeUnitCount = 0;
181 uint32_t ForeignTypeUnitCount = 0;
182 uint32_t BucketCount = 0;
183 uint32_t NameCount = 0;
184 uint32_t AbbrevTableSize = 0;
185 uint32_t AugmentationStringSize = sizeof(AugmentationString);
186 char AugmentationString[8] = {'L', 'L', 'V', 'M', '0', '7', '0', '0'};
187
188 Header(uint32_t CompUnitCount, uint32_t LocalTypeUnitCount,
189 uint32_t ForeignTypeUnitCount, uint32_t BucketCount,
190 uint32_t NameCount)
191 : CompUnitCount(CompUnitCount), LocalTypeUnitCount(LocalTypeUnitCount),
192 ForeignTypeUnitCount(ForeignTypeUnitCount), BucketCount(BucketCount),
193 NameCount(NameCount) {}
194
195 void emit(Dwarf5AccelTableWriter &Ctx);
196 };
197
198 Header Header;
199 /// FoldingSet that uniques the abbreviations.
200 FoldingSet<DebugNamesAbbrev> AbbreviationsSet;
201 /// Vector containing DebugNames abbreviations for iteration in order.
202 SmallVector<DebugNamesAbbrev *, 5> AbbreviationsVector;
203 /// The bump allocator to use when creating DIEAbbrev objects in the uniqued
204 /// storage container.
208 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
209 const DWARF5AccelTableData &)>
210 getIndexForEntry;
211 MCSymbol *ContributionEnd = nullptr;
212 MCSymbol *AbbrevStart = Asm->createTempSymbol("names_abbrev_start");
213 MCSymbol *AbbrevEnd = Asm->createTempSymbol("names_abbrev_end");
214 MCSymbol *EntryPool = Asm->createTempSymbol("names_entries");
215 // Indicates if this module is built with Split Dwarf enabled.
216 bool IsSplitDwarf = false;
217 /// Stores the DIE offsets which are indexed by this table.
218 DenseSet<OffsetAndUnitID> IndexedOffsets;
219
220 void populateAbbrevsMap();
221
222 void emitCUList() const;
223 void emitTUList() const;
224 void emitBuckets() const;
225 void emitStringOffsets() const;
226 void emitAbbrevs() const;
227 void emitEntry(
228 const DWARF5AccelTableData &Entry,
229 const DenseMap<OffsetAndUnitID, uint64_t> &DIEOffsetToAccelEntryOffset);
230 uint64_t getEntrySize(const DWARF5AccelTableData &Entry) const;
231 void emitData();
232
233public:
234 Dwarf5AccelTableWriter(
235 AsmPrinter *Asm, const AccelTableBase &Contents,
236 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
237 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
238 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
239 const DWARF5AccelTableData &)>
240 getIndexForEntry,
241 bool IsSplitDwarf);
242 ~Dwarf5AccelTableWriter() {
243 for (DebugNamesAbbrev *Abbrev : AbbreviationsVector)
244 Abbrev->~DebugNamesAbbrev();
245 }
246 void emit();
247};
248} // namespace
249
250void AccelTableWriter::emitHashes() const {
251 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
252 unsigned BucketIdx = 0;
253 for (const auto &Bucket : Contents.getBuckets()) {
254 for (const auto &Hash : Bucket) {
255 uint32_t HashValue = Hash->HashValue;
256 if (SkipIdenticalHashes && PrevHash == HashValue)
257 continue;
258 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
259 Asm->emitInt32(HashValue);
260 PrevHash = HashValue;
261 }
262 BucketIdx++;
263 }
264}
265
266void AccelTableWriter::emitOffsets(const MCSymbol *Base) const {
267 const auto &Buckets = Contents.getBuckets();
268 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
269 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
270 for (auto *Hash : Buckets[i]) {
271 uint32_t HashValue = Hash->HashValue;
272 if (SkipIdenticalHashes && PrevHash == HashValue)
273 continue;
274 PrevHash = HashValue;
275 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
276 Asm->emitLabelDifference(Hash->Sym, Base, Asm->getDwarfOffsetByteSize());
277 }
278 }
279}
280
281void AppleAccelTableWriter::Header::emit(AsmPrinter *Asm) const {
282 Asm->OutStreamer->AddComment("Header Magic");
283 Asm->emitInt32(Magic);
284 Asm->OutStreamer->AddComment("Header Version");
285 Asm->emitInt16(Version);
286 Asm->OutStreamer->AddComment("Header Hash Function");
287 Asm->emitInt16(HashFunction);
288 Asm->OutStreamer->AddComment("Header Bucket Count");
289 Asm->emitInt32(BucketCount);
290 Asm->OutStreamer->AddComment("Header Hash Count");
291 Asm->emitInt32(HashCount);
292 Asm->OutStreamer->AddComment("Header Data Length");
293 Asm->emitInt32(HeaderDataLength);
294}
295
296void AppleAccelTableWriter::HeaderData::emit(AsmPrinter *Asm) const {
297 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
298 Asm->emitInt32(DieOffsetBase);
299 Asm->OutStreamer->AddComment("HeaderData Atom Count");
300 Asm->emitInt32(Atoms.size());
301
302 for (const Atom &A : Atoms) {
303 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
304 Asm->emitInt16(A.Type);
305 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
306 Asm->emitInt16(A.Form);
307 }
308}
309
310void AppleAccelTableWriter::emitBuckets() const {
311 const auto &Buckets = Contents.getBuckets();
312 unsigned index = 0;
313 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
314 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
315 if (!Buckets[i].empty())
316 Asm->emitInt32(index);
317 else
318 Asm->emitInt32(std::numeric_limits<uint32_t>::max());
319 // Buckets point in the list of hashes, not to the data. Do not increment
320 // the index multiple times in case of hash collisions.
321 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
322 for (auto *HD : Buckets[i]) {
323 uint32_t HashValue = HD->HashValue;
324 if (PrevHash != HashValue)
325 ++index;
326 PrevHash = HashValue;
327 }
328 }
329}
330
331void AppleAccelTableWriter::emitData() const {
332 const auto &Buckets = Contents.getBuckets();
333 for (const AccelTableBase::HashList &Bucket : Buckets) {
334 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
335 for (const auto &Hash : Bucket) {
336 // Terminate the previous entry if there is no hash collision with the
337 // current one.
338 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
339 PrevHash != Hash->HashValue)
340 Asm->emitInt32(0);
341 // Remember to emit the label for our offset.
342 Asm->OutStreamer->emitLabel(Hash->Sym);
343 Asm->OutStreamer->AddComment(Hash->Name.getString());
344 Asm->emitDwarfStringOffset(Hash->Name);
345 Asm->OutStreamer->AddComment("Num DIEs");
346 Asm->emitInt32(Hash->Values.size());
347 for (const auto *V : Hash->getValues<const AppleAccelTableData *>())
348 V->emit(Asm);
349 PrevHash = Hash->HashValue;
350 }
351 // Emit the final end marker for the bucket.
352 if (!Bucket.empty())
353 Asm->emitInt32(0);
354 }
355}
356
357void AppleAccelTableWriter::emit() const {
358 Header.emit(Asm);
359 HeaderData.emit(Asm);
360 emitBuckets();
361 emitHashes();
362 emitOffsets(SecBegin);
363 emitData();
364}
365
367 const uint32_t UnitID,
368 const bool IsTU)
369 : OffsetVal(&Die), DieTag(Die.getTag()), AbbrevNumber(0), IsTU(IsTU),
370 UnitID(UnitID) {}
371
372void Dwarf5AccelTableWriter::Header::emit(Dwarf5AccelTableWriter &Ctx) {
373 assert(CompUnitCount > 0 && "Index must have at least one CU.");
374
375 AsmPrinter *Asm = Ctx.Asm;
376 Ctx.ContributionEnd =
377 Asm->emitDwarfUnitLength("names", "Header: unit length");
378 Asm->OutStreamer->AddComment("Header: version");
379 Asm->emitInt16(Version);
380 Asm->OutStreamer->AddComment("Header: padding");
381 Asm->emitInt16(Padding);
382 Asm->OutStreamer->AddComment("Header: compilation unit count");
383 Asm->emitInt32(CompUnitCount);
384 Asm->OutStreamer->AddComment("Header: local type unit count");
385 Asm->emitInt32(LocalTypeUnitCount);
386 Asm->OutStreamer->AddComment("Header: foreign type unit count");
387 Asm->emitInt32(ForeignTypeUnitCount);
388 Asm->OutStreamer->AddComment("Header: bucket count");
389 Asm->emitInt32(BucketCount);
390 Asm->OutStreamer->AddComment("Header: name count");
391 Asm->emitInt32(NameCount);
392 Asm->OutStreamer->AddComment("Header: abbreviation table size");
393 Asm->emitLabelDifference(Ctx.AbbrevEnd, Ctx.AbbrevStart, sizeof(uint32_t));
394 Asm->OutStreamer->AddComment("Header: augmentation string size");
395 assert(AugmentationStringSize % 4 == 0);
396 Asm->emitInt32(AugmentationStringSize);
397 Asm->OutStreamer->AddComment("Header: augmentation string");
398 Asm->OutStreamer->emitBytes({AugmentationString, AugmentationStringSize});
399}
400
401std::optional<uint64_t>
403 if (auto *Parent = Die.getParent();
404 Parent && !Parent->findAttribute(dwarf::Attribute::DW_AT_declaration))
405 return Parent->getOffset();
406 return {};
407}
408
409static std::optional<dwarf::Form>
411 std::optional<OffsetAndUnitID> ParentOffset) {
412 // No parent information
413 if (!ParentOffset)
414 return std::nullopt;
415 // Parent is indexed by this table.
416 if (IndexedOffsets.contains(*ParentOffset))
417 return dwarf::Form::DW_FORM_ref4;
418 // Parent is not indexed by this table.
419 return dwarf::Form::DW_FORM_flag_present;
420}
421
423 ID.AddInteger(DieTag);
424 for (const DebugNamesAbbrev::AttributeEncoding &Enc : AttrVect) {
425 ID.AddInteger(Enc.Index);
426 ID.AddInteger(Enc.Form);
427 }
428}
429
430void Dwarf5AccelTableWriter::populateAbbrevsMap() {
431 for (auto &Bucket : Contents.getBuckets()) {
432 for (auto *Hash : Bucket) {
433 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
434 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
435 getIndexForEntry(*Value);
436 std::optional<dwarf::Form> MaybeParentForm = getFormForIdxParent(
437 IndexedOffsets, Value->getParentDieOffsetAndUnitID());
438 DebugNamesAbbrev Abbrev(Value->getDieTag());
439 if (EntryRet)
440 Abbrev.addAttribute(EntryRet->Encoding);
441 Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});
442 if (MaybeParentForm)
443 Abbrev.addAttribute({dwarf::DW_IDX_parent, *MaybeParentForm});
445 Abbrev.Profile(ID);
446 void *InsertPos;
447 if (DebugNamesAbbrev *Existing =
448 AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {
449 Value->setAbbrevNumber(Existing->getNumber());
450 continue;
451 }
452 DebugNamesAbbrev *NewAbbrev =
453 new (Alloc) DebugNamesAbbrev(std::move(Abbrev));
454 AbbreviationsVector.push_back(NewAbbrev);
455 NewAbbrev->setNumber(AbbreviationsVector.size());
456 AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);
457 Value->setAbbrevNumber(NewAbbrev->getNumber());
458 }
459 }
460 }
461}
462
463void Dwarf5AccelTableWriter::emitCUList() const {
464 for (const auto &CU : enumerate(CompUnits)) {
465 Asm->OutStreamer->AddComment("Compilation unit " + Twine(CU.index()));
466 if (std::holds_alternative<MCSymbol *>(CU.value()))
467 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(CU.value()));
468 else
469 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(CU.value()));
470 }
471}
472
473void Dwarf5AccelTableWriter::emitTUList() const {
474 for (const auto &TU : enumerate(TypeUnits)) {
475 Asm->OutStreamer->AddComment("Type unit " + Twine(TU.index()));
476 if (std::holds_alternative<MCSymbol *>(TU.value()))
477 Asm->emitDwarfSymbolReference(std::get<MCSymbol *>(TU.value()));
478 else if (IsSplitDwarf)
479 Asm->emitInt64(std::get<uint64_t>(TU.value()));
480 else
481 Asm->emitDwarfLengthOrOffset(std::get<uint64_t>(TU.value()));
482 }
483}
484
485void Dwarf5AccelTableWriter::emitBuckets() const {
486 uint32_t Index = 1;
487 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
488 Asm->OutStreamer->AddComment("Bucket " + Twine(Bucket.index()));
489 Asm->emitInt32(Bucket.value().empty() ? 0 : Index);
490 Index += Bucket.value().size();
491 }
492}
493
494void Dwarf5AccelTableWriter::emitStringOffsets() const {
495 for (const auto &Bucket : enumerate(Contents.getBuckets())) {
496 for (auto *Hash : Bucket.value()) {
497 DwarfStringPoolEntryRef String = Hash->Name;
498 Asm->OutStreamer->AddComment("String in Bucket " + Twine(Bucket.index()) +
499 ": " + String.getString());
500 Asm->emitDwarfStringOffset(String);
501 }
502 }
503}
504
505void Dwarf5AccelTableWriter::emitAbbrevs() const {
506 Asm->OutStreamer->emitLabel(AbbrevStart);
507 for (const DebugNamesAbbrev *Abbrev : AbbreviationsVector) {
508 Asm->OutStreamer->AddComment("Abbrev code");
509 Asm->emitULEB128(Abbrev->getNumber());
510 Asm->OutStreamer->AddComment(dwarf::TagString(Abbrev->getDieTag()));
511 Asm->emitULEB128(Abbrev->getDieTag());
512 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
513 Abbrev->getAttributes()) {
514 Asm->emitULEB128(AttrEnc.Index, dwarf::IndexString(AttrEnc.Index).data());
515 Asm->emitULEB128(AttrEnc.Form,
516 dwarf::FormEncodingString(AttrEnc.Form).data());
517 }
518 Asm->emitULEB128(0, "End of abbrev");
519 Asm->emitULEB128(0, "End of abbrev");
520 }
521 Asm->emitULEB128(0, "End of abbrev list");
522 Asm->OutStreamer->emitLabel(AbbrevEnd);
523}
524
525void Dwarf5AccelTableWriter::emitEntry(
526 const DWARF5AccelTableData &Entry,
527 const DenseMap<OffsetAndUnitID, uint64_t> &DIEOffsetToAccelEntryOffset) {
528 unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
529 assert(AbbrevIndex < AbbreviationsVector.size() &&
530 "Entry abbrev index is outside of abbreviations vector range.");
531 DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
532 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
533 getIndexForEntry(Entry);
534 std::optional<OffsetAndUnitID> MaybeParentOffset =
535 Entry.getParentDieOffsetAndUnitID();
536
537 Asm->emitULEB128(Entry.getAbbrevNumber(), "Abbreviation code");
538
539 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :
540 Abbrev->getAttributes()) {
541 Asm->OutStreamer->AddComment(dwarf::IndexString(AttrEnc.Index));
542 switch (AttrEnc.Index) {
543 case dwarf::DW_IDX_compile_unit:
544 case dwarf::DW_IDX_type_unit: {
545 DIEInteger ID(EntryRet->Index);
546 ID.emitValue(Asm, AttrEnc.Form);
547 break;
548 }
549 case dwarf::DW_IDX_die_offset:
550 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);
551 Asm->emitInt32(Entry.getDieOffset());
552 break;
553 case dwarf::DW_IDX_parent: {
554 if (AttrEnc.Form == dwarf::Form::DW_FORM_flag_present)
555 break;
556 auto It = DIEOffsetToAccelEntryOffset.find(*MaybeParentOffset);
557 assert(It != DIEOffsetToAccelEntryOffset.end());
558 Asm->emitInt32(It->second);
559 break;
560 }
561 default:
562 llvm_unreachable("Unexpected index attribute!");
563 }
564 }
565}
566
567uint64_t
568Dwarf5AccelTableWriter::getEntrySize(const DWARF5AccelTableData &Entry) const {
569 unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;
570 assert(AbbrevIndex < AbbreviationsVector.size());
571 DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];
572 uint64_t Size = getULEB128Size(Entry.getAbbrevNumber());
573 std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =
574 getIndexForEntry(Entry);
575 for (const auto &AttrEnc : Abbrev->getAttributes()) {
576 switch (AttrEnc.Index) {
577 case dwarf::DW_IDX_compile_unit:
578 case dwarf::DW_IDX_type_unit:
579 Size += DIEInteger(EntryRet->Index)
580 .sizeOf(Asm->getDwarfFormParams(), AttrEnc.Form);
581 break;
582 case dwarf::DW_IDX_die_offset:
583 Size += 4;
584 break;
585 case dwarf::DW_IDX_parent:
586 if (AttrEnc.Form != dwarf::Form::DW_FORM_flag_present)
587 Size += 4;
588 break;
589 default:
590 llvm_unreachable("Unexpected index attribute!");
591 }
592 }
593 return Size;
594}
595
596void Dwarf5AccelTableWriter::emitData() {
597 // Pre-compute entry pool offsets for DW_IDX_parent references.
598 DenseMap<OffsetAndUnitID, uint64_t> DIEOffsetToAccelEntryOffset;
599 uint64_t Offset = 0;
600 for (auto &Bucket : Contents.getBuckets()) {
601 for (auto *Hash : Bucket) {
602 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>()) {
603 DIEOffsetToAccelEntryOffset.try_emplace(Value->getDieOffsetAndUnitID(),
604 Offset);
605 Offset += getEntrySize(*Value);
606 }
607 Offset += 1; // End of list
608 }
609 }
610
611 Asm->OutStreamer->emitLabel(EntryPool);
612 for (auto &Bucket : Contents.getBuckets()) {
613 for (auto *Hash : Bucket) {
614 // Remember to emit the label for our offset.
615 Asm->OutStreamer->emitLabel(Hash->Sym);
616 for (const auto *Value : Hash->getValues<DWARF5AccelTableData *>())
617 emitEntry(*Value, DIEOffsetToAccelEntryOffset);
618 Asm->OutStreamer->AddComment("End of list: " + Hash->Name.getString());
619 Asm->emitInt8(0);
620 }
621 }
622}
623
624Dwarf5AccelTableWriter::Dwarf5AccelTableWriter(
625 AsmPrinter *Asm, const AccelTableBase &Contents,
626 ArrayRef<std::variant<MCSymbol *, uint64_t>> CompUnits,
627 ArrayRef<std::variant<MCSymbol *, uint64_t>> TypeUnits,
628 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
629 const DWARF5AccelTableData &)>
630 getIndexForEntry,
631 bool IsSplitDwarf)
632 : AccelTableWriter(Asm, Contents, false),
633 Header(CompUnits.size(), IsSplitDwarf ? 0 : TypeUnits.size(),
634 IsSplitDwarf ? TypeUnits.size() : 0, Contents.getBucketCount(),
635 Contents.getUniqueNameCount()),
636 CompUnits(CompUnits), TypeUnits(TypeUnits),
637 getIndexForEntry(std::move(getIndexForEntry)),
638 IsSplitDwarf(IsSplitDwarf) {
639
640 for (auto &Bucket : Contents.getBuckets())
641 for (auto *Hash : Bucket)
642 for (auto *Value : Hash->getValues<DWARF5AccelTableData *>())
643 IndexedOffsets.insert(Value->getDieOffsetAndUnitID());
644
645 populateAbbrevsMap();
646}
647
648void Dwarf5AccelTableWriter::emit() {
649 Header.emit(*this);
650 emitCUList();
651 emitTUList();
652 emitBuckets();
653 emitHashes();
654 emitStringOffsets();
655 emitOffsets(EntryPool);
656 emitAbbrevs();
657 emitData();
658 Asm->OutStreamer->emitValueToAlignment(Align(4), 0);
659 Asm->OutStreamer->emitLabel(ContributionEnd);
660}
661
663 StringRef Prefix, const MCSymbol *SecBegin,
665 Contents.finalize(Asm, Prefix);
666 AppleAccelTableWriter(Asm, Contents, Atoms, SecBegin).emit();
667}
668
670 AsmPrinter *Asm, DWARF5AccelTable &Contents, const DwarfDebug &DD,
671 ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs) {
672 TUVectorTy TUSymbols = Contents.getTypeUnitsSymbols();
673 std::vector<std::variant<MCSymbol *, uint64_t>> CompUnits;
674 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
675 SmallVector<unsigned, 1> CUIndex(CUs.size());
676 DenseMap<unsigned, unsigned> TUIndex(TUSymbols.size());
677 int CUCount = 0;
678 int TUCount = 0;
679 for (const auto &CU : enumerate(CUs)) {
680 switch (CU.value()->getCUNode()->getNameTableKind()) {
683 break;
684 default:
685 continue;
686 }
687 CUIndex[CU.index()] = CUCount++;
688 assert(CU.index() == CU.value()->getUniqueID());
689 const DwarfCompileUnit *MainCU =
690 DD.useSplitDwarf() ? CU.value()->getSkeleton() : CU.value().get();
691 CompUnits.push_back(MainCU->getLabelBegin());
692 }
693
694 for (const auto &TU : TUSymbols) {
695 TUIndex[TU.UniqueID] = TUCount++;
696 if (DD.useSplitDwarf())
697 TypeUnits.push_back(std::get<uint64_t>(TU.LabelOrSignature));
698 else
699 TypeUnits.push_back(std::get<MCSymbol *>(TU.LabelOrSignature));
700 }
701
702 if (CompUnits.empty())
703 return;
704
705 Asm->OutStreamer->switchSection(
706 Asm->getObjFileLowering().getDwarfDebugNamesSection());
707
708 Contents.finalize(Asm, "names");
709 dwarf::Form CUIndexForm =
710 DIEInteger::BestForm(/*IsSigned*/ false, CompUnits.size() - 1);
711 dwarf::Form TUIndexForm =
712 DIEInteger::BestForm(/*IsSigned*/ false, TypeUnits.size() - 1);
713 Dwarf5AccelTableWriter(
714 Asm, Contents, CompUnits, TypeUnits,
715 [&](const DWARF5AccelTableData &Entry)
716 -> std::optional<DWARF5AccelTable::UnitIndexAndEncoding> {
717 if (Entry.isTU())
718 return {{TUIndex[Entry.getUnitID()],
719 {dwarf::DW_IDX_type_unit, TUIndexForm}}};
720 if (CUIndex.size() > 1)
721 return {{CUIndex[Entry.getUnitID()],
722 {dwarf::DW_IDX_compile_unit, CUIndexForm}}};
723 return std::nullopt;
724 },
725 DD.useSplitDwarf())
726 .emit();
727}
728
730 TUSymbolsOrHashes.push_back({U.getLabelBegin(), U.getUniqueID()});
731}
732
734 TUSymbolsOrHashes.push_back({U.getTypeSignature(), U.getUniqueID()});
735}
736
738 AsmPrinter *Asm, DWARF5AccelTable &Contents,
739 ArrayRef<std::variant<MCSymbol *, uint64_t>> CUs,
740 llvm::function_ref<std::optional<DWARF5AccelTable::UnitIndexAndEncoding>(
741 const DWARF5AccelTableData &)>
742 getIndexForEntry) {
743 std::vector<std::variant<MCSymbol *, uint64_t>> TypeUnits;
744 Contents.finalize(Asm, "names");
745 Dwarf5AccelTableWriter(Asm, Contents, CUs, TypeUnits, getIndexForEntry, false)
746 .emit();
747}
748
750 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
751 "The section offset exceeds the limit.");
752 Asm->emitInt32(Die.getDebugSectionOffset());
753}
754
756 assert(Die.getDebugSectionOffset() <= UINT32_MAX &&
757 "The section offset exceeds the limit.");
758 Asm->emitInt32(Die.getDebugSectionOffset());
759 Asm->emitInt16(Die.getTag());
760 Asm->emitInt8(0);
761}
762
764 Asm->emitInt32(Offset);
765}
766
768 Asm->emitInt32(Offset);
769 Asm->emitInt16(Tag);
771 : 0);
772 Asm->emitInt32(QualifiedNameHash);
773}
774
775#ifndef NDEBUG
776void AppleAccelTableWriter::Header::print(raw_ostream &OS) const {
777 OS << "Magic: " << format("0x%x", Magic) << "\n"
778 << "Version: " << Version << "\n"
779 << "Hash Function: " << HashFunction << "\n"
780 << "Bucket Count: " << BucketCount << "\n"
781 << "Header Data Length: " << HeaderDataLength << "\n";
782}
783
785 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
786 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
787}
788
789void AppleAccelTableWriter::HeaderData::print(raw_ostream &OS) const {
790 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
791 for (auto Atom : Atoms)
792 Atom.print(OS);
793}
794
795void AppleAccelTableWriter::print(raw_ostream &OS) const {
796 Header.print(OS);
797 HeaderData.print(OS);
798 Contents.print(OS);
799 SecBegin->print(OS, nullptr);
800}
801
803 OS << "Name: " << Name.getString() << "\n";
804 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
805 OS << " Symbol: ";
806 if (Sym)
807 OS << *Sym;
808 else
809 OS << "<none>";
810 OS << "\n";
811 for (auto *Value : Values)
812 Value->print(OS);
813}
814
816 // Print Content.
817 OS << "Entries: \n";
818 for (const auto &[Name, Data] : Entries) {
819 OS << "Name: " << Name << "\n";
820 for (auto *V : Data.Values)
821 V->print(OS);
822 }
823
824 OS << "Buckets and Hashes: \n";
825 for (const auto &Bucket : Buckets)
826 for (const auto &Hash : Bucket)
827 Hash->print(OS);
828
829 OS << "Data: \n";
830 for (const auto &E : Entries)
831 E.second.print(OS);
832}
833
835 OS << " Offset: " << getDieOffset() << "\n";
836 OS << " Tag: " << dwarf::TagString(getDieTag()) << "\n";
837}
838
840 OS << " Offset: " << Die.getOffset() << "\n";
841}
842
844 OS << " Offset: " << Die.getOffset() << "\n";
845 OS << " Tag: " << dwarf::TagString(Die.getTag()) << "\n";
846}
847
849 OS << " Static Offset: " << Offset << "\n";
850}
851
853 OS << " Static Offset: " << Offset << "\n";
854 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
855 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
856 OS << " ObjCClassIsImplementation: "
857 << (ObjCClassIsImplementation ? "true" : "false");
858 OS << "\n";
859}
860#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!")
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
ArrayRef - 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:421
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:828
LLVM_ABI DIEValue findAttribute(dwarf::Attribute Attribute) const
Find a value in the DIE with the attribute given.
Definition DIE.cpp:210
LLVM_ABI DIE * getParent() const
Definition DIE.cpp:172
The Data class implementation for DWARF v5 accelerator table.
Definition AccelTable.h:293
void print(raw_ostream &OS) const override
unsigned getDieTag() const
Definition AccelTable.h:319
std::variant< const DIE *, uint64_t > OffsetVal
Definition AccelTable.h:357
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:310
LLVM_ABI void addTypeUnitSignature(DwarfTypeUnit &U)
Add a type unit Signature.
const TUVectorTy & getTypeUnitsSymbols()
Returns type units that were constructed.
Definition AccelTable.h:413
LLVM_ABI void addTypeUnitSymbol(DwarfTypeUnit &U)
Add a type unit start symbol.
void setNumber(uint32_t AbbrevNumber)
Set abbreviation tag index.
Definition AccelTable.h:380
const SmallVector< AttributeEncoding, 1 > & getAttributes() const
Returns attributes for an abbreviation.
Definition AccelTable.h:388
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:382
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:178
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:256
iterator end()
Definition DenseMap.h:81
Implements a dense probed hash-table based set.
Definition DenseSet.h:279
Collects and handles dwarf debug information.
Definition DwarfDebug.h:352
bool useSplitDwarf() const
Returns whether or not to change the current debug info for the split dwarf proposal support.
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:106
void InsertNode(T *N, void *InsertPos)
InsertNode - Insert the specified node into the folding set, knowing that it is not already in the fo...
Definition FoldingSet.h:512
T * FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos)
FindNodeOrInsertPos - Look up the node specified by ID.
Definition FoldingSet.h:504
FoldingSetNodeID - This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:209
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.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
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:202
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:175
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:915
LLVM_ABI StringRef AtomTypeString(unsigned Atom)
Definition Dwarf.cpp:815
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
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
uint32_t getDebugNamesBucketCount(uint32_t UniqueHashCount)
Definition Dwarf.h:962
@ DW_FLAG_type_implementation
Definition Dwarf.h:953
@ DW_hash_function_djb
Definition Dwarf.h:958
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:532
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
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:402
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2134
LLVM_ABI void emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents, StringRef Prefix, const MCSymbol *SecBegin, ArrayRef< AppleAccelTableData::Atom > Atoms)
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Definition InstrProf.h:334
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:207
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:129
LLVM_ABI unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition LEB128.cpp:19
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
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:383
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