Skip to content

Commit

Permalink
[DWARFLinkerParallel] Add support for -odr mode. (#68721)
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 23, 2023
1 parent 272812c commit b61ac4a
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 b61ac4a

Please sign in to comment.