blob: ff70beb1613ec51924c21088216d61b306da37c5 [file] [log] [blame]
Jonas Devlieghere855fc3b2018-01-29 14:52:41 +00001//===- llvm/CodeGen/AsmPrinter/AccelTable.cpp - Accelerator Tables --------===//
Eric Christopher6e472042011-11-07 09:18:42 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Jonas Devlieghere855fc3b2018-01-29 14:52:41 +000010// This file contains support for writing accelerator tables.
Eric Christopher6e472042011-11-07 09:18:42 +000011//
12//===----------------------------------------------------------------------===//
13
Jonas Devlieghere855fc3b2018-01-29 14:52:41 +000014#include "llvm/CodeGen/AccelTable.h"
Benjamin Kramer3e6719c2012-03-26 14:17:26 +000015#include "llvm/ADT/STLExtras.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000016#include "llvm/ADT/StringMap.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000017#include "llvm/ADT/Twine.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000018#include "llvm/BinaryFormat/Dwarf.h"
Eric Christopher6e472042011-11-07 09:18:42 +000019#include "llvm/CodeGen/AsmPrinter.h"
Frederic Risse541e0b2015-01-05 21:29:41 +000020#include "llvm/CodeGen/DIE.h"
Eric Christopher6e472042011-11-07 09:18:42 +000021#include "llvm/MC/MCExpr.h"
22#include "llvm/MC/MCStreamer.h"
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000023#include "llvm/Support/raw_ostream.h"
24#include <algorithm>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000025#include <cstddef>
26#include <cstdint>
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +000027#include <limits>
28#include <vector>
Eric Christopher6e472042011-11-07 09:18:42 +000029
30using namespace llvm;
31
Pavel Labatha7c457d2018-02-19 16:12:20 +000032void AccelTableBase::computeBucketCount() {
33 // First get the number of unique hashes.
34 std::vector<uint32_t> Uniques;
35 Uniques.reserve(Entries.size());
36 for (const auto &E : Entries)
37 Uniques.push_back(E.second.HashValue);
38 array_pod_sort(Uniques.begin(), Uniques.end());
39 std::vector<uint32_t>::iterator P =
40 std::unique(Uniques.begin(), Uniques.end());
41
42 UniqueHashCount = std::distance(Uniques.begin(), P);
43
44 if (UniqueHashCount > 1024)
45 BucketCount = UniqueHashCount / 4;
46 else if (UniqueHashCount > 16)
47 BucketCount = UniqueHashCount / 2;
48 else
49 BucketCount = std::max<uint32_t>(UniqueHashCount, 1);
50}
51
52void AccelTableBase::finalize(AsmPrinter *Asm, StringRef Prefix) {
53 // Create the individual hash data outputs.
54 for (auto &E : Entries) {
55 // Unique the entries.
56 std::stable_sort(E.second.Values.begin(), E.second.Values.end(),
57 [](const AccelTableData *A, const AccelTableData *B) {
58 return *A < *B;
59 });
60 E.second.Values.erase(
61 std::unique(E.second.Values.begin(), E.second.Values.end()),
62 E.second.Values.end());
63 }
64
65 // Figure out how many buckets we need, then compute the bucket contents and
66 // the final ordering. The hashes and offsets can be emitted by walking these
67 // data structures. We add temporary symbols to the data so they can be
68 // referenced when emitting the offsets.
69 computeBucketCount();
70
71 // Compute bucket contents and final ordering.
72 Buckets.resize(BucketCount);
73 for (auto &E : Entries) {
74 uint32_t Bucket = E.second.HashValue % BucketCount;
75 Buckets[Bucket].push_back(&E.second);
76 E.second.Sym = Asm->createTempSymbol(Prefix);
77 }
78
79 // Sort the contents of the buckets by hash value so that hash collisions end
80 // up together. Stable sort makes testing easier and doesn't cost much more.
81 for (auto &Bucket : Buckets)
82 std::stable_sort(Bucket.begin(), Bucket.end(),
83 [](HashData *LHS, HashData *RHS) {
84 return LHS->HashValue < RHS->HashValue;
85 });
86}
87
88namespace {
89class AccelTableEmitter {
90protected:
91 AsmPrinter *const Asm; ///< Destination.
92 const AccelTableBase &Contents; ///< Data to emit.
93
94 /// Controls whether to emit duplicate hash and offset table entries for names
95 /// with identical hashes. Apple tables don't emit duplicate entries, DWARF v5
96 /// tables do.
97 const bool SkipIdenticalHashes;
98
99 void emitHashes() const;
100
101 /// Emit offsets to lists of entries with identical names. The offsets are
102 /// relative to the Base argument.
103 void emitOffsets(const MCSymbol *Base) const;
104
105public:
106 AccelTableEmitter(AsmPrinter *Asm, const AccelTableBase &Contents,
107 bool SkipIdenticalHashes)
108 : Asm(Asm), Contents(Contents), SkipIdenticalHashes(SkipIdenticalHashes) {
109 }
110};
111
112class AppleAccelTableEmitter : public AccelTableEmitter {
113 using Atom = AppleAccelTableData::Atom;
114
115 /// The fixed header of an Apple Accelerator Table.
116 struct Header {
117 uint32_t Magic = MagicHash;
118 uint16_t Version = 1;
119 uint16_t HashFunction = dwarf::DW_hash_function_djb;
120 uint32_t BucketCount;
121 uint32_t HashCount;
122 uint32_t HeaderDataLength;
123
124 /// 'HASH' magic value to detect endianness.
125 static const uint32_t MagicHash = 0x48415348;
126
127 Header(uint32_t BucketCount, uint32_t UniqueHashCount, uint32_t DataLength)
128 : BucketCount(BucketCount), HashCount(UniqueHashCount),
129 HeaderDataLength(DataLength) {}
130
131 void emit(AsmPrinter *Asm) const;
132#ifndef NDEBUG
133 void print(raw_ostream &OS) const;
134 void dump() const { print(dbgs()); }
135#endif
136 };
137
138 /// The HeaderData describes the structure of an Apple accelerator table
139 /// through a list of Atoms.
140 struct HeaderData {
141 /// In the case of data that is referenced via DW_FORM_ref_* the offset
142 /// base is used to describe the offset for all forms in the list of atoms.
143 uint32_t DieOffsetBase;
144
145 const SmallVector<Atom, 4> Atoms;
146
147 HeaderData(ArrayRef<Atom> AtomList, uint32_t Offset = 0)
148 : DieOffsetBase(Offset), Atoms(AtomList.begin(), AtomList.end()) {}
149
150 void emit(AsmPrinter *Asm) const;
151#ifndef NDEBUG
152 void print(raw_ostream &OS) const;
153 void dump() const { print(dbgs()); }
154#endif
155 };
156
157 Header Header;
158 HeaderData HeaderData;
159 const MCSymbol *SecBegin;
160
161 void emitBuckets() const;
162 void emitData() const;
163
164public:
165 AppleAccelTableEmitter(AsmPrinter *Asm, const AccelTableBase &Contents,
166 ArrayRef<Atom> Atoms, const MCSymbol *SecBegin)
167 : AccelTableEmitter(Asm, Contents, true),
168 Header(Contents.getBucketCount(), Contents.getUniqueHashCount(),
169 8 + (Atoms.size() * 4)),
170 HeaderData(Atoms), SecBegin(SecBegin) {}
171
172 void emit() const;
173
174#ifndef NDEBUG
175 void print(raw_ostream &OS) const;
176 void dump() const { print(dbgs()); }
177#endif
178};
179} // namespace
180
181void AccelTableEmitter::emitHashes() const {
182 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
183 unsigned BucketIdx = 0;
184 for (auto &Bucket : Contents.getBuckets()) {
185 for (auto &Hash : Bucket) {
186 uint32_t HashValue = Hash->HashValue;
187 if (SkipIdenticalHashes && PrevHash == HashValue)
188 continue;
189 Asm->OutStreamer->AddComment("Hash in Bucket " + Twine(BucketIdx));
190 Asm->EmitInt32(HashValue);
191 PrevHash = HashValue;
192 }
193 BucketIdx++;
194 }
195}
196
197void AccelTableEmitter::emitOffsets(const MCSymbol *Base) const {
198 const auto &Buckets = Contents.getBuckets();
199 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
200 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
201 for (auto *Hash : Buckets[i]) {
202 uint32_t HashValue = Hash->HashValue;
203 if (SkipIdenticalHashes && PrevHash == HashValue)
204 continue;
205 PrevHash = HashValue;
206 Asm->OutStreamer->AddComment("Offset in Bucket " + Twine(i));
207 Asm->EmitLabelDifference(Hash->Sym, Base, sizeof(uint32_t));
208 }
209 }
210}
211
212void AppleAccelTableEmitter::Header::emit(AsmPrinter *Asm) const {
Lang Hames9ff69c82015-04-24 19:11:51 +0000213 Asm->OutStreamer->AddComment("Header Magic");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000214 Asm->EmitInt32(Magic);
Lang Hames9ff69c82015-04-24 19:11:51 +0000215 Asm->OutStreamer->AddComment("Header Version");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000216 Asm->EmitInt16(Version);
Lang Hames9ff69c82015-04-24 19:11:51 +0000217 Asm->OutStreamer->AddComment("Header Hash Function");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000218 Asm->EmitInt16(HashFunction);
Lang Hames9ff69c82015-04-24 19:11:51 +0000219 Asm->OutStreamer->AddComment("Header Bucket Count");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000220 Asm->EmitInt32(BucketCount);
Lang Hames9ff69c82015-04-24 19:11:51 +0000221 Asm->OutStreamer->AddComment("Header Hash Count");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000222 Asm->EmitInt32(HashCount);
Lang Hames9ff69c82015-04-24 19:11:51 +0000223 Asm->OutStreamer->AddComment("Header Data Length");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000224 Asm->EmitInt32(HeaderDataLength);
225}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000226
Pavel Labatha7c457d2018-02-19 16:12:20 +0000227void AppleAccelTableEmitter::HeaderData::emit(AsmPrinter *Asm) const {
Lang Hames9ff69c82015-04-24 19:11:51 +0000228 Asm->OutStreamer->AddComment("HeaderData Die Offset Base");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000229 Asm->EmitInt32(DieOffsetBase);
Lang Hames9ff69c82015-04-24 19:11:51 +0000230 Asm->OutStreamer->AddComment("HeaderData Atom Count");
Pavel Labatha7c457d2018-02-19 16:12:20 +0000231 Asm->EmitInt32(Atoms.size());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000232
Pavel Labatha7c457d2018-02-19 16:12:20 +0000233 for (const Atom &A : Atoms) {
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000234 Asm->OutStreamer->AddComment(dwarf::AtomTypeString(A.Type));
235 Asm->EmitInt16(A.Type);
236 Asm->OutStreamer->AddComment(dwarf::FormEncodingString(A.Form));
237 Asm->EmitInt16(A.Form);
Eric Christopher6e472042011-11-07 09:18:42 +0000238 }
239}
240
Pavel Labatha7c457d2018-02-19 16:12:20 +0000241void AppleAccelTableEmitter::emitBuckets() const {
242 const auto &Buckets = Contents.getBuckets();
Eric Christopher6e472042011-11-07 09:18:42 +0000243 unsigned index = 0;
Eric Christopher54ce295d2011-11-08 18:38:40 +0000244 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Lang Hames9ff69c82015-04-24 19:11:51 +0000245 Asm->OutStreamer->AddComment("Bucket " + Twine(i));
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000246 if (!Buckets[i].empty())
Eric Christopher6e472042011-11-07 09:18:42 +0000247 Asm->EmitInt32(index);
248 else
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000249 Asm->EmitInt32(std::numeric_limits<uint32_t>::max());
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000250 // Buckets point in the list of hashes, not to the data. Do not increment
251 // the index multiple times in case of hash collisions.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000252 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000253 for (auto *HD : Buckets[i]) {
254 uint32_t HashValue = HD->HashValue;
255 if (PrevHash != HashValue)
256 ++index;
257 PrevHash = HashValue;
258 }
Eric Christopher6e472042011-11-07 09:18:42 +0000259 }
260}
261
Pavel Labatha7c457d2018-02-19 16:12:20 +0000262void AppleAccelTableEmitter::emitData() const {
263 const auto &Buckets = Contents.getBuckets();
Eric Christopher54ce295d2011-11-08 18:38:40 +0000264 for (size_t i = 0, e = Buckets.size(); i < e; ++i) {
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000265 uint64_t PrevHash = std::numeric_limits<uint64_t>::max();
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000266 for (auto &Hash : Buckets[i]) {
267 // Terminate the previous entry if there is no hash collision with the
268 // current one.
Eugene Zelenko6e07bfd2017-08-17 21:26:39 +0000269 if (PrevHash != std::numeric_limits<uint64_t>::max() &&
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000270 PrevHash != Hash->HashValue)
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000271 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000272 // Remember to emit the label for our offset.
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000273 Asm->OutStreamer->EmitLabel(Hash->Sym);
Pavel Labath062eb532018-02-09 10:06:56 +0000274 Asm->OutStreamer->AddComment(Hash->Name.getString());
275 Asm->emitDwarfStringOffset(Hash->Name);
Lang Hames9ff69c82015-04-24 19:11:51 +0000276 Asm->OutStreamer->AddComment("Num DIEs");
Pavel Labath062eb532018-02-09 10:06:56 +0000277 Asm->EmitInt32(Hash->Values.size());
Pavel Labatha7c457d2018-02-19 16:12:20 +0000278 for (const auto *V : Hash->Values)
279 static_cast<const AppleAccelTableData *>(V)->emit(Asm);
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000280 PrevHash = Hash->HashValue;
Eric Christopher6e472042011-11-07 09:18:42 +0000281 }
Frederic Riss0e9a50f2015-03-10 00:46:31 +0000282 // Emit the final end marker for the bucket.
Frederic Riss44a219f2015-03-10 03:47:55 +0000283 if (!Buckets[i].empty())
284 Asm->EmitInt32(0);
Eric Christopher6e472042011-11-07 09:18:42 +0000285 }
286}
287
Pavel Labatha7c457d2018-02-19 16:12:20 +0000288void AppleAccelTableEmitter::emit() const {
289 Header.emit(Asm);
290 HeaderData.emit(Asm);
291 emitBuckets();
292 emitHashes();
293 emitOffsets(SecBegin);
294 emitData();
Eric Christopher6e472042011-11-07 09:18:42 +0000295}
296
Pavel Labatha7c457d2018-02-19 16:12:20 +0000297void llvm::emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
298 StringRef Prefix, const MCSymbol *SecBegin,
299 ArrayRef<AppleAccelTableData::Atom> Atoms) {
300 Contents.finalize(Asm, Prefix);
301 AppleAccelTableEmitter(Asm, Contents, Atoms, SecBegin).emit();
Eric Christopher6e472042011-11-07 09:18:42 +0000302}
Jonas Devliegheree699dfa2018-01-29 14:52:34 +0000303
304void AppleAccelTableOffsetData::emit(AsmPrinter *Asm) const {
305 Asm->EmitInt32(Die->getDebugSectionOffset());
306}
307
308void AppleAccelTableTypeData::emit(AsmPrinter *Asm) const {
309 Asm->EmitInt32(Die->getDebugSectionOffset());
310 Asm->EmitInt16(Die->getTag());
311 Asm->EmitInt8(0);
312}
Jonas Devlieghere5ead3a22018-01-29 14:52:50 +0000313
314void AppleAccelTableStaticOffsetData::emit(AsmPrinter *Asm) const {
315 Asm->EmitInt32(Offset);
316}
317
318void AppleAccelTableStaticTypeData::emit(AsmPrinter *Asm) const {
319 Asm->EmitInt32(Offset);
320 Asm->EmitInt16(Tag);
321 Asm->EmitInt8(ObjCClassIsImplementation ? dwarf::DW_FLAG_type_implementation
322 : 0);
323 Asm->EmitInt32(QualifiedNameHash);
324}
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000325
326#ifndef _MSC_VER
327// The lines below are rejected by older versions (TBD) of MSVC.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000328constexpr AppleAccelTableData::Atom AppleAccelTableTypeData::Atoms[];
329constexpr AppleAccelTableData::Atom AppleAccelTableOffsetData::Atoms[];
330constexpr AppleAccelTableData::Atom AppleAccelTableStaticOffsetData::Atoms[];
331constexpr AppleAccelTableData::Atom AppleAccelTableStaticTypeData::Atoms[];
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000332#else
333// FIXME: Erase this path once the minimum MSCV version has been bumped.
Pavel Labatha7c457d2018-02-19 16:12:20 +0000334const SmallVector<AppleAccelTableData::Atom, 4>
335 AppleAccelTableOffsetData::Atoms = {
336 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
337const SmallVector<AppleAccelTableData::Atom, 4> AppleAccelTableTypeData::Atoms =
338 {Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
339 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
340 Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
341const SmallVector<AppleAccelTableData::Atom, 4>
342 AppleAccelTableStaticOffsetData::Atoms = {
343 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
344const SmallVector<AppleAccelTableData::Atom, 4>
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000345 AppleAccelTableStaticTypeData::Atoms = {
Pavel Labatha7c457d2018-02-19 16:12:20 +0000346 Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
347 Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
348 Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
Jonas Devlieghere073971b2018-01-29 17:28:51 +0000349#endif
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000350
351#ifndef NDEBUG
Pavel Labatha7c457d2018-02-19 16:12:20 +0000352void AppleAccelTableEmitter::Header::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000353 OS << "Magic: " << format("0x%x", Magic) << "\n"
354 << "Version: " << Version << "\n"
355 << "Hash Function: " << HashFunction << "\n"
356 << "Bucket Count: " << BucketCount << "\n"
357 << "Header Data Length: " << HeaderDataLength << "\n";
358}
359
Pavel Labatha7c457d2018-02-19 16:12:20 +0000360void AppleAccelTableData::Atom::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000361 OS << "Type: " << dwarf::AtomTypeString(Type) << "\n"
362 << "Form: " << dwarf::FormEncodingString(Form) << "\n";
363}
364
Pavel Labatha7c457d2018-02-19 16:12:20 +0000365void AppleAccelTableEmitter::HeaderData::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000366 OS << "DIE Offset Base: " << DieOffsetBase << "\n";
367 for (auto Atom : Atoms)
368 Atom.print(OS);
369}
370
Pavel Labatha7c457d2018-02-19 16:12:20 +0000371void AppleAccelTableEmitter::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000372 Header.print(OS);
373 HeaderData.print(OS);
Pavel Labatha7c457d2018-02-19 16:12:20 +0000374 Contents.print(OS);
375 SecBegin->print(OS, nullptr);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000376}
377
Pavel Labatha7c457d2018-02-19 16:12:20 +0000378void AccelTableBase::HashData::print(raw_ostream &OS) const {
Pavel Labath062eb532018-02-09 10:06:56 +0000379 OS << "Name: " << Name.getString() << "\n";
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000380 OS << " Hash Value: " << format("0x%x", HashValue) << "\n";
381 OS << " Symbol: ";
382 if (Sym)
383 OS << *Sym;
384 else
385 OS << "<none>";
386 OS << "\n";
Pavel Labath062eb532018-02-09 10:06:56 +0000387 for (auto *Value : Values)
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000388 Value->print(OS);
389}
390
Pavel Labatha7c457d2018-02-19 16:12:20 +0000391void AccelTableBase::print(raw_ostream &OS) const {
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000392 // Print Content.
393 OS << "Entries: \n";
394 for (const auto &Entry : Entries) {
395 OS << "Name: " << Entry.first() << "\n";
396 for (auto *V : Entry.second.Values)
397 V->print(OS);
398 }
399
400 OS << "Buckets and Hashes: \n";
401 for (auto &Bucket : Buckets)
402 for (auto &Hash : Bucket)
403 Hash->print(OS);
404
405 OS << "Data: \n";
Pavel Labath062eb532018-02-09 10:06:56 +0000406 for (auto &E : Entries)
407 E.second.print(OS);
Jonas Devlieghere1ce64dc2018-01-30 13:36:30 +0000408}
409
410void AppleAccelTableOffsetData::print(raw_ostream &OS) const {
411 OS << " Offset: " << Die->getOffset() << "\n";
412}
413
414void AppleAccelTableTypeData::print(raw_ostream &OS) const {
415 OS << " Offset: " << Die->getOffset() << "\n";
416 OS << " Tag: " << dwarf::TagString(Die->getTag()) << "\n";
417}
418
419void AppleAccelTableStaticOffsetData::print(raw_ostream &OS) const {
420 OS << " Static Offset: " << Offset << "\n";
421}
422
423void AppleAccelTableStaticTypeData::print(raw_ostream &OS) const {
424 OS << " Static Offset: " << Offset << "\n";
425 OS << " QualifiedNameHash: " << format("%x\n", QualifiedNameHash) << "\n";
426 OS << " Tag: " << dwarf::TagString(Tag) << "\n";
427 OS << " ObjCClassIsImplementation: "
428 << (ObjCClassIsImplementation ? "true" : "false");
429 OS << "\n";
430}
431#endif