Skip to content

Commit

Permalink
[DWARFLinkerParallel] Add support for -odr mode.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
avl-llvm committed Nov 22, 2023
1 parent 48f5855 commit 66b03b2
Show file tree
Hide file tree
Showing 77 changed files with 9,062 additions and 1,119 deletions.
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

0 comments on commit 66b03b2

Please sign in to comment.