Skip to content

[DWARFLinkerParallel] Add support for -odr mode. #68721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 295 additions & 0 deletions llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
//=== AcceleratorRecordsSaver.cpp -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "AcceleratorRecordsSaver.h"
#include "Utils.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
#include "llvm/Support/DJB.h"

namespace llvm {
namespace dwarflinker_parallel {

static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE,
int ChildRecurseDepth = 0) {
const char *Name = nullptr;
CompileUnit *CU = &InputCU;
std::optional<DWARFFormValue> RefVal;

if (Error Err = finiteLoop([&]() -> Expected<bool> {
if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
Name = CurrentName;

if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
!(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
return false;

if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
return false;

std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference(
*RefVal, ResolveInterCUReferencesMode::Resolve);
if (!RefDie)
return false;

if (!RefDie->DieEntry)
return false;

CU = RefDie->CU;
InputDIE = RefDie->CU->getDIE(RefDie->DieEntry);
return true;
})) {
consumeError(std::move(Err));
}

if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
Name = "(anonymous namespace)";

DWARFDie ParentDie = InputDIE.getParent();
if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));

return djbHash(
(Name ? Name : ""),
djbHash((Name ? "::" : ""),
hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth)));
}

void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry,
DIE *OutDIE, AttributesInfo &AttrInfo,
TypeEntry *TypeEntry) {
if (GlobalData.getOptions().AccelTables.empty())
return;

DWARFDie InputDIE = InUnit.getDIE(InputDieEntry);

// Look for short name recursively if short name is not known yet.
if (AttrInfo.Name == nullptr)
if (const char *ShortName = InputDIE.getShortName())
AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first;

switch (InputDieEntry->getTag()) {
case dwarf::DW_TAG_array_type:
case dwarf::DW_TAG_class_type:
case dwarf::DW_TAG_enumeration_type:
case dwarf::DW_TAG_pointer_type:
case dwarf::DW_TAG_reference_type:
case dwarf::DW_TAG_string_type:
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_subroutine_type:
case dwarf::DW_TAG_typedef:
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_ptr_to_member_type:
case dwarf::DW_TAG_set_type:
case dwarf::DW_TAG_subrange_type:
case dwarf::DW_TAG_base_type:
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_constant:
case dwarf::DW_TAG_file_type:
case dwarf::DW_TAG_namelist:
case dwarf::DW_TAG_packed_type:
case dwarf::DW_TAG_volatile_type:
case dwarf::DW_TAG_restrict_type:
case dwarf::DW_TAG_atomic_type:
case dwarf::DW_TAG_interface_type:
case dwarf::DW_TAG_unspecified_type:
case dwarf::DW_TAG_shared_type:
case dwarf::DW_TAG_immutable_type:
case dwarf::DW_TAG_rvalue_reference_type: {
if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr &&
!AttrInfo.Name->getKey().empty()) {
uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE);

uint64_t RuntimeLang =
dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
.value_or(0);

bool ObjCClassIsImplementation =
(RuntimeLang == dwarf::DW_LANG_ObjC ||
RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
dwarf::toUnsigned(
InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
.value_or(0);

saveTypeRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), Hash,
ObjCClassIsImplementation, TypeEntry);
}
} break;
case dwarf::DW_TAG_namespace: {
if (AttrInfo.Name == nullptr)
AttrInfo.Name =
GlobalData.getStringPool().insert("(anonymous namespace)").first;

saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
TypeEntry);
} break;
case dwarf::DW_TAG_imported_declaration: {
if (AttrInfo.Name != nullptr)
saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
TypeEntry);
} break;
case dwarf::DW_TAG_compile_unit:
case dwarf::DW_TAG_lexical_block: {
// Nothing to do.
} break;
default:
if (TypeEntry)
// Do not store this kind of accelerator entries for type entries.
return;

if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
if (AttrInfo.Name)
saveNameRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
InputDieEntry->getTag() ==
dwarf::DW_TAG_inlined_subroutine);

// Look for mangled name recursively if mangled name is not known yet.
if (!AttrInfo.MangledName)
if (const char *LinkageName = InputDIE.getLinkageName())
AttrInfo.MangledName =
GlobalData.getStringPool().insert(LinkageName).first;

if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
saveNameRecord(AttrInfo.MangledName, OutDIE, InputDieEntry->getTag(),
InputDieEntry->getTag() ==
dwarf::DW_TAG_inlined_subroutine);

// Strip template parameters from the short name.
if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name &&
(InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
if (std::optional<StringRef> Name =
StripTemplateParameters(AttrInfo.Name->getKey())) {
StringEntry *NameWithoutTemplateParams =
GlobalData.getStringPool().insert(*Name).first;

saveNameRecord(NameWithoutTemplateParams, OutDIE,
InputDieEntry->getTag(), true);
}
}

if (AttrInfo.Name)
saveObjC(InputDieEntry, OutDIE, AttrInfo);
}
break;
}
}

void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry,
DIE *OutDIE, AttributesInfo &AttrInfo) {
std::optional<ObjCSelectorNames> Names =
getObjCNamesIfSelector(AttrInfo.Name->getKey());
if (!Names)
return;

StringEntry *Selector =
GlobalData.getStringPool().insert(Names->Selector).first;
saveNameRecord(Selector, OutDIE, InputDieEntry->getTag(), true);
StringEntry *ClassName =
GlobalData.getStringPool().insert(Names->ClassName).first;
saveObjCNameRecord(ClassName, OutDIE, InputDieEntry->getTag());
if (Names->ClassNameNoCategory) {
StringEntry *ClassNameNoCategory =
GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first;
saveObjCNameRecord(ClassNameNoCategory, OutDIE, InputDieEntry->getTag());
}
if (Names->MethodNameNoCategory) {
StringEntry *MethodNameNoCategory =
GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first;
saveNameRecord(MethodNameNoCategory, OutDIE, InputDieEntry->getTag(), true);
}
}

void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE,
dwarf::Tag Tag,
bool AvoidForPubSections) {
DwarfUnit::AccelInfo Info;

Info.Type = DwarfUnit::AccelType::Name;
Info.String = Name;
Info.OutOffset = OutDIE->getOffset();
Info.Tag = Tag;
Info.AvoidForPubSections = AvoidForPubSections;

OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
}
void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry *Name,
DIE *OutDIE, dwarf::Tag Tag,
TypeEntry *TypeEntry) {
if (OutUnit.isCompileUnit()) {
assert(TypeEntry == nullptr);
DwarfUnit::AccelInfo Info;

Info.Type = DwarfUnit::AccelType::Namespace;
Info.String = Name;
Info.OutOffset = OutDIE->getOffset();
Info.Tag = Tag;

OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
return;
}

assert(TypeEntry != nullptr);
TypeUnit::TypeUnitAccelInfo Info;
Info.Type = DwarfUnit::AccelType::Namespace;
Info.String = Name;
Info.OutOffset = 0xbaddef;
Info.Tag = Tag;
Info.OutDIE = OutDIE;
Info.TypeEntryBodyPtr = TypeEntry->getValue().load();

OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
}

void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE,
dwarf::Tag Tag) {
DwarfUnit::AccelInfo Info;

Info.Type = DwarfUnit::AccelType::ObjC;
Info.String = Name;
Info.OutOffset = OutDIE->getOffset();
Info.Tag = Tag;
Info.AvoidForPubSections = true;

OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
}

void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE,
dwarf::Tag Tag,
uint32_t QualifiedNameHash,
bool ObjcClassImplementation,
TypeEntry *TypeEntry) {
if (OutUnit.isCompileUnit()) {
assert(TypeEntry == nullptr);
DwarfUnit::AccelInfo Info;

Info.Type = DwarfUnit::AccelType::Type;
Info.String = Name;
Info.OutOffset = OutDIE->getOffset();
Info.Tag = Tag;
Info.QualifiedNameHash = QualifiedNameHash;
Info.ObjcClassImplementation = ObjcClassImplementation;

OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
return;
}

assert(TypeEntry != nullptr);
TypeUnit::TypeUnitAccelInfo Info;

Info.Type = DwarfUnit::AccelType::Type;
Info.String = Name;
Info.OutOffset = 0xbaddef;
Info.Tag = Tag;
Info.QualifiedNameHash = QualifiedNameHash;
Info.ObjcClassImplementation = ObjcClassImplementation;
Info.OutDIE = OutDIE;
Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
}

} // end of namespace dwarflinker_parallel
} // namespace llvm
70 changes: 70 additions & 0 deletions llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//===- AcceleratorRecordsSaver.h --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
#define LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H

#include "DIEAttributeCloner.h"
#include "DWARFLinkerCompileUnit.h"
#include "DWARFLinkerGlobalData.h"
#include "DWARFLinkerTypeUnit.h"

namespace llvm {
namespace dwarflinker_parallel {

/// This class helps to store information for accelerator entries.
/// It prepares accelerator info for the certain DIE and store it inside
/// OutUnit.
class AcceleratorRecordsSaver {
public:
AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
CompileUnit *OutUnit)
: AcceleratorRecordsSaver(GlobalData, InUnit,
CompileUnit::OutputUnitVariantPtr(OutUnit)) {}

AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
TypeUnit *OutUnit)
: AcceleratorRecordsSaver(GlobalData, InUnit,
CompileUnit::OutputUnitVariantPtr(OutUnit)) {}

/// Save accelerator info for the specified \p OutDIE inside OutUnit.
/// Side effects: set attributes in \p AttrInfo.
void save(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
AttributesInfo &AttrInfo, TypeEntry *TypeEntry);

protected:
AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
CompileUnit::OutputUnitVariantPtr OutUnit)
: GlobalData(GlobalData), InUnit(InUnit), OutUnit(OutUnit) {}

void saveObjC(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
AttributesInfo &AttrInfo);

void saveNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
bool AvoidForPubSections);
void saveNamespaceRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
TypeEntry *TypeEntry);
void saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag);
void saveTypeRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
uint32_t QualifiedNameHash, bool ObjcClassImplementation,
TypeEntry *TypeEntry);

/// Global linking data.
LinkingGlobalData &GlobalData;

/// Comiple unit corresponding to input DWARF.
CompileUnit &InUnit;

/// Compile unit or Artificial type unit corresponding to the output DWARF.
CompileUnit::OutputUnitVariantPtr OutUnit;
};

} // end of namespace dwarflinker_parallel
} // end namespace llvm

#endif // LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
Loading