LLVM 24.0.0git
AcceleratorRecordsSaver.cpp
Go to the documentation of this file.
1//=== AcceleratorRecordsSaver.cpp -----------------------------------------===//
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
12#include "llvm/Support/DJB.h"
13
14using namespace llvm;
15using namespace dwarf_linker;
16using namespace dwarf_linker::parallel;
17
19 int ChildRecurseDepth = 0) {
20 const char *Name = nullptr;
21 CompileUnit *CU = &InputCU;
22 std::optional<DWARFFormValue> RefVal;
23
24 if (Error Err = finiteLoop([&]() -> Expected<bool> {
25 if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
26 Name = CurrentName;
27
28 if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
29 !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
30 return false;
31
32 if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
33 return false;
34
35 std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference(
36 *RefVal, ResolveInterCUReferencesMode::Resolve);
37 if (!RefDie)
38 return false;
39
40 if (!RefDie->DieEntry)
41 return false;
42
43 CU = RefDie->CU;
44 InputDIE = RefDie->CU->getDIE(RefDie->DieEntry);
45 return true;
46 })) {
47 consumeError(std::move(Err));
48 }
49
50 if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
51 Name = "(anonymous namespace)";
52
53 DWARFDie ParentDie = InputDIE.getParent();
54 if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
55 return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));
56
57 return djbHash(
58 (Name ? Name : ""),
59 djbHash((Name ? "::" : ""),
60 hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth)));
61}
62
64 DIE *OutDIE, AttributesInfo &AttrInfo,
66 if (GlobalData.getOptions().AccelTables.empty())
67 return;
68
69 DWARFDie InputDIE = InUnit.getDIE(InputDieEntry);
70
71 // Look for short name recursively if short name is not known yet.
72 if (AttrInfo.Name == nullptr)
73 if (const char *ShortName = InputDIE.getShortName())
74 AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first;
75
76 switch (InputDieEntry->getTag()) {
77 case dwarf::DW_TAG_array_type:
78 case dwarf::DW_TAG_class_type:
79 case dwarf::DW_TAG_enumeration_type:
80 case dwarf::DW_TAG_pointer_type:
81 case dwarf::DW_TAG_reference_type:
82 case dwarf::DW_TAG_string_type:
83 case dwarf::DW_TAG_structure_type:
84 case dwarf::DW_TAG_subroutine_type:
85 case dwarf::DW_TAG_template_alias:
86 case dwarf::DW_TAG_typedef:
87 case dwarf::DW_TAG_union_type:
88 case dwarf::DW_TAG_ptr_to_member_type:
89 case dwarf::DW_TAG_set_type:
90 case dwarf::DW_TAG_subrange_type:
91 case dwarf::DW_TAG_base_type:
92 case dwarf::DW_TAG_const_type:
93 case dwarf::DW_TAG_constant:
94 case dwarf::DW_TAG_file_type:
95 case dwarf::DW_TAG_namelist:
96 case dwarf::DW_TAG_packed_type:
97 case dwarf::DW_TAG_volatile_type:
98 case dwarf::DW_TAG_restrict_type:
99 case dwarf::DW_TAG_atomic_type:
100 case dwarf::DW_TAG_interface_type:
101 case dwarf::DW_TAG_unspecified_type:
102 case dwarf::DW_TAG_shared_type:
103 case dwarf::DW_TAG_immutable_type:
104 case dwarf::DW_TAG_rvalue_reference_type: {
105 if (AttrInfo.IsDeclaration)
106 break;
107
108 // hashFullyQualifiedName() advances InputDIE along the specification and
109 // abstract origin chain, so the DIE's own attributes have to be read first.
110
111 // The linkage name may be attached to the declaration rather than to the
112 // definition.
113 if (!AttrInfo.MangledName)
114 if (const char *LinkageName = InputDIE.getLinkageName())
115 AttrInfo.MangledName =
116 GlobalData.getStringPool().insert(LinkageName).first;
117
118 uint64_t RuntimeLang =
119 dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
120 .value_or(0);
121
122 bool ObjCClassIsImplementation =
123 (RuntimeLang == dwarf::DW_LANG_ObjC ||
124 RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
125 dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
126 .value_or(0);
127
128 if (AttrInfo.Name != nullptr && !AttrInfo.Name->getKey().empty()) {
129 uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE);
130 saveTypeRecord(InputDieEntry, AttrInfo.Name, OutDIE,
131 InputDieEntry->getTag(), Hash, ObjCClassIsImplementation,
132 TypeEntry);
133 }
134
135 // Swift carries a type's mangled name in DW_AT_linkage_name, which a
136 // consumer may look up on its own.
137 if (AttrInfo.MangledName != nullptr &&
138 RuntimeLang == dwarf::DW_LANG_Swift &&
139 !AttrInfo.MangledName->getKey().empty() &&
140 AttrInfo.MangledName != AttrInfo.Name)
141 saveTypeRecord(InputDieEntry, AttrInfo.MangledName, OutDIE,
142 InputDieEntry->getTag(),
143 djbHash(AttrInfo.MangledName->getKey()),
144 ObjCClassIsImplementation, TypeEntry);
145 } break;
146 case dwarf::DW_TAG_namespace: {
147 if (AttrInfo.Name == nullptr)
148 AttrInfo.Name =
149 GlobalData.getStringPool().insert("(anonymous namespace)").first;
150
151 saveNamespaceRecord(InputDieEntry, AttrInfo.Name, OutDIE,
152 InputDieEntry->getTag(), TypeEntry);
153 } break;
154 case dwarf::DW_TAG_imported_declaration: {
155 if (AttrInfo.Name != nullptr)
156 saveNamespaceRecord(InputDieEntry, AttrInfo.Name, OutDIE,
157 InputDieEntry->getTag(), TypeEntry);
158 } break;
159 case dwarf::DW_TAG_compile_unit:
160 case dwarf::DW_TAG_lexical_block: {
161 // Nothing to do.
162 } break;
163 default:
164 // HasLiveAddress / HasRanges below decides whether a DIE carries enough
165 // information of its own to warrant a name record; the output unit is
166 // incidental and routed by the helpers.
167
168 if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
169 if (AttrInfo.Name)
171 InputDieEntry, AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
172 InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine,
173 TypeEntry);
174
175 // Look for mangled name recursively if mangled name is not known yet.
176 if (!AttrInfo.MangledName)
177 if (const char *LinkageName = InputDIE.getLinkageName())
178 AttrInfo.MangledName =
179 GlobalData.getStringPool().insert(LinkageName).first;
180
181 if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
182 saveNameRecord(InputDieEntry, AttrInfo.MangledName, OutDIE,
183 InputDieEntry->getTag(),
184 InputDieEntry->getTag() ==
185 dwarf::DW_TAG_inlined_subroutine,
186 TypeEntry);
187
188 // Strip template parameters from the short name.
189 if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name &&
190 (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
191 if (std::optional<StringRef> Name =
192 StripTemplateParameters(AttrInfo.Name->getKey())) {
193 StringEntry *NameWithoutTemplateParams =
194 GlobalData.getStringPool().insert(*Name).first;
195
196 saveNameRecord(InputDieEntry, NameWithoutTemplateParams, OutDIE,
197 InputDieEntry->getTag(), true, TypeEntry);
198 }
199 }
200
201 if (AttrInfo.Name)
202 saveObjC(InputDieEntry, OutDIE, AttrInfo, TypeEntry);
203 }
204 break;
205 }
206}
207
209 DIE *OutDIE, AttributesInfo &AttrInfo,
211 std::optional<ObjCSelectorNames> Names =
213 if (!Names)
214 return;
215
216 StringEntry *Selector =
217 GlobalData.getStringPool().insert(Names->Selector).first;
218 saveNameRecord(InputDieEntry, Selector, OutDIE, InputDieEntry->getTag(), true,
219 TypeEntry);
220 StringEntry *ClassName =
221 GlobalData.getStringPool().insert(Names->ClassName).first;
222 saveObjCNameRecord(InputDieEntry, ClassName, OutDIE, InputDieEntry->getTag(),
223 TypeEntry);
224 if (Names->ClassNameNoCategory) {
225 StringEntry *ClassNameNoCategory =
226 GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first;
227 saveObjCNameRecord(InputDieEntry, ClassNameNoCategory, OutDIE,
228 InputDieEntry->getTag(), TypeEntry);
229 }
230 if (Names->MethodNameNoCategory) {
231 StringEntry *MethodNameNoCategory =
232 GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first;
233 saveNameRecord(InputDieEntry, MethodNameNoCategory, OutDIE,
234 InputDieEntry->getTag(), true, TypeEntry);
235 }
236}
237
239 const DWARFDebugInfoEntry *InputDieEntry) {
240 // getDieOutOffset returns this for input DIEs that were not cloned into
241 // this CU's plain DWARF (e.g. routed only into the artificial type unit).
242 // OutDieOffsetArray is zero-initialized and a real DIE never lives at
243 // offset 0 (the CU header occupies the first bytes of the unit), so 0 is
244 // an unambiguous "no plain-DWARF copy" sentinel.
245 constexpr uint64_t NotClonedInPlainDWARF = 0;
246
247 std::optional<uint32_t> ParentIdx = InputDieEntry->getParentIdx();
248 if (!ParentIdx)
249 return std::nullopt;
250 // Skip parents marked as declarations; the name table should only reference
251 // definitions.
252 if (dwarf::toUnsigned(InUnit.find(*ParentIdx, dwarf::DW_AT_declaration), 0))
253 return std::nullopt;
254 uint64_t ParentOutOffset = InUnit.getDieOutOffset(*ParentIdx);
255 if (ParentOutOffset == NotClonedInPlainDWARF)
256 return std::nullopt;
257 return ParentOutOffset;
258}
259
261 const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE,
262 dwarf::Tag Tag, bool AvoidForPubSections, TypeEntry *TypeEntry) {
263 if (OutUnit.isCompileUnit()) {
264 assert(TypeEntry == nullptr);
266
268 Info.String = Name;
269 Info.OutOffset = OutDIE->getOffset();
270 Info.ParentOffset = getDefiningParentOutOffset(InputDieEntry);
271 Info.Tag = Tag;
272 Info.AvoidForPubSections = AvoidForPubSections;
273
274 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
275 return;
276 }
277
278 // TODO: compute DW_IDX_parent for entries emitted into the artificial type
279 // unit (see saveNamespaceRecord).
280
281 assert(TypeEntry != nullptr);
284 Info.String = Name;
285 Info.OutOffset = 0xbaddef;
286 Info.Tag = Tag;
287 Info.AvoidForPubSections = AvoidForPubSections;
288 Info.OutDIE = OutDIE;
289 Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
290
291 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
292}
294 const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE,
296 if (OutUnit.isCompileUnit()) {
297 assert(TypeEntry == nullptr);
299
301 Info.String = Name;
302 Info.OutOffset = OutDIE->getOffset();
303 Info.ParentOffset = getDefiningParentOutOffset(InputDieEntry);
304 Info.Tag = Tag;
305
306 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
307 return;
308 }
309
310 // TODO: compute DW_IDX_parent for entries emitted into the artificial type
311 // unit. The parent lookup via the input-side DIE tree is only valid for
312 // DIEs cloned into this CU's plain DWARF.
313
314 assert(TypeEntry != nullptr);
317 Info.String = Name;
318 Info.OutOffset = 0xbaddef;
319 Info.Tag = Tag;
320 Info.OutDIE = OutDIE;
321 Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
322
323 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
324}
325
327 const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE,
329 if (OutUnit.isCompileUnit()) {
330 assert(TypeEntry == nullptr);
332
334 Info.String = Name;
335 Info.OutOffset = OutDIE->getOffset();
336 Info.ParentOffset = getDefiningParentOutOffset(InputDieEntry);
337 Info.Tag = Tag;
338 Info.AvoidForPubSections = true;
339
340 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
341 return;
342 }
343
344 // TODO: compute DW_IDX_parent for entries emitted into the artificial type
345 // unit (see saveNamespaceRecord).
346
347 assert(TypeEntry != nullptr);
350 Info.String = Name;
351 Info.OutOffset = 0xbaddef;
352 Info.Tag = Tag;
353 Info.AvoidForPubSections = true;
354 Info.OutDIE = OutDIE;
355 Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
356
357 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
358}
359
361 const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE,
362 dwarf::Tag Tag, uint32_t QualifiedNameHash, bool ObjcClassImplementation,
364 if (OutUnit.isCompileUnit()) {
365 assert(TypeEntry == nullptr);
367
369 Info.String = Name;
370 Info.OutOffset = OutDIE->getOffset();
371 Info.ParentOffset = getDefiningParentOutOffset(InputDieEntry);
372 Info.Tag = Tag;
373 Info.QualifiedNameHash = QualifiedNameHash;
374 Info.ObjcClassImplementation = ObjcClassImplementation;
375
376 OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
377 return;
378 }
379
380 // TODO: compute DW_IDX_parent for entries emitted into the artificial type
381 // unit (see saveNamespaceRecord).
382
383 assert(TypeEntry != nullptr);
385
387 Info.String = Name;
388 Info.OutOffset = 0xbaddef;
389 Info.Tag = Tag;
390 Info.QualifiedNameHash = QualifiedNameHash;
391 Info.ObjcClassImplementation = ObjcClassImplementation;
392 Info.OutDIE = OutDIE;
393 Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
394 OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
395}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE, int ChildRecurseDepth=0)
A structured debug information entry.
Definition DIE.h:840
unsigned getOffset() const
Get the compile/type unit relative offset of this DIE.
Definition DIE.h:878
DWARFDebugInfoEntry - A DIE with only the minimum required data.
std::optional< uint32_t > getParentIdx() const
Returns index of the parent die.
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition DWARFDie.h:43
LLVM_ABI const char * getShortName() const
Return the DIE short name resolving DW_AT_specification or DW_AT_abstract_origin references if necess...
Definition DWARFDie.cpp:553
LLVM_ABI DWARFDie getParent() const
Get the parent of this DIE object.
Definition DWARFDie.cpp:736
LLVM_ABI std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
Definition DWARFDie.cpp:317
LLVM_ABI const char * getName(DINameKind Kind) const
Return the DIE name resolving DW_AT_specification or DW_AT_abstract_origin references if necessary.
Definition DWARFDie.cpp:542
dwarf::Tag getTag() const
Definition DWARFDie.h:73
LLVM_ABI const char * getLinkageName() const
Return the DIE linkage name resolving DW_AT_specification or DW_AT_abstract_origin references if nece...
Definition DWARFDie.cpp:560
bool isValid() const
Definition DWARFDie.h:52
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Tagged union holding either a T or a Error.
Definition Error.h:485
StringRef getKey() const
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Stores all information relating to a compile unit, be it in its original instance in the object file ...
CompileUnit & InUnit
Comiple unit corresponding to input DWARF.
void saveObjCNameRecord(const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, TypeEntry *TypeEntry)
void saveNameRecord(const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, bool AvoidForPubSections, TypeEntry *TypeEntry)
CompileUnit::OutputUnitVariantPtr OutUnit
Compile unit or Artificial type unit corresponding to the output DWARF.
std::optional< uint64_t > getDefiningParentOutOffset(const DWARFDebugInfoEntry *InputDieEntry)
Return the output offset of InputDieEntry's immediate non-declaration parent, for use as the DW_IDX_p...
void saveTypeRecord(const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, uint32_t QualifiedNameHash, bool ObjcClassImplementation, TypeEntry *TypeEntry)
void save(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE, AttributesInfo &AttrInfo, TypeEntry *TypeEntry)
Save accelerator info for the specified OutDIE inside OutUnit.
void saveNamespaceRecord(const DWARFDebugInfoEntry *InputDieEntry, StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, TypeEntry *TypeEntry)
void saveObjC(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE, AttributesInfo &AttrInfo, TypeEntry *TypeEntry)
StringMapEntry< std::atomic< TypeEntryBody * > > TypeEntry
Definition TypePool.h:28
StringMapEntry< EmptyStringSetTag > StringEntry
StringEntry keeps data of the string: the length, external offset and a string body which is placed r...
Definition StringPool.h:23
Error finiteLoop(function_ref< Expected< bool >()> Iteration, size_t MaxCounter=100000)
This function calls Iteration() until it returns false.
Definition Utils.h:44
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::optional< StringRef > StripTemplateParameters(StringRef Name)
If Name is the name of a templated function that includes template parameters, returns a substring of...
uint32_t djbHash(StringRef Buffer, uint32_t H=5381)
The Bernstein hash function used by the DWARF accelerator tables.
Definition DJB.h:22
LLVM_ABI std::optional< ObjCSelectorNames > getObjCNamesIfSelector(StringRef Name)
If Name is the AT_name of a DIE which refers to an Objective-C selector, returns an instance of ObjCS...
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
Information gathered and exchanged between the various clone*Attr helpers about the attributes of a p...
bool IsDeclaration
Is this DIE only a declaration?
bool HasRanges
Does the DIE have a ranges attribute?
bool HasLiveAddress
Does the DIE have an address pointing to live code section?
This structure keeps fields which would be used for creating accelerator table.
AccelType Type
Type of this accelerator record.
TypeUnitAccelInfo extends AccelInfo structure with type specific fields.