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