Skip to content

Commit 66b03b2

Browse files
committed
[DWARFLinkerParallel] Add support for -odr mode.
This patch is extracted from D96035, it adds support for the type deduplication mode. With this patch DWARFLinkerParallel handles --odr option. It also processes clang modules.
1 parent 48f5855 commit 66b03b2

File tree

77 files changed

+9062
-1119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+9062
-1119
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
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+
9+
#include "AcceleratorRecordsSaver.h"
10+
#include "Utils.h"
11+
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
12+
#include "llvm/Support/DJB.h"
13+
14+
namespace llvm {
15+
namespace dwarflinker_parallel {
16+
17+
static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE,
18+
int ChildRecurseDepth = 0) {
19+
const char *Name = nullptr;
20+
CompileUnit *CU = &InputCU;
21+
std::optional<DWARFFormValue> RefVal;
22+
23+
if (Error Err = finiteLoop([&]() -> Expected<bool> {
24+
if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
25+
Name = CurrentName;
26+
27+
if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
28+
!(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
29+
return false;
30+
31+
if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
32+
return false;
33+
34+
std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference(
35+
*RefVal, ResolveInterCUReferencesMode::Resolve);
36+
if (!RefDie)
37+
return false;
38+
39+
if (!RefDie->DieEntry)
40+
return false;
41+
42+
CU = RefDie->CU;
43+
InputDIE = RefDie->CU->getDIE(RefDie->DieEntry);
44+
return true;
45+
})) {
46+
consumeError(std::move(Err));
47+
}
48+
49+
if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
50+
Name = "(anonymous namespace)";
51+
52+
DWARFDie ParentDie = InputDIE.getParent();
53+
if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
54+
return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));
55+
56+
return djbHash(
57+
(Name ? Name : ""),
58+
djbHash((Name ? "::" : ""),
59+
hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth)));
60+
}
61+
62+
void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry,
63+
DIE *OutDIE, AttributesInfo &AttrInfo,
64+
TypeEntry *TypeEntry) {
65+
if (GlobalData.getOptions().AccelTables.empty())
66+
return;
67+
68+
DWARFDie InputDIE = InUnit.getDIE(InputDieEntry);
69+
70+
// Look for short name recursively if short name is not known yet.
71+
if (AttrInfo.Name == nullptr)
72+
if (const char *ShortName = InputDIE.getShortName())
73+
AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first;
74+
75+
switch (InputDieEntry->getTag()) {
76+
case dwarf::DW_TAG_array_type:
77+
case dwarf::DW_TAG_class_type:
78+
case dwarf::DW_TAG_enumeration_type:
79+
case dwarf::DW_TAG_pointer_type:
80+
case dwarf::DW_TAG_reference_type:
81+
case dwarf::DW_TAG_string_type:
82+
case dwarf::DW_TAG_structure_type:
83+
case dwarf::DW_TAG_subroutine_type:
84+
case dwarf::DW_TAG_typedef:
85+
case dwarf::DW_TAG_union_type:
86+
case dwarf::DW_TAG_ptr_to_member_type:
87+
case dwarf::DW_TAG_set_type:
88+
case dwarf::DW_TAG_subrange_type:
89+
case dwarf::DW_TAG_base_type:
90+
case dwarf::DW_TAG_const_type:
91+
case dwarf::DW_TAG_constant:
92+
case dwarf::DW_TAG_file_type:
93+
case dwarf::DW_TAG_namelist:
94+
case dwarf::DW_TAG_packed_type:
95+
case dwarf::DW_TAG_volatile_type:
96+
case dwarf::DW_TAG_restrict_type:
97+
case dwarf::DW_TAG_atomic_type:
98+
case dwarf::DW_TAG_interface_type:
99+
case dwarf::DW_TAG_unspecified_type:
100+
case dwarf::DW_TAG_shared_type:
101+
case dwarf::DW_TAG_immutable_type:
102+
case dwarf::DW_TAG_rvalue_reference_type: {
103+
if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr &&
104+
!AttrInfo.Name->getKey().empty()) {
105+
uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE);
106+
107+
uint64_t RuntimeLang =
108+
dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
109+
.value_or(0);
110+
111+
bool ObjCClassIsImplementation =
112+
(RuntimeLang == dwarf::DW_LANG_ObjC ||
113+
RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
114+
dwarf::toUnsigned(
115+
InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
116+
.value_or(0);
117+
118+
saveTypeRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), Hash,
119+
ObjCClassIsImplementation, TypeEntry);
120+
}
121+
} break;
122+
case dwarf::DW_TAG_namespace: {
123+
if (AttrInfo.Name == nullptr)
124+
AttrInfo.Name =
125+
GlobalData.getStringPool().insert("(anonymous namespace)").first;
126+
127+
saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
128+
TypeEntry);
129+
} break;
130+
case dwarf::DW_TAG_imported_declaration: {
131+
if (AttrInfo.Name != nullptr)
132+
saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
133+
TypeEntry);
134+
} break;
135+
case dwarf::DW_TAG_compile_unit:
136+
case dwarf::DW_TAG_lexical_block: {
137+
// Nothing to do.
138+
} break;
139+
default:
140+
if (TypeEntry)
141+
// Do not store this kind of accelerator entries for type entries.
142+
return;
143+
144+
if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
145+
if (AttrInfo.Name)
146+
saveNameRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
147+
InputDieEntry->getTag() ==
148+
dwarf::DW_TAG_inlined_subroutine);
149+
150+
// Look for mangled name recursively if mangled name is not known yet.
151+
if (!AttrInfo.MangledName)
152+
if (const char *LinkageName = InputDIE.getLinkageName())
153+
AttrInfo.MangledName =
154+
GlobalData.getStringPool().insert(LinkageName).first;
155+
156+
if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
157+
saveNameRecord(AttrInfo.MangledName, OutDIE, InputDieEntry->getTag(),
158+
InputDieEntry->getTag() ==
159+
dwarf::DW_TAG_inlined_subroutine);
160+
161+
// Strip template parameters from the short name.
162+
if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name &&
163+
(InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
164+
if (std::optional<StringRef> Name =
165+
StripTemplateParameters(AttrInfo.Name->getKey())) {
166+
StringEntry *NameWithoutTemplateParams =
167+
GlobalData.getStringPool().insert(*Name).first;
168+
169+
saveNameRecord(NameWithoutTemplateParams, OutDIE,
170+
InputDieEntry->getTag(), true);
171+
}
172+
}
173+
174+
if (AttrInfo.Name)
175+
saveObjC(InputDieEntry, OutDIE, AttrInfo);
176+
}
177+
break;
178+
}
179+
}
180+
181+
void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry,
182+
DIE *OutDIE, AttributesInfo &AttrInfo) {
183+
std::optional<ObjCSelectorNames> Names =
184+
getObjCNamesIfSelector(AttrInfo.Name->getKey());
185+
if (!Names)
186+
return;
187+
188+
StringEntry *Selector =
189+
GlobalData.getStringPool().insert(Names->Selector).first;
190+
saveNameRecord(Selector, OutDIE, InputDieEntry->getTag(), true);
191+
StringEntry *ClassName =
192+
GlobalData.getStringPool().insert(Names->ClassName).first;
193+
saveObjCNameRecord(ClassName, OutDIE, InputDieEntry->getTag());
194+
if (Names->ClassNameNoCategory) {
195+
StringEntry *ClassNameNoCategory =
196+
GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first;
197+
saveObjCNameRecord(ClassNameNoCategory, OutDIE, InputDieEntry->getTag());
198+
}
199+
if (Names->MethodNameNoCategory) {
200+
StringEntry *MethodNameNoCategory =
201+
GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first;
202+
saveNameRecord(MethodNameNoCategory, OutDIE, InputDieEntry->getTag(), true);
203+
}
204+
}
205+
206+
void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE,
207+
dwarf::Tag Tag,
208+
bool AvoidForPubSections) {
209+
DwarfUnit::AccelInfo Info;
210+
211+
Info.Type = DwarfUnit::AccelType::Name;
212+
Info.String = Name;
213+
Info.OutOffset = OutDIE->getOffset();
214+
Info.Tag = Tag;
215+
Info.AvoidForPubSections = AvoidForPubSections;
216+
217+
OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
218+
}
219+
void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry *Name,
220+
DIE *OutDIE, dwarf::Tag Tag,
221+
TypeEntry *TypeEntry) {
222+
if (OutUnit.isCompileUnit()) {
223+
assert(TypeEntry == nullptr);
224+
DwarfUnit::AccelInfo Info;
225+
226+
Info.Type = DwarfUnit::AccelType::Namespace;
227+
Info.String = Name;
228+
Info.OutOffset = OutDIE->getOffset();
229+
Info.Tag = Tag;
230+
231+
OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
232+
return;
233+
}
234+
235+
assert(TypeEntry != nullptr);
236+
TypeUnit::TypeUnitAccelInfo Info;
237+
Info.Type = DwarfUnit::AccelType::Namespace;
238+
Info.String = Name;
239+
Info.OutOffset = 0xbaddef;
240+
Info.Tag = Tag;
241+
Info.OutDIE = OutDIE;
242+
Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
243+
244+
OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
245+
}
246+
247+
void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE,
248+
dwarf::Tag Tag) {
249+
DwarfUnit::AccelInfo Info;
250+
251+
Info.Type = DwarfUnit::AccelType::ObjC;
252+
Info.String = Name;
253+
Info.OutOffset = OutDIE->getOffset();
254+
Info.Tag = Tag;
255+
Info.AvoidForPubSections = true;
256+
257+
OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
258+
}
259+
260+
void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE,
261+
dwarf::Tag Tag,
262+
uint32_t QualifiedNameHash,
263+
bool ObjcClassImplementation,
264+
TypeEntry *TypeEntry) {
265+
if (OutUnit.isCompileUnit()) {
266+
assert(TypeEntry == nullptr);
267+
DwarfUnit::AccelInfo Info;
268+
269+
Info.Type = DwarfUnit::AccelType::Type;
270+
Info.String = Name;
271+
Info.OutOffset = OutDIE->getOffset();
272+
Info.Tag = Tag;
273+
Info.QualifiedNameHash = QualifiedNameHash;
274+
Info.ObjcClassImplementation = ObjcClassImplementation;
275+
276+
OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
277+
return;
278+
}
279+
280+
assert(TypeEntry != nullptr);
281+
TypeUnit::TypeUnitAccelInfo Info;
282+
283+
Info.Type = DwarfUnit::AccelType::Type;
284+
Info.String = Name;
285+
Info.OutOffset = 0xbaddef;
286+
Info.Tag = Tag;
287+
Info.QualifiedNameHash = QualifiedNameHash;
288+
Info.ObjcClassImplementation = ObjcClassImplementation;
289+
Info.OutDIE = OutDIE;
290+
Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
291+
OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
292+
}
293+
294+
} // end of namespace dwarflinker_parallel
295+
} // namespace llvm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//===- AcceleratorRecordsSaver.h --------------------------------*- C++ -*-===//
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+
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
10+
#define LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
11+
12+
#include "DIEAttributeCloner.h"
13+
#include "DWARFLinkerCompileUnit.h"
14+
#include "DWARFLinkerGlobalData.h"
15+
#include "DWARFLinkerTypeUnit.h"
16+
17+
namespace llvm {
18+
namespace dwarflinker_parallel {
19+
20+
/// This class helps to store information for accelerator entries.
21+
/// It prepares accelerator info for the certain DIE and store it inside
22+
/// OutUnit.
23+
class AcceleratorRecordsSaver {
24+
public:
25+
AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
26+
CompileUnit *OutUnit)
27+
: AcceleratorRecordsSaver(GlobalData, InUnit,
28+
CompileUnit::OutputUnitVariantPtr(OutUnit)) {}
29+
30+
AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
31+
TypeUnit *OutUnit)
32+
: AcceleratorRecordsSaver(GlobalData, InUnit,
33+
CompileUnit::OutputUnitVariantPtr(OutUnit)) {}
34+
35+
/// Save accelerator info for the specified \p OutDIE inside OutUnit.
36+
/// Side effects: set attributes in \p AttrInfo.
37+
void save(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
38+
AttributesInfo &AttrInfo, TypeEntry *TypeEntry);
39+
40+
protected:
41+
AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
42+
CompileUnit::OutputUnitVariantPtr OutUnit)
43+
: GlobalData(GlobalData), InUnit(InUnit), OutUnit(OutUnit) {}
44+
45+
void saveObjC(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
46+
AttributesInfo &AttrInfo);
47+
48+
void saveNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
49+
bool AvoidForPubSections);
50+
void saveNamespaceRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
51+
TypeEntry *TypeEntry);
52+
void saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag);
53+
void saveTypeRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
54+
uint32_t QualifiedNameHash, bool ObjcClassImplementation,
55+
TypeEntry *TypeEntry);
56+
57+
/// Global linking data.
58+
LinkingGlobalData &GlobalData;
59+
60+
/// Comiple unit corresponding to input DWARF.
61+
CompileUnit &InUnit;
62+
63+
/// Compile unit or Artificial type unit corresponding to the output DWARF.
64+
CompileUnit::OutputUnitVariantPtr OutUnit;
65+
};
66+
67+
} // end of namespace dwarflinker_parallel
68+
} // end namespace llvm
69+
70+
#endif // LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H

0 commit comments

Comments
 (0)