[llvm] b61ac4a - [DWARFLinkerParallel] Add support for -odr mode. (#68721)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 23 02:56:40 PST 2023
Author: avl-llvm
Date: 2023-11-23T13:56:34+03:00
New Revision: b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d
URL: https://github.com/llvm/llvm-project/commit/b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d
DIFF: https://github.com/llvm/llvm-project/commit/b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d.diff
LOG: [DWARFLinkerParallel] Add support for -odr mode. (#68721)
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.
Added:
llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
llvm/lib/DWARFLinkerParallel/TypePool.h
llvm/lib/DWARFLinkerParallel/Utils.h
llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o
llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o
llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o
llvm/test/tools/dsymutil/X86/Inputs/String/main.o
llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test
Modified:
llvm/lib/DWARFLinkerParallel/ArrayList.h
llvm/lib/DWARFLinkerParallel/CMakeLists.txt
llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
llvm/lib/DWARFLinkerParallel/DIEGenerator.h
llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
llvm/lib/DWARFLinkerParallel/DependencyTracker.h
llvm/lib/DWARFLinkerParallel/OutputSections.cpp
llvm/lib/DWARFLinkerParallel/OutputSections.h
llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
llvm/test/tools/dsymutil/X86/dead-stripped.cpp
llvm/test/tools/dsymutil/X86/dummy-debug-map.map
llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
llvm/test/tools/dsymutil/X86/empty-CU.test
llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
llvm/test/tools/dsymutil/X86/keep-func.test
llvm/test/tools/dsymutil/X86/location-expression.test
llvm/test/tools/dsymutil/X86/modules-empty.m
llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
llvm/test/tools/dsymutil/X86/op-convert.test
llvm/test/tools/dsymutil/X86/union-fwd-decl.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
Removed:
################################################################################
diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
new file mode 100644
index 000000000000000..5ec25cfe5fd26e1
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
@@ -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
diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
new file mode 100644
index 000000000000000..5e7f4d0c3166fd1
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
@@ -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
diff --git a/llvm/lib/DWARFLinkerParallel/ArrayList.h b/llvm/lib/DWARFLinkerParallel/ArrayList.h
index 58d550982c8dfc0..def83f91bc6f319 100644
--- a/llvm/lib/DWARFLinkerParallel/ArrayList.h
+++ b/llvm/lib/DWARFLinkerParallel/ArrayList.h
@@ -21,6 +21,9 @@ namespace dwarflinker_parallel {
/// Method add() can be called asynchronously.
template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
public:
+ ArrayList(parallel::PerThreadBumpPtrAllocator *Allocator)
+ : Allocator(Allocator) {}
+
/// Add specified \p Item to the list.
T &add(const T &Item) {
assert(Allocator);
@@ -73,8 +76,27 @@ template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
LastGroup = nullptr;
}
- void setAllocator(parallel::PerThreadBumpPtrAllocator *Allocator) {
- this->Allocator = Allocator;
+ void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) {
+ SmallVector<T> SortedItems;
+ forEach([&](T &Item) { SortedItems.push_back(Item); });
+
+ if (SortedItems.size()) {
+ std::sort(SortedItems.begin(), SortedItems.end(), Comparator);
+
+ size_t SortedItemIdx = 0;
+ forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });
+ assert(SortedItemIdx == SortedItems.size());
+ }
+ }
+
+ size_t size() {
+ size_t Result = 0;
+
+ for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
+ CurGroup = CurGroup->Next)
+ Result += CurGroup->getItemsCount();
+
+ return Result;
}
protected:
diff --git a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
index d321ecf8d5ce847..b0f0b3910e586ab 100644
--- a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
+++ b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
@@ -1,14 +1,17 @@
add_llvm_component_library(LLVMDWARFLinkerParallel
+ AcceleratorRecordsSaver.cpp
DependencyTracker.cpp
DIEAttributeCloner.cpp
DWARFEmitterImpl.cpp
DWARFFile.cpp
DWARFLinker.cpp
DWARFLinkerCompileUnit.cpp
+ DWARFLinkerTypeUnit.cpp
DWARFLinkerImpl.cpp
DWARFLinkerUnit.cpp
OutputSections.cpp
StringPool.cpp
+ SyntheticTypeNameBuilder.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/DWARFLinkerParallel
diff --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
index d05fd8d61b85743..81fc57f7cabbb79 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
@@ -13,18 +13,16 @@ namespace llvm {
namespace dwarflinker_parallel {
void DIEAttributeCloner::clone() {
- DWARFUnit &U = CU.getOrigUnit();
-
// Extract and clone every attribute.
- DWARFDataExtractor Data = U.getDebugInfoExtractor();
+ DWARFDataExtractor Data = InUnit.getOrigUnit().getDebugInfoExtractor();
uint64_t Offset = InputDieEntry->getOffset();
// Point to the next DIE (generally there is always at least a NULL
// entry after the current one). If this is a lone
// DW_TAG_compile_unit without any children, point to the next unit.
- uint64_t NextOffset = (InputDIEIdx + 1 < U.getNumDIEs())
- ? U.getDIEAtIndex(InputDIEIdx + 1).getOffset()
- : U.getNextUnitOffset();
+ uint64_t NextOffset = (InputDIEIdx + 1 < InUnit.getOrigUnit().getNumDIEs())
+ ? InUnit.getDIEAtIndex(InputDIEIdx + 1).getOffset()
+ : InUnit.getOrigUnit().getNextUnitOffset();
// We could copy the data only if we need to apply a relocation to it. After
// testing, it seems there is no performance downside to doing the copy
@@ -34,8 +32,8 @@ void DIEAttributeCloner::clone() {
DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
// Modify the copy with relocated addresses.
- CU.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
- Data.isLittleEndian());
+ InUnit.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
+ Data.isLittleEndian());
// Reset the Offset to 0 as we will be working on the local copy of
// the data.
@@ -45,17 +43,18 @@ void DIEAttributeCloner::clone() {
Offset += getULEB128Size(Abbrev->getCode());
// Set current output offset.
- AttrOutOffset = OutDIE->getOffset();
+ AttrOutOffset = OutUnit.isCompileUnit() ? OutDIE->getOffset() : 0;
for (const auto &AttrSpec : Abbrev->attributes()) {
// Check whether current attribute should be skipped.
if (shouldSkipAttribute(AttrSpec)) {
DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
- U.getFormParams());
+ InUnit.getFormParams());
continue;
}
DWARFFormValue Val = AttrSpec.getFormValue();
- Val.extractValue(Data, &Offset, U.getFormParams(), &U);
+ Val.extractValue(Data, &Offset, InUnit.getFormParams(),
+ &InUnit.getOrigUnit());
// Clone current attribute.
switch (AttrSpec.Form) {
@@ -107,10 +106,10 @@ void DIEAttributeCloner::clone() {
AttrOutOffset += cloneAddressAttr(Val, AttrSpec);
break;
default:
- CU.warn("unsupported attribute form " +
- dwarf::FormEncodingString(AttrSpec.Form) +
- " in DieAttributeCloner::clone(). Dropping.",
- InputDieEntry);
+ InUnit.warn("unsupported attribute form " +
+ dwarf::FormEncodingString(AttrSpec.Form) +
+ " in DieAttributeCloner::clone(). Dropping.",
+ InputDieEntry);
}
}
@@ -118,19 +117,20 @@ void DIEAttributeCloner::clone() {
// Check if original compile unit already has DW_AT_str_offsets_base
// attribute.
if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
- CU.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
+ InUnit.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugOffsetPatch{
- AttrOutOffset,
- &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets),
- true},
+ DebugOffsetPatch{AttrOutOffset,
+ &OutUnit->getOrCreateSectionDescriptor(
+ DebugSectionKind::DebugStrOffsets),
+ true},
PatchesOffsets);
- AttrOutOffset += Generator
- .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
- dwarf::DW_FORM_sec_offset,
- CU.getDebugStrOffsetsHeaderSize())
- .second;
+ AttrOutOffset +=
+ Generator
+ .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
+ dwarf::DW_FORM_sec_offset,
+ OutUnit->getDebugStrOffsetsHeaderSize())
+ .second;
}
}
@@ -142,28 +142,28 @@ bool DIEAttributeCloner::shouldSkipAttribute(
case dwarf::DW_AT_low_pc:
case dwarf::DW_AT_high_pc:
case dwarf::DW_AT_ranges:
- if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
+ if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
return false;
// Skip address attribute if we are in function scope and function does not
// reference live address.
- return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
+ return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
!FuncAddressAdjustment.has_value();
case dwarf::DW_AT_rnglists_base:
// In case !Update the .debug_addr table is not generated/preserved.
// Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used.
// Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the
// DW_AT_rnglists_base is removed.
- return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
+ return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
case dwarf::DW_AT_loclists_base:
// In case !Update the .debug_addr table is not generated/preserved.
// Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used.
// Since DW_AT_loclists_base is used for only DW_FORM_loclistx the
// DW_AT_loclists_base is removed.
- return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
+ return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
case dwarf::DW_AT_location:
case dwarf::DW_AT_frame_base:
- if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
+ if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
return false;
// When location expression contains an address: skip this attribute
@@ -173,7 +173,7 @@ bool DIEAttributeCloner::shouldSkipAttribute(
// Skip location attribute if we are in function scope and function does not
// reference live address.
- return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
+ return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
!FuncAddressAdjustment.has_value();
}
}
@@ -183,19 +183,12 @@ size_t DIEAttributeCloner::cloneStringAttr(
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
std::optional<const char *> String = dwarf::toString(Val);
if (!String) {
- CU.warn("cann't read string attribute.");
+ InUnit.warn("cann't read string attribute.");
return 0;
}
StringEntry *StringInPool =
- CU.getGlobalData().getStringPool().insert(*String).first;
- if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
- DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
- return Generator
- .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp)
- .second;
- }
+ InUnit.getGlobalData().getStringPool().insert(*String).first;
// Update attributes info.
if (AttrSpec.Attr == dwarf::DW_AT_name)
@@ -204,9 +197,29 @@ size_t DIEAttributeCloner::cloneStringAttr(
AttrSpec.Attr == dwarf::DW_AT_linkage_name)
AttrInfo.MangledName = StringInPool;
- if (CU.getVersion() < 5) {
- DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
+ if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
+ if (OutUnit.isTypeUnit()) {
+ DebugInfoOutputSection.notePatch(DebugTypeLineStrPatch{
+ AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx),
+ StringInPool});
+ } else {
+ DebugInfoOutputSection.notePatchWithOffsetUpdate(
+ DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
+ }
+ return Generator
+ .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp)
+ .second;
+ }
+
+ if (Use_DW_FORM_strp) {
+ if (OutUnit.isTypeUnit()) {
+ DebugInfoOutputSection.notePatch(
+ DebugTypeStrPatch{AttrOutOffset, OutDIE,
+ InUnit.getDieTypeEntry(InputDIEIdx), StringInPool});
+ } else {
+ DebugInfoOutputSection.notePatchWithOffsetUpdate(
+ DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
+ }
return Generator
.addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_strp)
@@ -215,7 +228,7 @@ size_t DIEAttributeCloner::cloneStringAttr(
return Generator
.addIndexedStringAttribute(AttrSpec.Attr, dwarf::DW_FORM_strx,
- CU.getDebugStrIndex(StringInPool))
+ OutUnit->getDebugStrIndex(StringInPool))
.second;
}
@@ -225,22 +238,48 @@ size_t DIEAttributeCloner::cloneDieRefAttr(
if (AttrSpec.Attr == dwarf::DW_AT_sibling)
return 0;
- std::optional<std::pair<CompileUnit *, uint32_t>> RefDiePair =
- CU.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve);
- if (!RefDiePair) {
+ std::optional<UnitEntryPairTy> RefDiePair =
+ InUnit.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve);
+ if (!RefDiePair || !RefDiePair->DieEntry) {
// If the referenced DIE is not found, drop the attribute.
- CU.warn("cann't find referenced DIE.", InputDieEntry);
+ InUnit.warn("cann't find referenced DIE.", InputDieEntry);
return 0;
}
- assert(RefDiePair->first->getStage() >= CompileUnit::Stage::Loaded);
- assert(RefDiePair->second != 0);
+
+ TypeEntry *RefTypeName = nullptr;
+ const CompileUnit::DIEInfo &RefDIEInfo =
+ RefDiePair->CU->getDIEInfo(RefDiePair->DieEntry);
+ if (RefDIEInfo.needToPlaceInTypeTable())
+ RefTypeName = RefDiePair->CU->getDieTypeEntry(RefDiePair->DieEntry);
+
+ if (OutUnit.isTypeUnit()) {
+ assert(RefTypeName && "Type name for referenced DIE is not set");
+ assert(InUnit.getDieTypeEntry(InputDIEIdx) &&
+ "Type name for DIE is not set");
+
+ DebugInfoOutputSection.notePatch(DebugType2TypeDieRefPatch{
+ AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx),
+ RefTypeName});
+
+ return Generator
+ .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref4, 0xBADDEF)
+ .second;
+ }
+
+ if (RefTypeName) {
+ DebugInfoOutputSection.notePatchWithOffsetUpdate(
+ DebugDieTypeRefPatch{AttrOutOffset, RefTypeName}, PatchesOffsets);
+
+ return Generator
+ .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref_addr, 0xBADDEF)
+ .second;
+ }
// Get output offset for referenced DIE.
- uint64_t OutDieOffset =
- RefDiePair->first->getDieOutOffset(RefDiePair->second);
+ uint64_t OutDieOffset = RefDiePair->CU->getDieOutOffset(RefDiePair->DieEntry);
// Examine whether referenced DIE is in current compile unit.
- bool IsLocal = CU.getUniqueID() == RefDiePair->first->getUniqueID();
+ bool IsLocal = OutUnit->getUniqueID() == RefDiePair->CU->getUniqueID();
// Set attribute form basing on the kind of referenced DIE(local or not?).
dwarf::Form NewForm = IsLocal ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr;
@@ -254,8 +293,9 @@ size_t DIEAttributeCloner::cloneDieRefAttr(
// If offset value is not known at this point then create patch for the
// reference value and write dummy value into the attribute.
DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugDieRefPatch{AttrOutOffset, &CU, RefDiePair->first,
- RefDiePair->second},
+ DebugDieRefPatch{AttrOutOffset, OutUnit.getAsCompileUnit(),
+ RefDiePair->CU,
+ RefDiePair->CU->getDIEIndex(RefDiePair->DieEntry)},
PatchesOffsets);
return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, 0xBADDEF).second;
}
@@ -267,41 +307,47 @@ size_t DIEAttributeCloner::cloneScalarAttr(
// Create patches for attribute referencing other non invariant section.
// Invariant section could not be updated here as this section and
// reference to it do not change value in case --update.
- if (AttrSpec.Attr == dwarf::DW_AT_macro_info) {
+ switch (AttrSpec.Attr) {
+ case dwarf::DW_AT_macro_info: {
if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
const DWARFDebugMacro *Macro =
- CU.getContaingFile().Dwarf->getDebugMacinfo();
+ InUnit.getContaingFile().Dwarf->getDebugMacinfo();
if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))
return 0;
DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
- DebugSectionKind::DebugMacinfo)},
+ DebugOffsetPatch{AttrOutOffset,
+ &OutUnit->getOrCreateSectionDescriptor(
+ DebugSectionKind::DebugMacinfo)},
PatchesOffsets);
}
- } else if (AttrSpec.Attr == dwarf::DW_AT_macros) {
+ } break;
+ case dwarf::DW_AT_macros: {
if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
const DWARFDebugMacro *Macro =
- CU.getContaingFile().Dwarf->getDebugMacro();
+ InUnit.getContaingFile().Dwarf->getDebugMacro();
if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))
return 0;
DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
- DebugSectionKind::DebugMacro)},
+ DebugOffsetPatch{AttrOutOffset,
+ &OutUnit->getOrCreateSectionDescriptor(
+ DebugSectionKind::DebugMacro)},
PatchesOffsets);
}
- } else if (AttrSpec.Attr == dwarf::DW_AT_stmt_list) {
+ } break;
+ case dwarf::DW_AT_stmt_list: {
DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
+ DebugOffsetPatch{AttrOutOffset, &OutUnit->getOrCreateSectionDescriptor(
DebugSectionKind::DebugLine)},
PatchesOffsets);
- } else if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {
+ } break;
+ case dwarf::DW_AT_str_offsets_base: {
DebugInfoOutputSection.notePatchWithOffsetUpdate(
- DebugOffsetPatch{
- AttrOutOffset,
- &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets),
- true},
+ DebugOffsetPatch{AttrOutOffset,
+ &OutUnit->getOrCreateSectionDescriptor(
+ DebugSectionKind::DebugStrOffsets),
+ true},
PatchesOffsets);
// Use size of .debug_str_offsets header as attribute value. The offset
@@ -309,9 +355,36 @@ size_t DIEAttributeCloner::cloneScalarAttr(
AttrInfo.HasStringOffsetBaseAttr = true;
return Generator
.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form,
- CU.getDebugStrOffsetsHeaderSize())
+ OutUnit->getDebugStrOffsetsHeaderSize())
.second;
- }
+ } break;
+ case dwarf::DW_AT_decl_file: {
+ // Value of DW_AT_decl_file may exceed original form. Longer
+ // form can affect offsets to the following attributes. To not
+ // update offsets of the following attributes we always remove
+ // original DW_AT_decl_file and attach it to the last position
+ // later.
+ if (OutUnit.isTypeUnit()) {
+ if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename =
+ InUnit.getDirAndFilenameFromLineTable(Val))
+ DebugInfoOutputSection.notePatch(DebugTypeDeclFilePatch{
+ OutDIE,
+ InUnit.getDieTypeEntry(InputDIEIdx),
+ OutUnit->getGlobalData()
+ .getStringPool()
+ .insert(DirAndFilename->first)
+ .first,
+ OutUnit->getGlobalData()
+ .getStringPool()
+ .insert(DirAndFilename->second)
+ .first,
+ });
+ return 0;
+ }
+ } break;
+ default: {
+ } break;
+ };
uint64_t Value;
if (AttrSpec.Attr == dwarf::DW_AT_const_value &&
@@ -319,7 +392,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
InputDieEntry->getTag() == dwarf::DW_TAG_constant))
AttrInfo.HasLiveAddress = true;
- if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) {
+ if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) {
if (auto OptionalValue = Val.getAsUnsignedConstant())
Value = *OptionalValue;
else if (auto OptionalValue = Val.getAsSignedConstant())
@@ -327,8 +400,8 @@ size_t DIEAttributeCloner::cloneScalarAttr(
else if (auto OptionalValue = Val.getAsSectionOffset())
Value = *OptionalValue;
else {
- CU.warn("unsupported scalar attribute form. Dropping attribute.",
- InputDieEntry);
+ InUnit.warn("unsupported scalar attribute form. Dropping attribute.",
+ InputDieEntry);
return 0;
}
@@ -350,12 +423,13 @@ size_t DIEAttributeCloner::cloneScalarAttr(
// to DW_FORM_sec_offset here.
std::optional<uint64_t> Index = Val.getAsSectionOffset();
if (!Index) {
- CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+ InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
return 0;
}
- std::optional<uint64_t> Offset = CU.getOrigUnit().getRnglistOffset(*Index);
+ std::optional<uint64_t> Offset =
+ InUnit.getOrigUnit().getRnglistOffset(*Index);
if (!Offset) {
- CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+ InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
return 0;
}
@@ -367,12 +441,13 @@ size_t DIEAttributeCloner::cloneScalarAttr(
// to DW_FORM_sec_offset here.
std::optional<uint64_t> Index = Val.getAsSectionOffset();
if (!Index) {
- CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+ InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
return 0;
}
- std::optional<uint64_t> Offset = CU.getOrigUnit().getLoclistOffset(*Index);
+ std::optional<uint64_t> Offset =
+ InUnit.getOrigUnit().getLoclistOffset(*Index);
if (!Offset) {
- CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+ InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
return 0;
}
@@ -380,11 +455,14 @@ size_t DIEAttributeCloner::cloneScalarAttr(
ResultingForm = dwarf::DW_FORM_sec_offset;
} else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
- std::optional<uint64_t> LowPC = CU.getLowPc();
+ if (!OutUnit.isCompileUnit())
+ return 0;
+
+ std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc();
if (!LowPC)
return 0;
// Dwarf >= 4 high_pc is an size, not an address.
- Value = CU.getHighPc() - *LowPC;
+ Value = OutUnit.getAsCompileUnit()->getHighPc() - *LowPC;
} else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
Value = *Val.getAsSectionOffset();
else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
@@ -392,8 +470,8 @@ size_t DIEAttributeCloner::cloneScalarAttr(
else if (auto OptionalValue = Val.getAsUnsignedConstant())
Value = *OptionalValue;
else {
- CU.warn("unsupported scalar attribute form. Dropping attribute.",
- InputDieEntry);
+ InUnit.warn("unsupported scalar attribute form. Dropping attribute.",
+ InputDieEntry);
return 0;
}
@@ -408,7 +486,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
} else if (DWARFAttribute::mayHaveLocationList(AttrSpec.Attr) &&
dwarf::doesFormBelongToClass(AttrSpec.Form,
DWARFFormValue::FC_SectionOffset,
- CU.getOrigUnit().getVersion())) {
+ InUnit.getOrigUnit().getVersion())) {
int64_t AddrAdjustmentValue = 0;
if (VarAddressAdjustment)
AddrAdjustmentValue = *VarAddressAdjustment;
@@ -422,7 +500,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
DebugInfoOutputSection.notePatchWithOffsetUpdate(
DebugOffsetPatch{
AttrOutOffset,
- &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr),
+ &OutUnit->getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr),
true},
PatchesOffsets);
@@ -430,7 +508,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
// .debug_addr would be added later while patching.
return Generator
.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form,
- CU.getDebugAddrHeaderSize())
+ OutUnit->getDebugAddrHeaderSize())
.second;
} else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
AttrInfo.IsDeclaration = true;
@@ -443,6 +521,9 @@ size_t DIEAttributeCloner::cloneBlockAttr(
const DWARFFormValue &Val,
const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
+ if (OutUnit.isTypeUnit())
+ return 0;
+
size_t NumberOfPatchesAtStart = PatchesOffsets.size();
// If the block is a DWARF Expression, clone it into the temporary
@@ -452,15 +533,14 @@ size_t DIEAttributeCloner::cloneBlockAttr(
if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) &&
(Val.isFormClass(DWARFFormValue::FC_Block) ||
Val.isFormClass(DWARFFormValue::FC_Exprloc))) {
- DWARFUnit &OrigUnit = CU.getOrigUnit();
DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),
- OrigUnit.isLittleEndian(),
- OrigUnit.getAddressByteSize());
- DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(),
- OrigUnit.getFormParams().Format);
+ InUnit.getOrigUnit().isLittleEndian(),
+ InUnit.getOrigUnit().getAddressByteSize());
+ DWARFExpression Expr(Data, InUnit.getOrigUnit().getAddressByteSize(),
+ InUnit.getFormParams().Format);
- CU.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection,
- VarAddressAdjustment, PatchesOffsets);
+ InUnit.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection,
+ VarAddressAdjustment, PatchesOffsets);
Bytes = Buffer;
}
@@ -491,7 +571,7 @@ size_t DIEAttributeCloner::cloneBlockAttr(
if (HasLocationExpressionAddress)
AttrInfo.HasLiveAddress =
VarAddressAdjustment.has_value() ||
- CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
+ InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
return FinalAttributeSize;
}
@@ -502,11 +582,14 @@ size_t DIEAttributeCloner::cloneAddressAttr(
if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
AttrInfo.HasLiveAddress = true;
- if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
+ if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
return Generator
.addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Val.getRawUValue())
.second;
+ if (OutUnit.isTypeUnit())
+ return 0;
+
// Cloned Die may have address attributes relocated to a
// totally unrelated value. This can happen:
// - If high_pc is an address (Dwarf version == 2), then it might have been
@@ -520,25 +603,25 @@ size_t DIEAttributeCloner::cloneAddressAttr(
// Info.PCOffset here.
std::optional<DWARFFormValue> AddrAttribute =
- CU.find(InputDieEntry, AttrSpec.Attr);
+ InUnit.find(InputDieEntry, AttrSpec.Attr);
if (!AddrAttribute)
llvm_unreachable("Cann't find attribute");
std::optional<uint64_t> Addr = AddrAttribute->getAsAddress();
if (!Addr) {
- CU.warn("cann't read address attribute value.");
+ InUnit.warn("cann't read address attribute value.");
return 0;
}
if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
AttrSpec.Attr == dwarf::DW_AT_low_pc) {
- if (std::optional<uint64_t> LowPC = CU.getLowPc())
+ if (std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc())
Addr = *LowPC;
else
return 0;
} else if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
AttrSpec.Attr == dwarf::DW_AT_high_pc) {
- if (uint64_t HighPc = CU.getHighPc())
+ if (uint64_t HighPc = OutUnit.getAsCompileUnit()->getHighPc())
Addr = HighPc;
else
return 0;
@@ -556,20 +639,14 @@ size_t DIEAttributeCloner::cloneAddressAttr(
return Generator
.addScalarAttribute(AttrSpec.Attr, dwarf::Form::DW_FORM_addrx,
- CU.getDebugAddrIndex(*Addr))
+ OutUnit.getAsCompileUnit()->getDebugAddrIndex(*Addr))
.second;
}
unsigned DIEAttributeCloner::finalizeAbbreviations(bool HasChildrenToClone) {
- size_t SizeOfAbbreviationNumber =
- Generator.finalizeAbbreviations(HasChildrenToClone);
-
- // We need to update patches offsets after we know the size of the
- // abbreviation number.
- updatePatchesWithSizeOfAbbreviationNumber(SizeOfAbbreviationNumber);
-
// Add the size of the abbreviation number to the output offset.
- AttrOutOffset += SizeOfAbbreviationNumber;
+ AttrOutOffset +=
+ Generator.finalizeAbbreviations(HasChildrenToClone, &PatchesOffsets);
return AttrOutOffset;
}
diff --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
index 74d80e131480171..e18c0a15cefc63d 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
+++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
@@ -13,6 +13,7 @@
#include "DIEGenerator.h"
#include "DWARFLinkerCompileUnit.h"
#include "DWARFLinkerGlobalData.h"
+#include "DWARFLinkerTypeUnit.h"
namespace llvm {
namespace dwarflinker_parallel {
@@ -44,20 +45,28 @@ struct AttributesInfo {
/// attribute, adds cloned attribute to the output DIE.
class DIEAttributeCloner {
public:
- DIEAttributeCloner(DIE *OutDIE, CompileUnit &CU,
+ DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, CompileUnit *OutUnit,
const DWARFDebugInfoEntry *InputDieEntry,
DIEGenerator &Generator,
std::optional<int64_t> FuncAddressAdjustment,
std::optional<int64_t> VarAddressAdjustment,
bool HasLocationExpressionAddress)
- : OutDIE(OutDIE), CU(CU),
- DebugInfoOutputSection(
- CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)),
- InputDieEntry(InputDieEntry), Generator(Generator),
- FuncAddressAdjustment(FuncAddressAdjustment),
- VarAddressAdjustment(VarAddressAdjustment),
- HasLocationExpressionAddress(HasLocationExpressionAddress) {
- InputDIEIdx = CU.getDIEIndex(InputDieEntry);
+ : DIEAttributeCloner(OutDIE, InUnit,
+ CompileUnit::OutputUnitVariantPtr(OutUnit),
+ InputDieEntry, Generator, FuncAddressAdjustment,
+ VarAddressAdjustment, HasLocationExpressionAddress) {
+ }
+
+ DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, TypeUnit *OutUnit,
+ const DWARFDebugInfoEntry *InputDieEntry,
+ DIEGenerator &Generator,
+ std::optional<int64_t> FuncAddressAdjustment,
+ std::optional<int64_t> VarAddressAdjustment,
+ bool HasLocationExpressionAddress)
+ : DIEAttributeCloner(OutDIE, InUnit,
+ CompileUnit::OutputUnitVariantPtr(OutUnit),
+ InputDieEntry, Generator, FuncAddressAdjustment,
+ VarAddressAdjustment, HasLocationExpressionAddress) {
}
/// Clone attributes of input DIE.
@@ -69,7 +78,36 @@ class DIEAttributeCloner {
/// Cannot be used concurrently.
AttributesInfo AttrInfo;
+ unsigned getOutOffset() { return AttrOutOffset; }
+
protected:
+ DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit,
+ CompileUnit::OutputUnitVariantPtr OutUnit,
+ const DWARFDebugInfoEntry *InputDieEntry,
+ DIEGenerator &Generator,
+ std::optional<int64_t> FuncAddressAdjustment,
+ std::optional<int64_t> VarAddressAdjustment,
+ bool HasLocationExpressionAddress)
+ : OutDIE(OutDIE), InUnit(InUnit), OutUnit(OutUnit),
+ DebugInfoOutputSection(
+ OutUnit->getSectionDescriptor(DebugSectionKind::DebugInfo)),
+ InputDieEntry(InputDieEntry), Generator(Generator),
+ FuncAddressAdjustment(FuncAddressAdjustment),
+ VarAddressAdjustment(VarAddressAdjustment),
+ HasLocationExpressionAddress(HasLocationExpressionAddress) {
+ InputDIEIdx = InUnit.getDIEIndex(InputDieEntry);
+
+ // Use DW_FORM_strp form for string attributes for DWARF version less than 5
+ // or if output unit is type unit and we need to produce deterministic
+ // result. (We can not generate deterministic results for debug_str_offsets
+ // section when attributes are cloned parallelly).
+ Use_DW_FORM_strp =
+ (InUnit.getVersion() < 5) ||
+ (OutUnit.isTypeUnit() &&
+ ((InUnit.getGlobalData().getOptions().Threads != 1) &&
+ !InUnit.getGlobalData().getOptions().AllowNonDeterministicOutput));
+ }
+
/// Clone string attribute.
size_t
cloneStringAttr(const DWARFFormValue &Val,
@@ -99,18 +137,14 @@ class DIEAttributeCloner {
bool
shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec);
- /// Update patches offsets with the size of abbreviation number.
- void
- updatePatchesWithSizeOfAbbreviationNumber(unsigned SizeOfAbbreviationNumber) {
- for (uint64_t *OffsetPtr : PatchesOffsets)
- *OffsetPtr += SizeOfAbbreviationNumber;
- }
-
/// Output DIE.
DIE *OutDIE = nullptr;
- /// Compile unit for the output DIE.
- CompileUnit &CU;
+ /// Input compilation unit.
+ CompileUnit &InUnit;
+
+ /// Output unit(either "plain" compilation unit, either artificial type unit).
+ CompileUnit::OutputUnitVariantPtr OutUnit;
/// .debug_info section descriptor.
SectionDescriptor &DebugInfoOutputSection;
@@ -139,6 +173,9 @@ class DIEAttributeCloner {
/// Patches for the cloned attributes.
OffsetsPtrVector PatchesOffsets;
+
+ /// This flag forces using DW_FORM_strp for string attributes.
+ bool Use_DW_FORM_strp = false;
};
} // end of namespace dwarflinker_parallel
diff --git a/llvm/lib/DWARFLinkerParallel/DIEGenerator.h b/llvm/lib/DWARFLinkerParallel/DIEGenerator.h
index c0bbce0f520143c..42bf00f55ff1801 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEGenerator.h
+++ b/llvm/lib/DWARFLinkerParallel/DIEGenerator.h
@@ -23,6 +23,9 @@ class DIEGenerator {
DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU)
: Allocator(Allocator), CU(CU) {}
+ DIEGenerator(DIE *OutputDIE, BumpPtrAllocator &Allocator, DwarfUnit &CU)
+ : Allocator(Allocator), CU(CU), OutputDIE(OutputDIE) {}
+
/// Creates a DIE of specified tag \p DieTag and \p OutOffset.
DIE *createDIE(dwarf::Tag DieTag, uint32_t OutOffset) {
OutputDIE = DIE::get(Allocator, DieTag);
@@ -32,6 +35,8 @@ class DIEGenerator {
return OutputDIE;
}
+ DIE *getDIE() { return OutputDIE; }
+
/// Adds a specified \p Child to the current DIE.
void addChild(DIE *Child) {
assert(Child != nullptr);
@@ -126,8 +131,10 @@ class DIEGenerator {
}
/// Creates appreviations for the current DIE. Returns value of
- /// abbreviation number.
- size_t finalizeAbbreviations(bool CHILDREN_yes) {
+ /// abbreviation number. Updates offsets with the size of abbreviation
+ /// number.
+ size_t finalizeAbbreviations(bool CHILDREN_yes,
+ OffsetsPtrVector *OffsetsList) {
// Create abbreviations for output DIE.
DIEAbbrev NewAbbrev = OutputDIE->generateAbbrev();
if (CHILDREN_yes)
@@ -136,7 +143,15 @@ class DIEGenerator {
CU.assignAbbrev(NewAbbrev);
OutputDIE->setAbbrevNumber(NewAbbrev.getNumber());
- return getULEB128Size(OutputDIE->getAbbrevNumber());
+ size_t AbbrevNumberSize = getULEB128Size(OutputDIE->getAbbrevNumber());
+
+ // Add size of abbreviation number to the offsets.
+ if (OffsetsList != nullptr) {
+ for (uint64_t *OffsetPtr : *OffsetsList)
+ *OffsetPtr += AbbrevNumberSize;
+ }
+
+ return AbbrevNumberSize;
}
protected:
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
index f082fd603610038..269f24b1a13b9ab 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "DWARFLinkerImpl.h"
+#include "DependencyTracker.h"
std::unique_ptr<llvm::dwarflinker_parallel::DWARFLinker>
llvm::dwarflinker_parallel::DWARFLinker::createLinker(
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
index c1181a264f879f0..48e7cb1fd7e2f36 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
@@ -7,17 +7,65 @@
//===----------------------------------------------------------------------===//
#include "DWARFLinkerCompileUnit.h"
+#include "AcceleratorRecordsSaver.h"
#include "DIEAttributeCloner.h"
#include "DIEGenerator.h"
-#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "DependencyTracker.h"
+#include "SyntheticTypeNameBuilder.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+#include <utility>
using namespace llvm;
using namespace llvm::dwarflinker_parallel;
+CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, unsigned ID,
+ StringRef ClangModuleName, DWARFFile &File,
+ OffsetToUnitTy UnitFromOffset,
+ dwarf::FormParams Format, llvm::endianness Endianess)
+ : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
+ getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded),
+ AcceleratorRecords(&GlobalData.getAllocator()) {
+ UnitName = File.FileName;
+ setOutputFormat(Format, Endianess);
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+}
+
+CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit,
+ unsigned ID, StringRef ClangModuleName,
+ DWARFFile &File, OffsetToUnitTy UnitFromOffset,
+ dwarf::FormParams Format, llvm::endianness Endianess)
+ : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
+ OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset),
+ Stage(Stage::CreatedNotLoaded),
+ AcceleratorRecords(&GlobalData.getAllocator()) {
+ setOutputFormat(Format, Endianess);
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+
+ DWARFDie CUDie = OrigUnit.getUnitDIE();
+ if (!CUDie)
+ return;
+
+ if (std::optional<DWARFFormValue> Val = CUDie.find(dwarf::DW_AT_language)) {
+ uint16_t LangVal = dwarf::toUnsigned(Val, 0);
+ if (isODRLanguage(LangVal))
+ Language = LangVal;
+ }
+
+ if (!GlobalData.getOptions().NoODR && Language.has_value())
+ NoODR = false;
+
+ if (const char *CUName = CUDie.getName(DINameKind::ShortName))
+ UnitName = CUName;
+ else
+ UnitName = File.FileName;
+ SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
+}
+
void CompileUnit::loadLineTable() {
LineTablePtr = File.Dwarf->getLineTableForUnit(&getOrigUnit());
}
@@ -39,6 +87,7 @@ void CompileUnit::maybeResetToLoadedStage() {
HighPc = 0;
Labels.clear();
Ranges.clear();
+ Dependencies.reset(nullptr);
if (getStage() < Stage::Cloned) {
setStage(Stage::Loaded);
@@ -53,6 +102,8 @@ void CompileUnit::maybeResetToLoadedStage() {
for (uint64_t &Offset : OutDieOffsetArray)
Offset = 0;
+ for (TypeEntry *&Name : TypeEntries)
+ Name = nullptr;
eraseSections();
setStage(Stage::CreatedNotLoaded);
@@ -66,21 +117,30 @@ bool CompileUnit::loadInputDIEs() {
// load input dies, resize Info structures array.
DieInfoArray.resize(getOrigUnit().getNumDIEs());
OutDieOffsetArray.resize(getOrigUnit().getNumDIEs(), 0);
+ if (!NoODR)
+ TypeEntries.resize(getOrigUnit().getNumDIEs());
return true;
}
void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
- bool IsInModule, bool IsInFunction) {
+ bool IsODRUnavailableFunctionScope) {
+ CompileUnit::DIEInfo &DieInfo = getDIEInfo(DieEntry);
+
for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry);
CurChild && CurChild->getAbbreviationDeclarationPtr();
CurChild = getSiblingEntry(CurChild)) {
CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild);
+ bool ChildIsODRUnavailableFunctionScope = IsODRUnavailableFunctionScope;
- if (IsInModule)
+ if (DieInfo.getIsInMouduleScope())
ChildInfo.setIsInMouduleScope();
- if (IsInFunction)
+
+ if (DieInfo.getIsInFunctionScope())
ChildInfo.setIsInFunctionScope();
+ if (DieInfo.getIsInAnonNamespaceScope())
+ ChildInfo.setIsInAnonNamespaceScope();
+
switch (CurChild->getTag()) {
case dwarf::DW_TAG_module:
ChildInfo.setIsInMouduleScope();
@@ -91,19 +151,35 @@ void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
break;
case dwarf::DW_TAG_subprogram:
ChildInfo.setIsInFunctionScope();
+ if (!ChildIsODRUnavailableFunctionScope &&
+ !ChildInfo.getIsInMouduleScope()) {
+ if (find(CurChild,
+ {dwarf::DW_AT_abstract_origin, dwarf::DW_AT_specification}))
+ ChildIsODRUnavailableFunctionScope = true;
+ }
break;
+ case dwarf::DW_TAG_namespace: {
+ UnitEntryPairTy NamespaceEntry = {this, CurChild};
+
+ if (find(CurChild, dwarf::DW_AT_extension))
+ NamespaceEntry = NamespaceEntry.getNamespaceOrigin();
+
+ if (!NamespaceEntry.CU->find(NamespaceEntry.DieEntry, dwarf::DW_AT_name))
+ ChildInfo.setIsInAnonNamespaceScope();
+ } break;
default:
break;
}
- if (IsInModule)
- ChildInfo.setIsInMouduleScope();
- if (IsInFunction)
- ChildInfo.setIsInFunctionScope();
+ if (!isClangModule() && !getGlobalData().getOptions().UpdateIndexTablesOnly)
+ ChildInfo.setTrackLiveness();
+
+ if ((!ChildInfo.getIsInAnonNamespaceScope() &&
+ !ChildIsODRUnavailableFunctionScope && !NoODR))
+ ChildInfo.setODRAvailable();
if (CurChild->hasChildren())
- analyzeDWARFStructureRec(CurChild, ChildInfo.getIsInMouduleScope(),
- ChildInfo.getIsInFunctionScope());
+ analyzeDWARFStructureRec(CurChild, ChildIsODRUnavailableFunctionScope);
}
}
@@ -162,8 +238,11 @@ void CompileUnit::cleanupDataAfterClonning() {
AbbreviationsSet.clear();
ResolvedFullPaths.shrink_and_clear();
ResolvedParentPaths.clear();
+ FileNames.shrink_and_clear();
DieInfoArray = SmallVector<DIEInfo>();
OutDieOffsetArray = SmallVector<uint64_t>();
+ TypeEntries = SmallVector<TypeEntry *>();
+ Dependencies.reset(nullptr);
getOrigUnit().clear();
}
@@ -184,7 +263,7 @@ static SmallString<128> guessToolchainBaseDir(StringRef SysRoot) {
/// Collect references to parseable Swift interfaces in imported
/// DW_TAG_module blocks.
void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) {
- if (getLanguage() != dwarf::DW_LANG_Swift)
+ if (!Language || Language != dwarf::DW_LANG_Swift)
return;
if (!GlobalData.getOptions().ParseableSwiftInterfaces)
@@ -231,12 +310,43 @@ void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) {
}
}
+Error CompileUnit::assignTypeNames(TypePool &TypePoolRef) {
+ if (!getUnitDIE().isValid())
+ return Error::success();
+
+ SyntheticTypeNameBuilder NameBuilder(TypePoolRef);
+ return assignTypeNamesRec(getDebugInfoEntry(0), NameBuilder);
+}
+
+Error CompileUnit::assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry,
+ SyntheticTypeNameBuilder &NameBuilder) {
+ OrderedChildrenIndexAssigner ChildrenIndexAssigner(*this, DieEntry);
+ for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = getSiblingEntry(CurChild)) {
+ CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild);
+ if (!ChildInfo.needToPlaceInTypeTable())
+ continue;
+
+ assert(ChildInfo.getODRAvailable());
+ if (Error Err = NameBuilder.assignName(
+ {this, CurChild},
+ ChildrenIndexAssigner.getChildIndex(*this, CurChild)))
+ return Err;
+
+ if (Error Err = assignTypeNamesRec(CurChild, NameBuilder))
+ return Err;
+ }
+
+ return Error::success();
+}
+
void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
if (std::optional<SectionDescriptor *> DebugInfoSection =
tryGetSectionDescriptor(DebugSectionKind::DebugInfo)) {
(*DebugInfoSection)
- ->ListDebugDieRefPatch.forEach([](DebugDieRefPatch &Patch) {
+ ->ListDebugDieRefPatch.forEach([&](DebugDieRefPatch &Patch) {
/// Replace stored DIE indexes with DIE output offsets.
Patch.RefDieIdxOrClonedOffset =
Patch.RefCU.getPointer()->getDieOutOffset(
@@ -245,7 +355,7 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
(*DebugInfoSection)
->ListDebugULEB128DieRefPatch.forEach(
- [](DebugULEB128DieRefPatch &Patch) {
+ [&](DebugULEB128DieRefPatch &Patch) {
/// Replace stored DIE indexes with DIE output offsets.
Patch.RefDieIdxOrClonedOffset =
Patch.RefCU.getPointer()->getDieOutOffset(
@@ -278,45 +388,53 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
}
}
-std::optional<std::pair<CompileUnit *, uint32_t>>
-CompileUnit::resolveDIEReference(
+std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference(
const DWARFFormValue &RefValue,
ResolveInterCUReferencesMode CanResolveInterCUReferences) {
if (std::optional<DWARFFormValue::UnitOffset> Ref =
*RefValue.getAsRelativeReference()) {
- if (Ref->Unit != nullptr) {
+ if (Ref->Unit == OrigUnit) {
// Referenced DIE is in current compile unit.
-
if (std::optional<uint32_t> RefDieIdx =
- getDIEIndexForOffset(Ref->Unit->getOffset() + Ref->Offset))
- return std::make_pair(this, *RefDieIdx);
+ getDIEIndexForOffset(OrigUnit->getOffset() + Ref->Offset))
+ return UnitEntryPairTy{this, OrigUnit->getDebugInfoEntry(*RefDieIdx)};
}
-
- if (CompileUnit *RefCU = getUnitFromOffset(Ref->Offset)) {
- if (RefCU->getUniqueID() == getUniqueID()) {
+ uint64_t RefDIEOffset =
+ Ref->Unit ? Ref->Unit->getOffset() + Ref->Offset : Ref->Offset;
+ if (CompileUnit *RefCU = getUnitFromOffset(RefDIEOffset)) {
+ if (RefCU == this) {
// Referenced DIE is in current compile unit.
if (std::optional<uint32_t> RefDieIdx =
- getDIEIndexForOffset(Ref->Offset))
- return std::make_pair(this, *RefDieIdx);
+ getDIEIndexForOffset(RefDIEOffset))
+ return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)};
} else if (CanResolveInterCUReferences) {
// Referenced DIE is in other compile unit.
// Check whether DIEs are loaded for that compile unit.
enum Stage ReferredCUStage = RefCU->getStage();
if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned)
- return std::make_pair(RefCU, 0);
+ return UnitEntryPairTy{RefCU, nullptr};
if (std::optional<uint32_t> RefDieIdx =
- RefCU->getDIEIndexForOffset(Ref->Offset))
- return std::make_pair(RefCU, *RefDieIdx);
+ RefCU->getDIEIndexForOffset(RefDIEOffset))
+ return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)};
} else
- return std::make_pair(RefCU, 0);
+ return UnitEntryPairTy{RefCU, nullptr};
}
}
return std::nullopt;
}
+std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference(
+ const DWARFDebugInfoEntry *DieEntry, dwarf::Attribute Attr,
+ ResolveInterCUReferencesMode CanResolveInterCUReferences) {
+ if (std::optional<DWARFFormValue> AttrVal = find(DieEntry, Attr))
+ return resolveDIEReference(*AttrVal, CanResolveInterCUReferences);
+
+ return std::nullopt;
+}
+
void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
int64_t PcOffset) {
std::lock_guard<std::mutex> Guard(RangesMutex);
@@ -565,48 +683,6 @@ Error CompileUnit::emitDebugAddrSection() {
return Error::success();
}
-Error CompileUnit::emitDebugStringOffsetSection() {
- if (getVersion() < 5)
- return Error::success();
-
- if (DebugStringIndexMap.empty())
- return Error::success();
-
- SectionDescriptor &OutDebugStrOffsetsSection =
- getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets);
-
- // Emit section header.
-
- // Emit length.
- OutDebugStrOffsetsSection.emitUnitLength(0xBADDEF);
- uint64_t OffsetAfterSectionLength = OutDebugStrOffsetsSection.OS.tell();
-
- // Emit version.
- OutDebugStrOffsetsSection.emitIntVal(5, 2);
-
- // Emit padding.
- OutDebugStrOffsetsSection.emitIntVal(0, 2);
-
- // Emit index to offset map.
- for (const StringEntry *String : DebugStringIndexMap.getValues()) {
- // Note patch for string offset value.
- OutDebugStrOffsetsSection.notePatch(
- DebugStrPatch{{OutDebugStrOffsetsSection.OS.tell()}, String});
-
- // Emit placeholder for offset value.
- OutDebugStrOffsetsSection.emitOffset(0xBADDEF);
- }
-
- // Patch section length.
- OutDebugStrOffsetsSection.apply(
- OffsetAfterSectionLength -
- OutDebugStrOffsetsSection.getFormParams().getDwarfOffsetByteSize(),
- dwarf::DW_FORM_sec_offset,
- OutDebugStrOffsetsSection.OS.tell() - OffsetAfterSectionLength);
-
- return Error::success();
-}
-
Error CompileUnit::cloneAndEmitRanges() {
if (getGlobalData().getOptions().UpdateIndexTablesOnly)
return Error::success();
@@ -1165,20 +1241,25 @@ void CompileUnit::cloneDieAttrExpression(
}
}
-Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple) {
+Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple,
+ TypeUnit *ArtificialTypeUnit) {
BumpPtrAllocator Allocator;
DWARFDie OrigUnitDIE = getOrigUnit().getUnitDIE();
if (!OrigUnitDIE.isValid())
return Error::success();
+ TypeEntry *RootEntry = nullptr;
+ if (ArtificialTypeUnit)
+ RootEntry = ArtificialTypeUnit->getTypePool().getRoot();
+
// Clone input DIE entry recursively.
- DIE *OutCUDie =
- cloneDIE(OrigUnitDIE.getDebugInfoEntry(), getDebugInfoHeaderSize(),
- std::nullopt, std::nullopt, Allocator);
- setOutUnitDIE(OutCUDie);
+ std::pair<DIE *, TypeEntry *> OutCUDie = cloneDIE(
+ OrigUnitDIE.getDebugInfoEntry(), RootEntry, getDebugInfoHeaderSize(),
+ std::nullopt, std::nullopt, Allocator, ArtificialTypeUnit);
+ setOutUnitDIE(OutCUDie.first);
- if (getGlobalData().getOptions().NoOutput || (OutCUDie == nullptr))
+ if (getGlobalData().getOptions().NoOutput || (OutCUDie.first == nullptr))
return Error::success();
assert(TargetTriple.has_value());
@@ -1188,6 +1269,7 @@ Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple) {
if (Error Err = cloneAndEmitDebugMacro())
return Err;
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
if (Error Err = emitDebugInfo(*TargetTriple))
return Err;
@@ -1215,27 +1297,103 @@ Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple) {
return emitAbbreviations();
}
-bool needToClone(CompileUnit::DIEInfo &Info) {
- return Info.getKeep() || Info.getKeepChildren();
-}
-
-DIE *CompileUnit::cloneDIE(const DWARFDebugInfoEntry *InputDieEntry,
- uint64_t OutOffset,
- std::optional<int64_t> FuncAddressAdjustment,
- std::optional<int64_t> VarAddressAdjustment,
- BumpPtrAllocator &Allocator) {
+std::pair<DIE *, TypeEntry *> CompileUnit::cloneDIE(
+ const DWARFDebugInfoEntry *InputDieEntry, TypeEntry *ClonedParentTypeDIE,
+ uint64_t OutOffset, std::optional<int64_t> FuncAddressAdjustment,
+ std::optional<int64_t> VarAddressAdjustment, BumpPtrAllocator &Allocator,
+ TypeUnit *ArtificialTypeUnit) {
uint32_t InputDieIdx = getDIEIndex(InputDieEntry);
CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx);
- if (!needToClone(Info))
- return nullptr;
+ bool NeedToClonePlainDIE = Info.needToKeepInPlainDwarf();
+ bool NeedToCloneTypeDIE =
+ (InputDieEntry->getTag() != dwarf::DW_TAG_compile_unit) &&
+ Info.needToPlaceInTypeTable();
+ std::pair<DIE *, TypeEntry *> ClonedDIE;
+
+ DIEGenerator PlainDIEGenerator(Allocator, *this);
+
+ if (NeedToClonePlainDIE)
+ // Create a cloned DIE which would be placed into the cloned version
+ // of input compile unit.
+ ClonedDIE.first = createPlainDIEandCloneAttributes(
+ InputDieEntry, PlainDIEGenerator, OutOffset, FuncAddressAdjustment,
+ VarAddressAdjustment);
+ if (NeedToCloneTypeDIE) {
+ // Create a cloned DIE which would be placed into the artificial type
+ // unit.
+ assert(ArtificialTypeUnit != nullptr);
+ DIEGenerator TypeDIEGenerator(
+ ArtificialTypeUnit->getTypePool().getThreadLocalAllocator(), *this);
+
+ ClonedDIE.second = createTypeDIEandCloneAttributes(
+ InputDieEntry, TypeDIEGenerator, ClonedParentTypeDIE,
+ ArtificialTypeUnit);
+ }
+ TypeEntry *TypeParentForChild =
+ ClonedDIE.second ? ClonedDIE.second : ClonedParentTypeDIE;
+
+ bool HasPlainChildrenToClone =
+ (ClonedDIE.first && Info.getKeepPlainChildren());
+
+ bool HasTypeChildrenToClone =
+ ((ClonedDIE.second ||
+ InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) &&
+ Info.getKeepTypeChildren());
+
+ // Recursively clone children.
+ if (HasPlainChildrenToClone || HasTypeChildrenToClone) {
+ for (const DWARFDebugInfoEntry *CurChild =
+ getFirstChildEntry(InputDieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = getSiblingEntry(CurChild)) {
+ std::pair<DIE *, TypeEntry *> ClonedChild = cloneDIE(
+ CurChild, TypeParentForChild, OutOffset, FuncAddressAdjustment,
+ VarAddressAdjustment, Allocator, ArtificialTypeUnit);
+
+ if (ClonedChild.first) {
+ OutOffset =
+ ClonedChild.first->getOffset() + ClonedChild.first->getSize();
+ PlainDIEGenerator.addChild(ClonedChild.first);
+ }
+ }
+ assert(ClonedDIE.first == nullptr ||
+ HasPlainChildrenToClone == ClonedDIE.first->hasChildren());
+
+ // Account for the end of children marker.
+ if (HasPlainChildrenToClone)
+ OutOffset += sizeof(int8_t);
+ }
+
+ // Update our size.
+ if (ClonedDIE.first != nullptr)
+ ClonedDIE.first->setSize(OutOffset - ClonedDIE.first->getOffset());
+ return ClonedDIE;
+}
+
+DIE *CompileUnit::createPlainDIEandCloneAttributes(
+ const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator,
+ uint64_t &OutOffset, std::optional<int64_t> &FuncAddressAdjustment,
+ std::optional<int64_t> &VarAddressAdjustment) {
+ uint32_t InputDieIdx = getDIEIndex(InputDieEntry);
+ CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx);
+ DIE *ClonedDIE = nullptr;
bool HasLocationExpressionAddress = false;
if (InputDieEntry->getTag() == dwarf::DW_TAG_subprogram) {
// Get relocation adjustment value for the current function.
FuncAddressAdjustment =
getContaingFile().Addresses->getSubprogramRelocAdjustment(
getDIE(InputDieEntry));
+ } else if (InputDieEntry->getTag() == dwarf::DW_TAG_label) {
+ // Get relocation adjustment value for the current label.
+ std::optional<uint64_t> lowPC =
+ dwarf::toAddress(find(InputDieEntry, dwarf::DW_AT_low_pc));
+ if (lowPC) {
+ LabelMapTy::iterator It = Labels.find(*lowPC);
+ if (It != Labels.end())
+ FuncAddressAdjustment = It->second;
+ }
} else if (InputDieEntry->getTag() == dwarf::DW_TAG_variable) {
// Get relocation adjustment value for the current variable.
std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
@@ -1248,51 +1406,132 @@ DIE *CompileUnit::cloneDIE(const DWARFDebugInfoEntry *InputDieEntry,
VarAddressAdjustment = *LocExprAddrAndRelocAdjustment.second;
}
- DIEGenerator DIEGenerator(Allocator, *this);
- DIE *ClonedDIE = DIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset);
+ ClonedDIE = PlainDIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset);
+
+ // Offset to the DIE would be used after output DIE tree is deleted.
+ // Thus we need to remember DIE offset separately.
rememberDieOutOffset(InputDieIdx, OutOffset);
// Clone Attributes.
- DIEAttributeCloner AttributesCloner(
- ClonedDIE, *this, InputDieEntry, DIEGenerator, FuncAddressAdjustment,
- VarAddressAdjustment, HasLocationExpressionAddress);
+ DIEAttributeCloner AttributesCloner(ClonedDIE, *this, this, InputDieEntry,
+ PlainDIEGenerator, FuncAddressAdjustment,
+ VarAddressAdjustment,
+ HasLocationExpressionAddress);
AttributesCloner.clone();
// Remember accelerator info.
- rememberAcceleratorEntries(InputDieEntry, OutOffset,
- AttributesCloner.AttrInfo);
+ AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this, this);
+ AccelRecordsSaver.save(InputDieEntry, ClonedDIE, AttributesCloner.AttrInfo,
+ nullptr);
- bool HasChildrenToClone = Info.getKeepChildren();
- OutOffset = AttributesCloner.finalizeAbbreviations(HasChildrenToClone);
+ OutOffset =
+ AttributesCloner.finalizeAbbreviations(Info.getKeepPlainChildren());
- if (HasChildrenToClone) {
- // Recursively clone children.
- for (const DWARFDebugInfoEntry *CurChild =
- getFirstChildEntry(InputDieEntry);
- CurChild && CurChild->getAbbreviationDeclarationPtr();
- CurChild = getSiblingEntry(CurChild)) {
- if (DIE *ClonedChild =
- cloneDIE(CurChild, OutOffset, FuncAddressAdjustment,
- VarAddressAdjustment, Allocator)) {
- OutOffset = ClonedChild->getOffset() + ClonedChild->getSize();
- DIEGenerator.addChild(ClonedChild);
- }
+ return ClonedDIE;
+}
+
+/// Allocates output DIE for the specified \p TypeDescriptor.
+DIE *CompileUnit::allocateTypeDie(TypeEntryBody *TypeDescriptor,
+ DIEGenerator &TypeDIEGenerator,
+ dwarf::Tag DieTag, bool IsDeclaration,
+ bool IsParentDeclaration) {
+ DIE *DefinitionDie = TypeDescriptor->Die;
+ // Do not allocate any new DIE if definition DIE is already met.
+ if (DefinitionDie)
+ return nullptr;
+
+ DIE *DeclarationDie = TypeDescriptor->DeclarationDie;
+ bool OldParentIsDeclaration = TypeDescriptor->ParentIsDeclaration;
+
+ if (IsDeclaration && !DeclarationDie) {
+ // Alocate declaration DIE.
+ DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+ if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie,
+ NewDie))
+ return NewDie;
+ } else if (IsDeclaration && !IsParentDeclaration && OldParentIsDeclaration) {
+ // Overwrite existing declaration DIE if it's parent is also an declaration
+ // while parent of current declaration DIE is a definition.
+ if (TypeDescriptor->ParentIsDeclaration.compare_exchange_weak(
+ OldParentIsDeclaration, false)) {
+ DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+ TypeDescriptor->DeclarationDie = NewDie;
+ return NewDie;
+ }
+ } else if (!IsDeclaration && IsParentDeclaration && !DeclarationDie) {
+ // Alocate declaration DIE since parent of current DIE is marked as
+ // declaration.
+ DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+ if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie,
+ NewDie))
+ return NewDie;
+ } else if (!IsDeclaration && !IsParentDeclaration) {
+ // Allocate definition DIE.
+ DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+ if (TypeDescriptor->Die.compare_exchange_weak(DefinitionDie, NewDie)) {
+ TypeDescriptor->ParentIsDeclaration = false;
+ return NewDie;
}
+ }
- // Account for the end of children marker.
- OutOffset += sizeof(int8_t);
+ return nullptr;
+}
+
+TypeEntry *CompileUnit::createTypeDIEandCloneAttributes(
+ const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator,
+ TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit) {
+ assert(ArtificialTypeUnit != nullptr);
+ uint32_t InputDieIdx = getDIEIndex(InputDieEntry);
+
+ TypeEntry *Entry = getDieTypeEntry(InputDieIdx);
+ assert(Entry != nullptr);
+ assert(ClonedParentTypeDIE != nullptr);
+ TypeEntryBody *EntryBody =
+ ArtificialTypeUnit->getTypePool().getOrCreateTypeEntryBody(
+ Entry, ClonedParentTypeDIE);
+ assert(EntryBody);
+
+ bool IsDeclaration =
+ dwarf::toUnsigned(find(InputDieEntry, dwarf::DW_AT_declaration), 0);
+
+ bool ParentIsDeclaration = false;
+ if (std::optional<uint32_t> ParentIdx = InputDieEntry->getParentIdx())
+ ParentIsDeclaration =
+ dwarf::toUnsigned(find(*ParentIdx, dwarf::DW_AT_declaration), 0);
+
+ DIE *OutDIE =
+ allocateTypeDie(EntryBody, TypeDIEGenerator, InputDieEntry->getTag(),
+ IsDeclaration, ParentIsDeclaration);
+
+ if (OutDIE != nullptr) {
+ assert(ArtificialTypeUnit != nullptr);
+ ArtificialTypeUnit->getSectionDescriptor(DebugSectionKind::DebugInfo);
+
+ DIEAttributeCloner AttributesCloner(OutDIE, *this, ArtificialTypeUnit,
+ InputDieEntry, TypeDIEGenerator,
+ std::nullopt, std::nullopt, false);
+ AttributesCloner.clone();
+
+ // Remember accelerator info.
+ AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this,
+ ArtificialTypeUnit);
+ AccelRecordsSaver.save(InputDieEntry, OutDIE, AttributesCloner.AttrInfo,
+ Entry);
+
+ // if AttributesCloner.getOutOffset() == 0 then we need to add
+ // 1 to avoid assertion for zero size. We will subtract it back later.
+ OutDIE->setSize(AttributesCloner.getOutOffset() + 1);
}
- // Update our size.
- ClonedDIE->setSize(OutOffset - ClonedDIE->getOffset());
- return ClonedDIE;
+ return Entry;
}
Error CompileUnit::cloneAndEmitLineTable(Triple &TargetTriple) {
const DWARFDebugLine::LineTable *InputLineTable =
getContaingFile().Dwarf->getLineTableForUnit(&getOrigUnit());
if (InputLineTable == nullptr) {
- warn("cann't load line table.");
+ if (getOrigUnit().getUnitDIE().find(dwarf::DW_AT_stmt_list))
+ warn("cann't load line table.");
return Error::success();
}
@@ -1413,230 +1652,228 @@ void CompileUnit::insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() {
- llvm::errs() << "{\n";
+ llvm::errs() << "{";
llvm::errs() << " Placement: ";
switch (getPlacement()) {
case NotSet:
- llvm::errs() << "NotSet\n";
+ llvm::errs() << "NotSet";
break;
case TypeTable:
- llvm::errs() << "TypeTable\n";
+ llvm::errs() << "TypeTable";
break;
case PlainDwarf:
- llvm::errs() << "PlainDwarf\n";
+ llvm::errs() << "PlainDwarf";
break;
case Both:
- llvm::errs() << "Both\n";
- break;
- case Parent:
- llvm::errs() << "Parent\n";
+ llvm::errs() << "Both";
break;
}
llvm::errs() << " Keep: " << getKeep();
- llvm::errs() << " KeepChildren: " << getKeepChildren();
- llvm::errs() << " ReferrencedBy: " << getReferrencedBy();
+ llvm::errs() << " KeepPlainChildren: " << getKeepPlainChildren();
+ llvm::errs() << " KeepTypeChildren: " << getKeepTypeChildren();
llvm::errs() << " IsInMouduleScope: " << getIsInMouduleScope();
llvm::errs() << " IsInFunctionScope: " << getIsInFunctionScope();
+ llvm::errs() << " IsInAnonNamespaceScope: " << getIsInAnonNamespaceScope();
+ llvm::errs() << " ODRAvailable: " << getODRAvailable();
+ llvm::errs() << " TrackLiveness: " << getTrackLiveness();
llvm::errs() << "}\n";
}
#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-static uint32_t hashFullyQualifiedName(CompileUnit *InputCU, DWARFDie &InputDIE,
- int ChildRecurseDepth = 0) {
- const char *Name = nullptr;
- CompileUnit *CU = InputCU;
- std::optional<DWARFFormValue> RefVal;
+std::optional<std::pair<StringRef, StringRef>>
+CompileUnit::getDirAndFilenameFromLineTable(
+ const DWARFFormValue &FileIdxValue) {
+ uint64_t FileIdx;
+ if (std::optional<uint64_t> Val = FileIdxValue.getAsUnsignedConstant())
+ FileIdx = *Val;
+ else if (std::optional<int64_t> Val = FileIdxValue.getAsSignedConstant())
+ FileIdx = *Val;
+ else if (std::optional<uint64_t> Val = FileIdxValue.getAsSectionOffset())
+ FileIdx = *Val;
+ else
+ return std::nullopt;
- // Usually name`s depth does not exceed 3. Set maximal depth
- // to 1000 here, to avoid infinite loop in case incorrect input
- // DWARF.
- size_t MaxNameDepth = 1000;
- size_t CurNameDepth = 0;
+ return getDirAndFilenameFromLineTable(FileIdx);
+}
- while (CurNameDepth++ < MaxNameDepth) {
- if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
- Name = CurrentName;
+static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) {
+ // Debug info can contain paths from any OS, not necessarily
+ // an OS we're currently running on. Moreover
diff erent compilation units can
+ // be compiled on
diff erent operating systems and linked together later.
+ return sys::path::is_absolute(Path, sys::path::Style::posix) ||
+ sys::path::is_absolute(Path, sys::path::Style::windows);
+}
- if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
- !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
- break;
+std::optional<std::pair<StringRef, StringRef>>
+CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) {
+ FileNamesCache::iterator FileData = FileNames.find(FileIdx);
+ if (FileData != FileNames.end())
+ return std::make_pair(StringRef(FileData->second.first),
+ StringRef(FileData->second.second));
- if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
- break;
+ if (const DWARFDebugLine::LineTable *LineTable =
+ getOrigUnit().getContext().getLineTableForUnit(&getOrigUnit())) {
+ if (LineTable->hasFileAtIndex(FileIdx)) {
- std::optional<std::pair<CompileUnit *, uint32_t>> RefDie =
- CU->resolveDIEReference(*RefVal, ResolveInterCUReferencesMode::Resolve);
- if (!RefDie)
- break;
+ const llvm::DWARFDebugLine::FileNameEntry &Entry =
+ LineTable->Prologue.getFileNameEntry(FileIdx);
+
+ Expected<const char *> Name = Entry.Name.getAsCString();
+ if (!Name) {
+ warn(Name.takeError());
+ return std::nullopt;
+ }
+
+ std::string FileName = *Name;
+ if (isPathAbsoluteOnWindowsOrPosix(FileName)) {
+ FileNamesCache::iterator FileData =
+ FileNames
+ .insert(std::make_pair(
+ FileIdx,
+ std::make_pair(std::string(""), std::move(FileName))))
+ .first;
+ return std::make_pair(StringRef(FileData->second.first),
+ StringRef(FileData->second.second));
+ }
+
+ SmallString<256> FilePath;
+ StringRef IncludeDir;
+ // Be defensive about the contents of Entry.
+ if (getVersion() >= 5) {
+ // DirIdx 0 is the compilation directory, so don't include it for
+ // relative names.
+ if ((Entry.DirIdx != 0) &&
+ Entry.DirIdx < LineTable->Prologue.IncludeDirectories.size()) {
+ Expected<const char *> DirName =
+ LineTable->Prologue.IncludeDirectories[Entry.DirIdx]
+ .getAsCString();
+ if (DirName)
+ IncludeDir = *DirName;
+ else {
+ warn(DirName.takeError());
+ return std::nullopt;
+ }
+ }
+ } else {
+ if (0 < Entry.DirIdx &&
+ Entry.DirIdx <= LineTable->Prologue.IncludeDirectories.size()) {
+ Expected<const char *> DirName =
+ LineTable->Prologue.IncludeDirectories[Entry.DirIdx - 1]
+ .getAsCString();
+ if (DirName)
+ IncludeDir = *DirName;
+ else {
+ warn(DirName.takeError());
+ return std::nullopt;
+ }
+ }
+ }
+
+ StringRef CompDir = getOrigUnit().getCompilationDir();
+
+ if (!CompDir.empty() && !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) {
+ sys::path::append(FilePath, sys::path::Style::native, CompDir);
+ }
- assert(RefDie->second != 0);
+ sys::path::append(FilePath, sys::path::Style::native, IncludeDir);
- CU = RefDie->first;
- InputDIE = RefDie->first->getDIEAtIndex(RefDie->second);
+ FileNamesCache::iterator FileData =
+ FileNames
+ .insert(
+ std::make_pair(FileIdx, std::make_pair(std::string(FilePath),
+ std::move(FileName))))
+ .first;
+ return std::make_pair(StringRef(FileData->second.first),
+ StringRef(FileData->second.second));
+ }
}
- if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
- Name = "(anonymous namespace)";
+ return std::nullopt;
+}
+
+#define MAX_REFERENCIES_DEPTH 1000
+UnitEntryPairTy UnitEntryPairTy::getNamespaceOrigin() {
+ UnitEntryPairTy CUDiePair(*this);
+ std::optional<UnitEntryPairTy> RefDiePair;
+ int refDepth = 0;
+ do {
+ RefDiePair = CUDiePair.CU->resolveDIEReference(
+ CUDiePair.DieEntry, dwarf::DW_AT_extension,
+ ResolveInterCUReferencesMode::Resolve);
+ if (!RefDiePair || !RefDiePair->DieEntry)
+ return CUDiePair;
+
+ CUDiePair = *RefDiePair;
+ } while (refDepth++ < MAX_REFERENCIES_DEPTH);
+
+ return CUDiePair;
+}
- DWARFDie ParentDie = InputDIE.getParent();
- if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
- return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));
+std::optional<UnitEntryPairTy> UnitEntryPairTy::getParent() {
+ if (std::optional<uint32_t> ParentIdx = DieEntry->getParentIdx())
+ return UnitEntryPairTy{CU, CU->getDebugInfoEntry(*ParentIdx)};
- return djbHash(
- (Name ? Name : ""),
- djbHash((Name ? "::" : ""),
- hashFullyQualifiedName(CU, ParentDie, ++ChildRecurseDepth)));
+ return std::nullopt;
}
-void CompileUnit::rememberAcceleratorEntries(
- const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
- AttributesInfo &AttrInfo) {
- if (GlobalData.getOptions().AccelTables.empty())
- return;
+CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(CompileUnit *U)
+ : Ptr(U) {
+ assert(U != nullptr);
+}
- DWARFDie InputDIE = 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 = getGlobalData().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(this, 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);
-
- rememberTypeForAccelerators(AttrInfo.Name, OutOffset,
- InputDieEntry->getTag(), Hash,
- ObjCClassIsImplementation);
- }
- } break;
- case dwarf::DW_TAG_namespace: {
- if (AttrInfo.Name == nullptr)
- AttrInfo.Name =
- getGlobalData().getStringPool().insert("(anonymous namespace)").first;
-
- rememberNamespaceForAccelerators(AttrInfo.Name, OutOffset,
- InputDieEntry->getTag());
- } break;
- case dwarf::DW_TAG_imported_declaration: {
- if (AttrInfo.Name != nullptr)
- rememberNamespaceForAccelerators(AttrInfo.Name, OutOffset,
- InputDieEntry->getTag());
- } break;
- case dwarf::DW_TAG_compile_unit:
- case dwarf::DW_TAG_lexical_block: {
- // Nothing to do.
- } break;
- default:
- if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
- if (AttrInfo.Name != nullptr)
- rememberNameForAccelerators(
- AttrInfo.Name, OutOffset, InputDieEntry->getTag(),
- InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine);
-
- // Look for mangled name recursively if mangled name is not known yet.
- if (AttrInfo.MangledName == nullptr)
- if (const char *LinkageName = InputDIE.getLinkageName())
- AttrInfo.MangledName =
- getGlobalData().getStringPool().insert(LinkageName).first;
-
- if (AttrInfo.MangledName != nullptr &&
- AttrInfo.MangledName != AttrInfo.Name)
- rememberNameForAccelerators(
- AttrInfo.MangledName, OutOffset, InputDieEntry->getTag(),
- InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine);
-
- // Strip template parameters from the short name.
- if (AttrInfo.Name != nullptr && AttrInfo.MangledName != AttrInfo.Name &&
- (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
- if (std::optional<StringRef> Name =
- StripTemplateParameters(AttrInfo.Name->getKey())) {
- StringEntry *NameWithoutTemplateParams =
- getGlobalData().getStringPool().insert(*Name).first;
-
- rememberNameForAccelerators(NameWithoutTemplateParams, OutOffset,
- InputDieEntry->getTag(), true);
- }
- }
+CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(TypeUnit *U) : Ptr(U) {
+ assert(U != nullptr);
+}
- if (AttrInfo.Name)
- rememberObjCAccelerator(InputDieEntry, OutOffset, AttrInfo);
- }
- break;
- }
+DwarfUnit *CompileUnit::OutputUnitVariantPtr::operator->() {
+ if (isCompileUnit())
+ return getAsCompileUnit();
+ else
+ return getAsTypeUnit();
}
-void CompileUnit::rememberObjCAccelerator(
- const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
- AttributesInfo &AttrInfo) {
- std::optional<ObjCSelectorNames> Names =
- getObjCNamesIfSelector(AttrInfo.Name->getKey());
- if (!Names)
- return;
+bool CompileUnit::OutputUnitVariantPtr::isCompileUnit() {
+ return Ptr.is<CompileUnit *>();
+}
- StringEntry *Selector =
- getGlobalData().getStringPool().insert(Names->Selector).first;
- rememberNameForAccelerators(Selector, OutOffset, InputDieEntry->getTag(),
- true);
- StringEntry *ClassName =
- getGlobalData().getStringPool().insert(Names->ClassName).first;
- rememberObjCNameForAccelerators(ClassName, OutOffset,
- InputDieEntry->getTag());
- if (Names->ClassNameNoCategory) {
- StringEntry *ClassNameNoCategory = getGlobalData()
- .getStringPool()
- .insert(*Names->ClassNameNoCategory)
- .first;
- rememberObjCNameForAccelerators(ClassNameNoCategory, OutOffset,
- InputDieEntry->getTag());
- }
- if (Names->MethodNameNoCategory) {
- StringEntry *MethodNameNoCategory =
- getGlobalData()
- .getStringPool()
- .insert(*Names->MethodNameNoCategory)
- .first;
- rememberNameForAccelerators(MethodNameNoCategory, OutOffset,
- InputDieEntry->getTag(), true);
- }
+bool CompileUnit::OutputUnitVariantPtr::isTypeUnit() {
+ return Ptr.is<TypeUnit *>();
+}
+
+CompileUnit *CompileUnit::OutputUnitVariantPtr::getAsCompileUnit() {
+ return Ptr.get<CompileUnit *>();
+}
+
+TypeUnit *CompileUnit::OutputUnitVariantPtr::getAsTypeUnit() {
+ return Ptr.get<TypeUnit *>();
+}
+
+bool CompileUnit::resolveDependenciesAndMarkLiveness(
+ bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
+ if (!Dependencies.get())
+ Dependencies.reset(new DependencyTracker(*this));
+
+ return Dependencies->resolveDependenciesAndMarkLiveness(
+ InterCUProcessingStarted, HasNewInterconnectedCUs);
+}
+
+bool CompileUnit::updateDependenciesCompleteness() {
+ assert(Dependencies.get());
+
+ return Dependencies.get()->updateDependenciesCompleteness();
+}
+
+void CompileUnit::verifyDependencies() {
+ assert(Dependencies.get());
+
+ Dependencies.get()->verifyKeepChain();
+}
+
+ArrayRef<dwarf::Attribute> llvm::dwarflinker_parallel::getODRAttributes() {
+ static dwarf::Attribute ODRAttributes[] = {
+ dwarf::DW_AT_type, dwarf::DW_AT_specification,
+ dwarf::DW_AT_abstract_origin, dwarf::DW_AT_import};
+
+ return ODRAttributes;
}
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
index 54666f684f3a3b0..39e010fd632393d 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
@@ -10,7 +10,6 @@
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
#include "DWARFLinkerUnit.h"
-#include "IndexedValuesMap.h"
#include "llvm/DWARFLinkerParallel/DWARFFile.h"
#include <optional>
@@ -20,6 +19,26 @@ namespace dwarflinker_parallel {
using OffsetToUnitTy = function_ref<CompileUnit *(uint64_t Offset)>;
struct AttributesInfo;
+class SyntheticTypeNameBuilder;
+class DIEGenerator;
+class TypeUnit;
+class DependencyTracker;
+
+class CompileUnit;
+
+/// This is a helper structure which keeps a debug info entry
+/// with it's containing compilation unit.
+struct UnitEntryPairTy {
+ UnitEntryPairTy() = default;
+ UnitEntryPairTy(CompileUnit *CU, const DWARFDebugInfoEntry *DieEntry)
+ : CU(CU), DieEntry(DieEntry) {}
+
+ CompileUnit *CU = nullptr;
+ const DWARFDebugInfoEntry *DieEntry = nullptr;
+
+ UnitEntryPairTy getNamespaceOrigin();
+ std::optional<UnitEntryPairTy> getParent();
+};
enum ResolveInterCUReferencesMode : bool {
Resolve = true,
@@ -42,6 +61,13 @@ class CompileUnit : public DwarfUnit {
/// discovered, type names are assigned if ODR is requested).
LivenessAnalysisDone,
+ /// Check if dependencies have incompatible placement.
+ /// If that is the case modify placement to be compatible.
+ UpdateDependenciesCompleteness,
+
+ /// Type names assigned to DIEs.
+ TypeNamesAssigned,
+
/// Output DWARF is generated.
Cloned,
@@ -50,38 +76,20 @@ class CompileUnit : public DwarfUnit {
/// Resources(Input DWARF, Output DWARF tree) are released.
Cleaned,
+
+ /// Compile Unit should be skipped
+ Skipped
};
CompileUnit(LinkingGlobalData &GlobalData, unsigned ID,
StringRef ClangModuleName, DWARFFile &File,
OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format,
- llvm::endianness Endianess)
- : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
- getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded) {
- UnitName = File.FileName;
- setOutputFormat(Format, Endianess);
- }
+ llvm::endianness Endianess);
CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, unsigned ID,
StringRef ClangModuleName, DWARFFile &File,
OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format,
- llvm::endianness Endianess)
- : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
- OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset),
- Stage(Stage::CreatedNotLoaded) {
- DWARFDie CUDie = OrigUnit.getUnitDIE();
- if (!CUDie)
- return;
-
- setOutputFormat(Format, Endianess);
-
- Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0);
- if (const char *CUName = CUDie.getName(DINameKind::ShortName))
- UnitName = CUName;
- else
- UnitName = File.FileName;
- SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
- }
+ llvm::endianness Endianess);
/// Returns stage of overall processing.
Stage getStage() const { return Stage; }
@@ -114,7 +122,7 @@ class CompileUnit : public DwarfUnit {
/// Navigate DWARF tree and set die properties.
void analyzeDWARFStructure() {
- analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false, false);
+ analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false);
}
/// Cleanup unneeded resources after compile unit is cloned.
@@ -124,25 +132,34 @@ class CompileUnit : public DwarfUnit {
/// This method copies output offsets for referenced DIEs into DIEs patches.
void updateDieRefPatchesWithClonedOffsets();
+ /// Search for subprograms and variables referencing live code and discover
+ /// dependend DIEs. Mark live DIEs, set placement for DIEs.
+ bool resolveDependenciesAndMarkLiveness(
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
+
+ /// Check dependend DIEs for incompatible placement.
+ /// Make placement to be consistent.
+ bool updateDependenciesCompleteness();
+
+ /// Check DIEs to have a consistent marking(keep marking, placement marking).
+ void verifyDependencies();
+
+ /// Search for type entries and assign names.
+ Error assignTypeNames(TypePool &TypePoolRef);
+
/// Kinds of placement for the output die.
enum DieOutputPlacement : uint8_t {
NotSet = 0,
/// Corresponding DIE goes to the type table only.
- /// NOTE: Not used yet.
TypeTable = 1,
/// Corresponding DIE goes to the plain dwarf only.
PlainDwarf = 2,
/// Corresponding DIE goes to type table and to plain dwarf.
- /// NOTE: Not used yet.
Both = 3,
-
- /// Corresponding DIE needs to examine parent to determine
- /// the point of placement.
- /// NOTE: Not used yet.
- Parent = 4
};
/// Information gathered about source DIEs.
@@ -204,10 +221,10 @@ class CompileUnit : public DwarfUnit {
SINGLE_FLAG_METHODS_SET(Keep, 0x08)
/// DIE has children which are part of the linked output.
- SINGLE_FLAG_METHODS_SET(KeepChildren, 0x10)
+ SINGLE_FLAG_METHODS_SET(KeepPlainChildren, 0x10)
- /// DIE is referenced by other DIE.
- SINGLE_FLAG_METHODS_SET(ReferrencedBy, 0x20)
+ /// DIE has children which are part of the type table.
+ SINGLE_FLAG_METHODS_SET(KeepTypeChildren, 0x20)
/// DIE is in module scope.
SINGLE_FLAG_METHODS_SET(IsInMouduleScope, 0x40)
@@ -215,6 +232,18 @@ class CompileUnit : public DwarfUnit {
/// DIE is in function scope.
SINGLE_FLAG_METHODS_SET(IsInFunctionScope, 0x80)
+ /// DIE is in anonymous namespace scope.
+ SINGLE_FLAG_METHODS_SET(IsInAnonNamespaceScope, 0x100)
+
+ /// DIE is available for ODR type deduplication.
+ SINGLE_FLAG_METHODS_SET(ODRAvailable, 0x200)
+
+ /// Track liveness for the DIE.
+ SINGLE_FLAG_METHODS_SET(TrackLiveness, 0x400)
+
+ /// Track liveness for the DIE.
+ SINGLE_FLAG_METHODS_SET(HasAnAddress, 0x800)
+
void unsetFlagsWhichSetDuringLiveAnalysis() {
auto InputData = Flags.load();
while (!Flags.compare_exchange_weak(
@@ -228,6 +257,18 @@ class CompileUnit : public DwarfUnit {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void dump();
#endif
+
+ bool needToPlaceInTypeTable() const {
+ return (getKeep() && (getPlacement() == CompileUnit::TypeTable ||
+ getPlacement() == CompileUnit::Both)) ||
+ getKeepTypeChildren();
+ }
+
+ bool needToKeepInPlainDwarf() const {
+ return (getKeep() && (getPlacement() == CompileUnit::PlainDwarf ||
+ getPlacement() == CompileUnit::Both)) ||
+ getKeepPlainChildren();
+ }
};
/// \defgroup Group of functions returning DIE info.
@@ -273,6 +314,29 @@ class CompileUnit : public DwarfUnit {
->load();
}
+ /// \p Idx index of the DIE.
+ /// \returns type entry.
+ TypeEntry *getDieTypeEntry(uint32_t Idx) {
+ return reinterpret_cast<std::atomic<TypeEntry *> *>(&TypeEntries[Idx])
+ ->load();
+ }
+
+ /// \p InputDieEntry debug info entry.
+ /// \returns DieInfo descriptor.
+ uint64_t getDieOutOffset(const DWARFDebugInfoEntry *InputDieEntry) {
+ return reinterpret_cast<std::atomic<uint64_t> *>(
+ &OutDieOffsetArray[getOrigUnit().getDIEIndex(InputDieEntry)])
+ ->load();
+ }
+
+ /// \p InputDieEntry debug info entry.
+ /// \returns type entry.
+ TypeEntry *getDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry) {
+ return reinterpret_cast<std::atomic<TypeEntry *> *>(
+ &TypeEntries[getOrigUnit().getDIEIndex(InputDieEntry)])
+ ->load();
+ }
+
/// \p Idx index of the DIE.
/// \returns DieInfo descriptor.
void rememberDieOutOffset(uint32_t Idx, uint64_t Offset) {
@@ -280,6 +344,22 @@ class CompileUnit : public DwarfUnit {
->store(Offset);
}
+ /// \p Idx index of the DIE.
+ /// \p Type entry.
+ void setDieTypeEntry(uint32_t Idx, TypeEntry *Entry) {
+ reinterpret_cast<std::atomic<TypeEntry *> *>(&TypeEntries[Idx])
+ ->store(Entry);
+ }
+
+ /// \p InputDieEntry debug info entry.
+ /// \p Type entry.
+ void setDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry,
+ TypeEntry *Entry) {
+ reinterpret_cast<std::atomic<TypeEntry *> *>(
+ &TypeEntries[getOrigUnit().getDIEIndex(InputDieEntry)])
+ ->store(Entry);
+ }
+
/// @}
/// Returns value of DW_AT_low_pc attribute.
@@ -299,9 +379,15 @@ class CompileUnit : public DwarfUnit {
/// RefValue. The resulting DIE might be in another CompileUnit.
/// \returns referenced die and corresponding compilation unit.
/// compilation unit is null if reference could not be resolved.
- std::optional<std::pair<CompileUnit *, uint32_t>>
+ std::optional<UnitEntryPairTy>
resolveDIEReference(const DWARFFormValue &RefValue,
ResolveInterCUReferencesMode CanResolveInterCUReferences);
+
+ std::optional<UnitEntryPairTy>
+ resolveDIEReference(const DWARFDebugInfoEntry *DieEntry,
+ dwarf::Attribute Attr,
+ ResolveInterCUReferencesMode CanResolveInterCUReferences);
+
/// @}
/// Add a function range [\p LowPC, \p HighPC) that is relocated by applying
@@ -312,7 +398,8 @@ class CompileUnit : public DwarfUnit {
const RangesTy &getFunctionRanges() const { return Ranges; }
/// Clone and emit this compilation unit.
- Error cloneAndEmit(std::optional<Triple> TargetTriple);
+ Error cloneAndEmit(std::optional<Triple> TargetTriple,
+ TypeUnit *ArtificialTypeUnit);
/// Clone and emit debug locations(.debug_loc/.debug_loclists).
Error cloneAndEmitDebugLocations();
@@ -324,10 +411,12 @@ class CompileUnit : public DwarfUnit {
Error cloneAndEmitDebugMacro();
// Clone input DIE entry.
- DIE *cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
- std::optional<int64_t> FuncAddressAdjustment,
- std::optional<int64_t> VarAddressAdjustment,
- BumpPtrAllocator &Allocator);
+ std::pair<DIE *, TypeEntry *>
+ cloneDIE(const DWARFDebugInfoEntry *InputDieEntry,
+ TypeEntry *ClonedParentTypeDIE, uint64_t OutOffset,
+ std::optional<int64_t> FuncAddressAdjustment,
+ std::optional<int64_t> VarAddressAdjustment,
+ BumpPtrAllocator &Allocator, TypeUnit *ArtificialTypeUnit);
// Clone and emit line table.
Error cloneAndEmitLineTable(Triple &TargetTriple);
@@ -344,10 +433,13 @@ class CompileUnit : public DwarfUnit {
return DebugAddrIndexMap.getValueIndex(Addr);
}
- /// Returns index(inside .debug_str_offsets) of specified string.
- uint64_t getDebugStrIndex(const StringEntry *String) {
- return DebugStringIndexMap.getValueIndex(String);
- }
+ /// Returns directory and file from the line table by index.
+ std::optional<std::pair<StringRef, StringRef>>
+ getDirAndFilenameFromLineTable(const DWARFFormValue &FileIdxValue);
+
+ /// Returns directory and file from the line table by index.
+ std::optional<std::pair<StringRef, StringRef>>
+ getDirAndFilenameFromLineTable(uint64_t FileIdx);
/// \defgroup Helper methods to access OrigUnit.
///
@@ -469,10 +561,44 @@ class CompileUnit : public DwarfUnit {
/// @}
+ /// Save specified accelerator info \p Info.
+ void saveAcceleratorInfo(const DwarfUnit::AccelInfo &Info) {
+ AcceleratorRecords.add(Info);
+ }
+
+ /// Enumerates all units accelerator records.
+ void
+ forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) override {
+ AcceleratorRecords.forEach(Handler);
+ }
+
+ /// Output unit selector.
+ class OutputUnitVariantPtr {
+ public:
+ OutputUnitVariantPtr(CompileUnit *U);
+ OutputUnitVariantPtr(TypeUnit *U);
+
+ /// Accessor for common functionality.
+ DwarfUnit *operator->();
+
+ bool isCompileUnit();
+
+ bool isTypeUnit();
+
+ /// Returns CompileUnit if applicable.
+ CompileUnit *getAsCompileUnit();
+
+ /// Returns TypeUnit if applicable.
+ TypeUnit *getAsTypeUnit();
+
+ protected:
+ PointerUnion<CompileUnit *, TypeUnit *> Ptr;
+ };
+
private:
/// Navigate DWARF tree recursively and set die properties.
void analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
- bool IsInModule, bool IsInFunction);
+ bool IsODRUnavailableFunctionScope);
struct LinkedLocationExpressionsWithOffsetPatches {
DWARFLocationExpression Expression;
@@ -495,9 +621,6 @@ class CompileUnit : public DwarfUnit {
/// Emit the .debug_addr section fragment for current unit.
Error emitDebugAddrSection();
- /// Emit the .debug_str_offsets section for current unit.
- Error emitDebugStringOffsetSection();
-
/// Emit .debug_aranges.
void emitAranges(AddressRanges &LinkedFunctionRanges);
@@ -521,13 +644,25 @@ class CompileUnit : public DwarfUnit {
void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
uint64_t OffsetToMacroTable, bool hasDWARFv5Header);
- /// Store accelerator information for the \p InputDieEntry.
- void rememberAcceleratorEntries(const DWARFDebugInfoEntry *InputDieEntry,
- uint64_t OutOffset, AttributesInfo &AttrInfo);
+ /// Creates DIE which would be placed into the "Plain" compile unit.
+ DIE *createPlainDIEandCloneAttributes(
+ const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator,
+ uint64_t &OutOffset, std::optional<int64_t> &FuncAddressAdjustment,
+ std::optional<int64_t> &VarAddressAdjustment);
+
+ /// Creates DIE which would be placed into the "Type" compile unit.
+ TypeEntry *createTypeDIEandCloneAttributes(
+ const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator,
+ TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit);
+
+ /// Create output DIE inside specified \p TypeDescriptor.
+ DIE *allocateTypeDie(TypeEntryBody *TypeDescriptor,
+ DIEGenerator &TypeDIEGenerator, dwarf::Tag DieTag,
+ bool IsDeclaration, bool IsParentDeclaration);
- /// Store ObjC accelerator information for the \p InputDieEntry.
- void rememberObjCAccelerator(const DWARFDebugInfoEntry *InputDieEntry,
- uint64_t OutOffset, AttributesInfo &AttrInfo);
+ /// Enumerate \p DieEntry children and assign names for them.
+ Error assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry,
+ SyntheticTypeNameBuilder &NameBuilder);
/// DWARFFile containing this compile unit.
DWARFFile &File;
@@ -535,6 +670,9 @@ class CompileUnit : public DwarfUnit {
/// Pointer to the paired compile unit from the input DWARF.
DWARFUnit *OrigUnit = nullptr;
+ /// The DW_AT_language of this unit.
+ std::optional<uint16_t> Language;
+
/// Line table for this unit.
const DWARFDebugLine::LineTable *LineTablePtr = nullptr;
@@ -547,10 +685,9 @@ class CompileUnit : public DwarfUnit {
/// Maps an address into the index inside .debug_addr section.
IndexedValuesMap<uint64_t> DebugAddrIndexMap;
- /// Maps a string into the index inside .debug_str_offsets section.
- IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
+ std::unique_ptr<DependencyTracker> Dependencies;
- /// \defgroup Data Members accessed asinchroniously.
+ /// \defgroup Data Members accessed asinchronously.
///
/// @{
OffsetToUnitTy getUnitFromOffset;
@@ -558,6 +695,9 @@ class CompileUnit : public DwarfUnit {
std::optional<uint64_t> LowPc;
uint64_t HighPc = 0;
+ /// Flag indicating whether type de-duplication is forbidden.
+ bool NoODR = true;
+
/// The ranges in that map are the PC ranges for functions in this unit,
/// associated with the PC offset to apply to the addresses to get
/// the linked address.
@@ -565,7 +705,8 @@ class CompileUnit : public DwarfUnit {
std::mutex RangesMutex;
/// The DW_AT_low_pc of each DW_TAG_label.
- SmallDenseMap<uint64_t, uint64_t, 1> Labels;
+ using LabelMapTy = SmallDenseMap<uint64_t, uint64_t, 1>;
+ LabelMapTy Labels;
std::mutex LabelsMutex;
/// This field keeps current stage of overall compile unit processing.
@@ -574,9 +715,19 @@ class CompileUnit : public DwarfUnit {
/// DIE info indexed by DIE index.
SmallVector<DIEInfo> DieInfoArray;
SmallVector<uint64_t> OutDieOffsetArray;
+ SmallVector<TypeEntry *> TypeEntries;
+
+ /// The list of accelerator records for this unit.
+ ArrayList<AccelInfo> AcceleratorRecords;
/// @}
};
+/// \returns list of attributes referencing type DIEs which might be
+/// deduplicated.
+/// Note: it does not include DW_AT_containing_type attribute to avoid
+/// infinite recursion.
+ArrayRef<dwarf::Attribute> getODRAttributes();
+
} // end of namespace dwarflinker_parallel
} // end namespace llvm
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
index 78d0b5468d0495e..220739a1214c690 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
@@ -9,6 +9,7 @@
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
+#include "TypePool.h"
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
#include "llvm/DWARFLinkerParallel/StringPool.h"
#include "llvm/Support/PerThreadBumpPtrAllocator.h"
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
index a755d540aef99e1..c49b9ef0cdf989d 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
@@ -9,6 +9,8 @@
#include "DWARFLinkerImpl.h"
#include "DIEGenerator.h"
#include "DependencyTracker.h"
+#include "Utils.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/ThreadPool.h"
@@ -16,6 +18,50 @@
namespace llvm {
namespace dwarflinker_parallel {
+DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
+ MessageHandlerTy WarningHandler,
+ TranslatorFuncTy StringsTranslator)
+ : UniqueUnitID(0), DebugStrStrings(GlobalData),
+ DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {
+ GlobalData.setTranslator(StringsTranslator);
+ GlobalData.setErrorHandler(ErrorHandler);
+ GlobalData.setWarningHandler(WarningHandler);
+}
+
+DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData,
+ DWARFFile &File,
+ StringMap<uint64_t> &ClangModules,
+ std::atomic<size_t> &UniqueUnitID,
+ std::optional<Triple> TargetTriple)
+ : OutputSections(GlobalData), InputDWARFFile(File),
+ ClangModules(ClangModules), TargetTriple(TargetTriple),
+ UniqueUnitID(UniqueUnitID) {
+
+ if (File.Dwarf) {
+ if (!File.Dwarf->compile_units().empty())
+ CompileUnits.reserve(File.Dwarf->getNumCompileUnits());
+
+ // Set context format&endianness based on the input file.
+ Format.Version = File.Dwarf->getMaxVersion();
+ Format.AddrSize = File.Dwarf->getCUAddrSize();
+ Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little
+ : llvm::endianness::big;
+ }
+}
+
+DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit(
+ DWARFFile &File, std::unique_ptr<CompileUnit> Unit)
+ : File(File), Unit(std::move(Unit)) {}
+
+DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit(
+ LinkContext::RefModuleUnit &&Other)
+ : File(Other.File), Unit(std::move(Other.Unit)) {}
+
+void DWARFLinkerImpl::LinkContext::addModulesCompileUnit(
+ LinkContext::RefModuleUnit &&Unit) {
+ ModulesCompileUnits.emplace_back(std::move(Unit));
+}
+
Error DWARFLinkerImpl::createEmitter(const Triple &TheTriple,
OutputFileType FileType,
raw_pwrite_stream &OutFile) {
@@ -55,6 +101,10 @@ void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,
}
}
+void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) {
+ ObjectContexts.reserve(ObjFilesNum);
+}
+
Error DWARFLinkerImpl::link() {
// reset compile unit unique ID counter.
UniqueUnitID = 0;
@@ -71,6 +121,7 @@ Error DWARFLinkerImpl::link() {
? llvm::endianness::little
: llvm::endianness::big;
}
+ std::optional<uint16_t> Language;
for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {
if (Context->InputDWARFFile.Dwarf.get() == nullptr) {
@@ -101,6 +152,23 @@ Error DWARFLinkerImpl::link() {
std::max(GlobalFormat.AddrSize, Context->getFormParams().AddrSize);
Context->setOutputFormat(Context->getFormParams(), GlobalEndianness);
+
+ // FIXME: move creation of CompileUnits into the addObjectFile.
+ // This would allow to not scan for context Language and Modules state
+ // twice. And then following handling might be removed.
+ for (const std::unique_ptr<DWARFUnit> &OrigCU :
+ Context->InputDWARFFile.Dwarf->compile_units()) {
+ DWARFDie UnitDie = OrigCU.get()->getUnitDIE();
+
+ if (!Language) {
+ if (std::optional<DWARFFormValue> Val =
+ UnitDie.find(dwarf::DW_AT_language)) {
+ uint16_t LangVal = dwarf::toUnsigned(Val, 0);
+ if (isODRLanguage(LangVal))
+ Language = LangVal;
+ }
+ }
+ }
}
if (GlobalFormat.AddrSize == 0) {
@@ -113,6 +181,14 @@ Error DWARFLinkerImpl::link() {
CommonSections.setOutputFormat(GlobalFormat, GlobalEndianness);
+ if (!GlobalData.Options.NoODR && Language.has_value()) {
+ parallel::TaskGroup TGroup;
+ TGroup.spawn([&]() {
+ ArtificialTypeUnit = std::make_unique<TypeUnit>(
+ GlobalData, UniqueUnitID++, Language, GlobalFormat, GlobalEndianness);
+ });
+ }
+
// Set parallel options.
if (GlobalData.getOptions().Threads == 0)
parallel::strategy = optimal_concurrency(OverallNumberOfCU);
@@ -123,7 +199,7 @@ Error DWARFLinkerImpl::link() {
if (GlobalData.getOptions().Threads == 1) {
for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {
// Link object file.
- if (Error Err = Context->link())
+ if (Error Err = Context->link(ArtificialTypeUnit.get()))
GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);
Context->InputDWARFFile.unload();
@@ -133,7 +209,7 @@ Error DWARFLinkerImpl::link() {
for (std::unique_ptr<LinkContext> &Context : ObjectContexts)
Pool.async([&]() {
// Link object file.
- if (Error Err = Context->link())
+ if (Error Err = Context->link(ArtificialTypeUnit.get()))
GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);
Context->InputDWARFFile.unload();
@@ -142,6 +218,19 @@ Error DWARFLinkerImpl::link() {
Pool.wait();
}
+ if (ArtificialTypeUnit.get() != nullptr && !ArtificialTypeUnit->getTypePool()
+ .getRoot()
+ ->getValue()
+ .load()
+ ->Children.empty()) {
+ std::optional<Triple> OutTriple = TheDwarfEmitter.get() == nullptr
+ ? std::optional<Triple>(std::nullopt)
+ : TheDwarfEmitter->getTargetTriple();
+
+ if (Error Err = ArtificialTypeUnit.get()->finishCloningAndEmit(OutTriple))
+ return Err;
+ }
+
// At this stage each compile units are cloned to their own set of debug
// sections. Now, update patches, assign offsets and assemble final file
// glueing debug tables from each compile unit.
@@ -175,6 +264,11 @@ Error DWARFLinkerImpl::validateAndUpdateOptions() {
"set number of threads to 1 to make --verbose to work properly.", "");
}
+ // Do not do types deduplication in case --update.
+ if (GlobalData.getOptions().UpdateIndexTablesOnly &&
+ !GlobalData.Options.NoODR)
+ GlobalData.Options.NoODR = true;
+
return Error::success();
}
@@ -369,7 +463,7 @@ Error DWARFLinkerImpl::LinkContext::loadClangModule(
return Error::success();
}
-Error DWARFLinkerImpl::LinkContext::link() {
+Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) {
InterCUProcessingStarted = false;
if (!InputDWARFFile.Dwarf)
return Error::success();
@@ -380,7 +474,7 @@ Error DWARFLinkerImpl::LinkContext::link() {
// Link modules compile units first.
parallelForEach(ModulesCompileUnits, [&](RefModuleUnit &RefModule) {
- linkSingleCompileUnit(*RefModule.Unit);
+ linkSingleCompileUnit(*RefModule.Unit, ArtificialTypeUnit);
});
// Check for live relocations. If there is no any live relocation then we
@@ -420,43 +514,78 @@ Error DWARFLinkerImpl::LinkContext::link() {
// Link self-sufficient compile units and discover inter-connected compile
// units.
parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
- linkSingleCompileUnit(*CU);
+ linkSingleCompileUnit(*CU, ArtificialTypeUnit);
});
// Link all inter-connected units.
if (HasNewInterconnectedCUs) {
InterCUProcessingStarted = true;
- do {
- HasNewInterconnectedCUs = false;
-
- // Load inter-connected units.
- parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
- if (CU->isInterconnectedCU()) {
- CU->maybeResetToLoadedStage();
- linkSingleCompileUnit(*CU, CompileUnit::Stage::Loaded);
- }
- });
+ if (Error Err = finiteLoop([&]() -> Expected<bool> {
+ HasNewInterconnectedCUs = false;
+
+ // Load inter-connected units.
+ parallelForEach(
+ CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+ if (CU->isInterconnectedCU()) {
+ CU->maybeResetToLoadedStage();
+ linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+ CompileUnit::Stage::Loaded);
+ }
+ });
+
+ // Do liveness analysis for inter-connected units.
+ parallelForEach(CompileUnits,
+ [&](std::unique_ptr<CompileUnit> &CU) {
+ linkSingleCompileUnit(
+ *CU, ArtificialTypeUnit,
+ CompileUnit::Stage::LivenessAnalysisDone);
+ });
+
+ return HasNewInterconnectedCUs.load();
+ }))
+ return Err;
+
+ // Update dependencies.
+ if (Error Err = finiteLoop([&]() -> Expected<bool> {
+ HasNewGlobalDependency = false;
+ parallelForEach(
+ CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+ linkSingleCompileUnit(
+ *CU, ArtificialTypeUnit,
+ CompileUnit::Stage::UpdateDependenciesCompleteness);
+ });
+ return HasNewGlobalDependency.load();
+ }))
+ return Err;
+ parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+ if (CU->isInterconnectedCU() &&
+ CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone)
+ CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness);
+ });
- // Do liveness analysis for inter-connected units.
- parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
- linkSingleCompileUnit(*CU, CompileUnit::Stage::LivenessAnalysisDone);
- });
- } while (HasNewInterconnectedCUs);
+ // Assign type names.
+ parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+ linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+ CompileUnit::Stage::TypeNamesAssigned);
+ });
// Clone inter-connected units.
parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
- linkSingleCompileUnit(*CU, CompileUnit::Stage::Cloned);
+ linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+ CompileUnit::Stage::Cloned);
});
// Update patches for inter-connected units.
parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
- linkSingleCompileUnit(*CU, CompileUnit::Stage::PatchesUpdated);
+ linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+ CompileUnit::Stage::PatchesUpdated);
});
// Release data.
parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
- linkSingleCompileUnit(*CU, CompileUnit::Stage::Cleaned);
+ linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+ CompileUnit::Stage::Cleaned);
});
}
@@ -483,78 +612,119 @@ Error DWARFLinkerImpl::LinkContext::link() {
}
void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit(
- CompileUnit &CU, enum CompileUnit::Stage DoUntilStage) {
- while (CU.getStage() < DoUntilStage) {
- if (InterCUProcessingStarted != CU.isInterconnectedCU())
- return;
+ CompileUnit &CU, TypeUnit *ArtificialTypeUnit,
+ enum CompileUnit::Stage DoUntilStage) {
+ if (InterCUProcessingStarted != CU.isInterconnectedCU())
+ return;
- switch (CU.getStage()) {
- case CompileUnit::Stage::CreatedNotLoaded: {
- // Load input compilation unit DIEs.
- // Analyze properties of DIEs.
- if (!CU.loadInputDIEs()) {
- // We do not need to do liveness analysis for invalud compilation unit.
- CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);
- } else {
- CU.analyzeDWARFStructure();
-
- // The registerModuleReference() condition effectively skips
- // over fully resolved skeleton units. This second pass of
- // registerModuleReferences doesn't do any new work, but it
- // will collect top-level errors, which are suppressed. Module
- // warnings were already displayed in the first iteration.
- if (registerModuleReference(
- CU.getOrigUnit().getUnitDIE(), nullptr,
- [](const DWARFUnit &) {}, 0))
- CU.setStage(CompileUnit::Stage::PatchesUpdated);
- else
- CU.setStage(CompileUnit::Stage::Loaded);
- }
- } break;
+ if (Error Err = finiteLoop([&]() -> Expected<bool> {
+ if (CU.getStage() >= DoUntilStage)
+ return false;
+
+ switch (CU.getStage()) {
+ case CompileUnit::Stage::CreatedNotLoaded: {
+ // Load input compilation unit DIEs.
+ // Analyze properties of DIEs.
+ if (!CU.loadInputDIEs()) {
+ // We do not need to do liveness analysis for invalid compilation
+ // unit.
+ CU.setStage(CompileUnit::Stage::Skipped);
+ } else {
+ CU.analyzeDWARFStructure();
+
+ // The registerModuleReference() condition effectively skips
+ // over fully resolved skeleton units. This second pass of
+ // registerModuleReferences doesn't do any new work, but it
+ // will collect top-level errors, which are suppressed. Module
+ // warnings were already displayed in the first iteration.
+ if (registerModuleReference(
+ CU.getOrigUnit().getUnitDIE(), nullptr,
+ [](const DWARFUnit &) {}, 0))
+ CU.setStage(CompileUnit::Stage::PatchesUpdated);
+ else
+ CU.setStage(CompileUnit::Stage::Loaded);
+ }
+ } break;
- case CompileUnit::Stage::Loaded: {
- // Mark all the DIEs that need to be present in the generated output.
- // If ODR requested, build type names.
- if (!DependencyTracker(*this).resolveDependenciesAndMarkLiveness(CU)) {
- assert(HasNewInterconnectedCUs);
- return;
- }
+ case CompileUnit::Stage::Loaded: {
+ // Mark all the DIEs that need to be present in the generated output.
+ // If ODR requested, build type names.
+ if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted,
+ HasNewInterconnectedCUs)) {
+ assert(HasNewInterconnectedCUs &&
+ "Flag indicating new inter-connections is not set");
+ return false;
+ }
- CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);
- } break;
+ CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);
+ } break;
- case CompileUnit::Stage::LivenessAnalysisDone:
+ case CompileUnit::Stage::LivenessAnalysisDone: {
+ if (InterCUProcessingStarted) {
+ if (CU.updateDependenciesCompleteness())
+ HasNewGlobalDependency = true;
+ return false;
+ } else {
+ if (Error Err = finiteLoop([&]() -> Expected<bool> {
+ return CU.updateDependenciesCompleteness();
+ }))
+ return std::move(Err);
+
+ CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness);
+ }
+ } break;
+ case CompileUnit::Stage::UpdateDependenciesCompleteness:
#ifndef NDEBUG
- DependencyTracker::verifyKeepChain(CU);
+ CU.verifyDependencies();
#endif
- // Clone input compile unit.
- if (CU.isClangModule() || GlobalData.getOptions().UpdateIndexTablesOnly ||
- CU.getContaingFile().Addresses->hasValidRelocs()) {
- if (Error Err = CU.cloneAndEmit(TargetTriple))
- CU.error(std::move(Err));
- }
+ if (ArtificialTypeUnit) {
+ if (Error Err =
+ CU.assignTypeNames(ArtificialTypeUnit->getTypePool()))
+ return std::move(Err);
+ }
+ CU.setStage(CompileUnit::Stage::TypeNamesAssigned);
+ break;
+
+ case CompileUnit::Stage::TypeNamesAssigned:
+ // Clone input compile unit.
+ if (CU.isClangModule() ||
+ GlobalData.getOptions().UpdateIndexTablesOnly ||
+ CU.getContaingFile().Addresses->hasValidRelocs()) {
+ if (Error Err = CU.cloneAndEmit(TargetTriple, ArtificialTypeUnit))
+ return std::move(Err);
+ }
- CU.setStage(CompileUnit::Stage::Cloned);
- break;
+ CU.setStage(CompileUnit::Stage::Cloned);
+ break;
- case CompileUnit::Stage::Cloned:
- // Update DIEs referencies.
- CU.updateDieRefPatchesWithClonedOffsets();
- CU.setStage(CompileUnit::Stage::PatchesUpdated);
- break;
+ case CompileUnit::Stage::Cloned:
+ // Update DIEs referencies.
+ CU.updateDieRefPatchesWithClonedOffsets();
+ CU.setStage(CompileUnit::Stage::PatchesUpdated);
+ break;
- case CompileUnit::Stage::PatchesUpdated:
- // Cleanup resources.
- CU.cleanupDataAfterClonning();
- CU.setStage(CompileUnit::Stage::Cleaned);
- break;
+ case CompileUnit::Stage::PatchesUpdated:
+ // Cleanup resources.
+ CU.cleanupDataAfterClonning();
+ CU.setStage(CompileUnit::Stage::Cleaned);
+ break;
- case CompileUnit::Stage::Cleaned:
- assert(false);
- break;
- }
+ case CompileUnit::Stage::Cleaned:
+ assert(false);
+ break;
+
+ case CompileUnit::Stage::Skipped:
+ // Nothing to do.
+ break;
+ }
+
+ return true;
+ })) {
+ CU.error(std::move(Err));
+ CU.cleanupDataAfterClonning();
+ CU.setStage(CompileUnit::Stage::Skipped);
}
}
@@ -716,6 +886,9 @@ void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() {
// units into the resulting file.
emitCommonSectionsAndWriteCompileUnitsToTheOutput();
+ if (ArtificialTypeUnit.get() != nullptr)
+ ArtificialTypeUnit.reset();
+
// Write common debug sections into the resulting file.
writeCommonSectionsToTheOutput();
@@ -861,47 +1034,101 @@ void DWARFLinkerImpl::forEachOutputString(
});
});
- CU->AcceleratorRecords.forEach([&](DwarfUnit::AccelInfo &Info) {
+ CU->forEachAcceleratorRecord([&](DwarfUnit::AccelInfo &Info) {
StringHandler(DebugStr, Info.String);
});
});
+
+ if (ArtificialTypeUnit.get() != nullptr) {
+ ArtificialTypeUnit->forEach([&](SectionDescriptor &OutSection) {
+ OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {
+ StringHandler(StringDestinationKind::DebugStr, Patch.String);
+ });
+
+ OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {
+ StringHandler(StringDestinationKind::DebugLineStr, Patch.String);
+ });
+
+ OutSection.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) {
+ if (Patch.Die == nullptr)
+ return;
+
+ StringHandler(StringDestinationKind::DebugStr, Patch.String);
+ });
+
+ OutSection.ListDebugTypeLineStrPatch.forEach(
+ [&](DebugTypeLineStrPatch &Patch) {
+ if (Patch.Die == nullptr)
+ return;
+
+ StringHandler(StringDestinationKind::DebugStr, Patch.String);
+ });
+ });
+ }
}
void DWARFLinkerImpl::forEachObjectSectionsSet(
function_ref<void(OutputSections &)> SectionsSetHandler) {
- // Handle all modules first(before regular compilation units).
+ // Handle artificial type unit first.
+ if (ArtificialTypeUnit.get() != nullptr)
+ SectionsSetHandler(*ArtificialTypeUnit);
+
+ // Then all modules(before regular compilation units).
for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
- SectionsSetHandler(*ModuleUnit.Unit);
+ if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)
+ SectionsSetHandler(*ModuleUnit.Unit);
+ // Finally all compilation units.
for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) {
// Handle object file common sections.
SectionsSetHandler(*Context);
// Handle compilation units.
for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
- SectionsSetHandler(*CU);
+ if (CU->getStage() != CompileUnit::Stage::Skipped)
+ SectionsSetHandler(*CU);
}
}
+void DWARFLinkerImpl::forEachCompileAndTypeUnit(
+ function_ref<void(DwarfUnit *CU)> UnitHandler) {
+ if (ArtificialTypeUnit.get() != nullptr)
+ UnitHandler(ArtificialTypeUnit.get());
+
+ // Enumerate module units.
+ for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
+ for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
+ if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)
+ UnitHandler(ModuleUnit.Unit.get());
+
+ // Enumerate compile units.
+ for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
+ for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
+ if (CU->getStage() != CompileUnit::Stage::Skipped)
+ UnitHandler(CU.get());
+}
+
void DWARFLinkerImpl::forEachCompileUnit(
function_ref<void(CompileUnit *CU)> UnitHandler) {
// Enumerate module units.
for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
- UnitHandler(ModuleUnit.Unit.get());
+ if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)
+ UnitHandler(ModuleUnit.Unit.get());
// Enumerate compile units.
for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
- UnitHandler(CU.get());
+ if (CU->getStage() != CompileUnit::Stage::Skipped)
+ UnitHandler(CU.get());
}
void DWARFLinkerImpl::patchOffsetsAndSizes() {
forEachObjectSectionsSet([&](OutputSections &SectionsSet) {
SectionsSet.forEach([&](SectionDescriptor &OutSection) {
- SectionsSet.applyPatches(OutSection, DebugStrStrings,
- DebugLineStrStrings);
+ SectionsSet.applyPatches(OutSection, DebugStrStrings, DebugLineStrStrings,
+ ArtificialTypeUnit.get());
});
});
}
@@ -1005,8 +1232,9 @@ void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) {
AccelTable<AppleAccelTableStaticOffsetData> AppleObjC;
AccelTable<AppleAccelTableStaticTypeData> AppleTypes;
- forEachCompileUnit([&](CompileUnit *CU) {
- CU->AcceleratorRecords.forEach([&](const DwarfUnit::AccelInfo &Info) {
+ forEachCompileAndTypeUnit([&](DwarfUnit *CU) {
+ CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {
+ uint64_t OutOffset = Info.OutOffset;
switch (Info.Type) {
case DwarfUnit::AccelType::None: {
llvm_unreachable("Unknown accelerator record");
@@ -1015,25 +1243,25 @@ void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) {
AppleNamespaces.addName(
*DebugStrStrings.getExistingEntry(Info.String),
CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
- Info.OutOffset);
+ OutOffset);
} break;
case DwarfUnit::AccelType::Name: {
AppleNames.addName(
*DebugStrStrings.getExistingEntry(Info.String),
CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
- Info.OutOffset);
+ OutOffset);
} break;
case DwarfUnit::AccelType::ObjC: {
AppleObjC.addName(
*DebugStrStrings.getExistingEntry(Info.String),
CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
- Info.OutOffset);
+ OutOffset);
} break;
case DwarfUnit::AccelType::Type: {
AppleTypes.addName(
*DebugStrStrings.getExistingEntry(Info.String),
CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
- Info.OutOffset,
+ OutOffset,
Info.Tag,
Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation
: 0,
@@ -1136,16 +1364,13 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) {
unsigned Id = 0;
- forEachCompileUnit([&](CompileUnit *CU) {
- CompUnits.push_back(
- CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)
- .StartOffset);
- CUidToIdx[CU->getUniqueID()] = Id++;
-
- CU->AcceleratorRecords.forEach([&](const DwarfUnit::AccelInfo &Info) {
+ forEachCompileAndTypeUnit([&](DwarfUnit *CU) {
+ bool HasRecords = false;
+ CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {
if (DebugNames.get() == nullptr)
DebugNames = std::make_unique<DWARF5AccelTable>();
+ HasRecords = true;
switch (Info.Type) {
case DwarfUnit::AccelType::Name:
case DwarfUnit::AccelType::Namespace:
@@ -1158,6 +1383,13 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) {
break; // Nothing to do.
};
});
+
+ if (HasRecords) {
+ CompUnits.push_back(
+ CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)
+ .StartOffset);
+ CUidToIdx[CU->getUniqueID()] = Id++;
+ }
});
if (DebugNames.get() != nullptr) {
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
index 45dc506b9947ea1..60018eea121f204 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
@@ -11,6 +11,7 @@
#include "DWARFEmitterImpl.h"
#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerTypeUnit.h"
#include "StringEntryToDwarfStringPoolEntryMap.h"
#include "llvm/ADT/AddressRanges.h"
#include "llvm/CodeGen/AccelTable.h"
@@ -25,13 +26,7 @@ class DWARFLinkerImpl : public DWARFLinker {
public:
DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
MessageHandlerTy WarningHandler,
- TranslatorFuncTy StringsTranslator)
- : UniqueUnitID(0), DebugStrStrings(GlobalData),
- DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {
- GlobalData.setTranslator(StringsTranslator);
- GlobalData.setErrorHandler(ErrorHandler);
- GlobalData.setWarningHandler(WarningHandler);
- }
+ TranslatorFuncTy StringsTranslator);
/// Create debug info emitter.
Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
@@ -74,11 +69,7 @@ class DWARFLinkerImpl : public DWARFLinker {
}
/// Do not unique types according to ODR.
- void setNoODR(bool) override {
- // FIXME: set option when ODR mode will be supported.
- // getOptions().NoODR = NoODR;
- GlobalData.Options.NoODR = true;
- }
+ void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; }
/// Update index tables only(do not modify rest of DWARF).
void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override {
@@ -114,9 +105,7 @@ class DWARFLinkerImpl : public DWARFLinker {
}
/// Set estimated objects files amount, for preliminary data allocation.
- void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override {
- ObjectContexts.reserve(ObjFilesNum);
- }
+ void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override;
/// Set verification handler which would be used to report verification
/// errors.
@@ -173,10 +162,8 @@ class DWARFLinkerImpl : public DWARFLinker {
/// Keep information for referenced clang module: already loaded DWARF info
/// of the clang module and a CompileUnit of the module.
struct RefModuleUnit {
- RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit)
- : File(File), Unit(std::move(Unit)) {}
- RefModuleUnit(RefModuleUnit &&Other)
- : File(Other.File), Unit(std::move(Other.Unit)) {}
+ RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit);
+ RefModuleUnit(RefModuleUnit &&Other);
RefModuleUnit(const RefModuleUnit &) = delete;
DWARFFile &File;
@@ -209,28 +196,15 @@ class DWARFLinkerImpl : public DWARFLinker {
/// if new inter-connected units were found.
std::atomic<bool> HasNewInterconnectedCUs = {false};
+ std::atomic<bool> HasNewGlobalDependency = {false};
+
/// Counter for compile units ID.
std::atomic<size_t> &UniqueUnitID;
LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File,
StringMap<uint64_t> &ClangModules,
std::atomic<size_t> &UniqueUnitID,
- std::optional<Triple> TargetTriple)
- : OutputSections(GlobalData), InputDWARFFile(File),
- ClangModules(ClangModules), TargetTriple(TargetTriple),
- UniqueUnitID(UniqueUnitID) {
-
- if (File.Dwarf) {
- if (!File.Dwarf->compile_units().empty())
- CompileUnits.reserve(File.Dwarf->getNumCompileUnits());
-
- // Set context format&endianness based on the input file.
- Format.Version = File.Dwarf->getMaxVersion();
- Format.AddrSize = File.Dwarf->getCUAddrSize();
- Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little
- : llvm::endianness::big;
- }
- }
+ std::optional<Triple> TargetTriple);
/// Check whether specified \p CUDie is a Clang module reference.
/// if \p Quiet is false then display error messages.
@@ -259,9 +233,7 @@ class DWARFLinkerImpl : public DWARFLinker {
unsigned Indent = 0);
/// Add Compile Unit corresponding to the module.
- void addModulesCompileUnit(RefModuleUnit &&Unit) {
- ModulesCompileUnits.emplace_back(std::move(Unit));
- }
+ void addModulesCompileUnit(RefModuleUnit &&Unit);
/// Computes the total size of the debug info.
uint64_t getInputDebugInfoSize() const {
@@ -277,11 +249,11 @@ class DWARFLinkerImpl : public DWARFLinker {
}
/// Link compile units for this context.
- Error link();
+ Error link(TypeUnit *ArtificialTypeUnit);
/// Link specified compile unit until specified stage.
void linkSingleCompileUnit(
- CompileUnit &CU,
+ CompileUnit &CU, TypeUnit *ArtificialTypeUnit,
enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned);
/// Emit invariant sections.
@@ -331,6 +303,9 @@ class DWARFLinkerImpl : public DWARFLinker {
void forEachObjectSectionsSet(
function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler);
+ /// Enumerates all compile and type units.
+ void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler);
+
/// Enumerates all comple units.
void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler);
@@ -368,6 +343,9 @@ class DWARFLinkerImpl : public DWARFLinker {
/// Mapping the PCM filename to the DwoId.
StringMap<uint64_t> ClangModules;
std::mutex ClangModulesMutex;
+
+ /// Type unit.
+ std::unique_ptr<TypeUnit> ArtificialTypeUnit;
/// @}
/// \defgroup Data members accessed sequentially.
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
new file mode 100644
index 000000000000000..9d5c213085c2935
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
@@ -0,0 +1,391 @@
+//===- DWARFLinkerTypeUnit.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 "DWARFLinkerTypeUnit.h"
+#include "DIEGenerator.h"
+#include "DWARFEmitterImpl.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+using namespace llvm::dwarflinker_parallel;
+
+TypeUnit::TypeUnit(LinkingGlobalData &GlobalData, unsigned ID,
+ std::optional<uint16_t> Language, dwarf::FormParams Format,
+ endianness Endianess)
+ : DwarfUnit(GlobalData, ID, ""), Language(Language),
+ AcceleratorRecords(&GlobalData.getAllocator()) {
+
+ UnitName = "__artificial_type_unit";
+
+ setOutputFormat(Format, Endianess);
+
+ // Create line table prologue.
+ LineTable.Prologue.FormParams = getFormParams();
+ LineTable.Prologue.MinInstLength = 1;
+ LineTable.Prologue.MaxOpsPerInst = 1;
+ LineTable.Prologue.DefaultIsStmt = 1;
+ LineTable.Prologue.LineBase = -5;
+ LineTable.Prologue.LineRange = 14;
+ LineTable.Prologue.OpcodeBase = 13;
+ LineTable.Prologue.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 1};
+
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+}
+
+void TypeUnit::createDIETree(BumpPtrAllocator &Allocator) {
+ prepareDataForTreeCreation();
+
+ // TaskGroup is created here as internal code has calls to
+ // PerThreadBumpPtrAllocator which should be called from the task group task.
+ parallel::TaskGroup TG;
+ TG.spawn([&]() {
+ SectionDescriptor &DebugInfoSection =
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+ SectionDescriptor &DebugLineSection =
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);
+
+ DIEGenerator DIETreeGenerator(Allocator, *this);
+ OffsetsPtrVector PatchesOffsets;
+
+ // Create a Die for artificial compilation unit for types.
+ DIE *UnitDIE = DIETreeGenerator.createDIE(dwarf::DW_TAG_compile_unit, 0);
+ uint64_t OutOffset = getDebugInfoHeaderSize();
+ UnitDIE->setOffset(OutOffset);
+
+ SmallString<200> ProducerString;
+ ProducerString += "llvm DWARFLinkerParallel library version ";
+ DebugInfoSection.notePatchWithOffsetUpdate(
+ DebugStrPatch{
+ {OutOffset},
+ GlobalData.getStringPool().insert(ProducerString.str()).first},
+ PatchesOffsets);
+ OutOffset += DIETreeGenerator
+ .addStringPlaceholderAttribute(dwarf::DW_AT_producer,
+ dwarf::DW_FORM_strp)
+ .second;
+
+ if (Language) {
+ OutOffset += DIETreeGenerator
+ .addScalarAttribute(dwarf::DW_AT_language,
+ dwarf::DW_FORM_data2, *Language)
+ .second;
+ }
+
+ DebugInfoSection.notePatchWithOffsetUpdate(
+ DebugStrPatch{{OutOffset},
+ GlobalData.getStringPool().insert(getUnitName()).first},
+ PatchesOffsets);
+ OutOffset += DIETreeGenerator
+ .addStringPlaceholderAttribute(dwarf::DW_AT_name,
+ dwarf::DW_FORM_strp)
+ .second;
+
+ if (!LineTable.Prologue.FileNames.empty()) {
+ DebugInfoSection.notePatchWithOffsetUpdate(
+ DebugOffsetPatch{OutOffset, &DebugLineSection}, PatchesOffsets);
+
+ OutOffset += DIETreeGenerator
+ .addScalarAttribute(dwarf::DW_AT_stmt_list,
+ dwarf::DW_FORM_sec_offset, 0xbaddef)
+ .second;
+ }
+
+ DebugInfoSection.notePatchWithOffsetUpdate(
+ DebugStrPatch{{OutOffset}, GlobalData.getStringPool().insert("").first},
+ PatchesOffsets);
+ OutOffset += DIETreeGenerator
+ .addStringPlaceholderAttribute(dwarf::DW_AT_comp_dir,
+ dwarf::DW_FORM_strp)
+ .second;
+
+ if (!DebugStringIndexMap.empty()) {
+ // Type unit is assumed to be emitted first. Thus we can use direct value
+ // for DW_AT_str_offsets_base attribute(No need to fix it up with unit
+ // offset value).
+ OutOffset += DIETreeGenerator
+ .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
+ dwarf::DW_FORM_sec_offset,
+ getDebugStrOffsetsHeaderSize())
+ .second;
+ }
+
+ UnitDIE->setSize(OutOffset - UnitDIE->getOffset() + 1);
+ OutOffset =
+ finalizeTypeEntryRec(UnitDIE->getOffset(), UnitDIE, Types.getRoot());
+
+ // Update patch offsets.
+ for (uint64_t *OffsetPtr : PatchesOffsets)
+ *OffsetPtr += getULEB128Size(UnitDIE->getAbbrevNumber());
+
+ setOutUnitDIE(UnitDIE);
+ });
+}
+
+void TypeUnit::prepareDataForTreeCreation() {
+ SectionDescriptor &DebugInfoSection =
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+
+ // Type unit data created parallelly. So the order of data is not
+ // deterministic. Order data here if we need deterministic output.
+
+ parallel::TaskGroup TG;
+
+ if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+ TG.spawn([&]() {
+ // Sort types to have a deterministic output.
+ Types.sortTypes();
+ });
+ }
+
+ TG.spawn([&]() {
+ if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+ // Sort decl type patches to have a deterministic output.
+ std::function<bool(const DebugTypeDeclFilePatch &LHS,
+ const DebugTypeDeclFilePatch &RHS)>
+ PatchesComparator = [&](const DebugTypeDeclFilePatch &LHS,
+ const DebugTypeDeclFilePatch &RHS) {
+ return LHS.Directory->first() < RHS.Directory->first() ||
+ (!(RHS.Directory->first() < LHS.Directory->first()) &&
+ LHS.FilePath->first() < RHS.FilePath->first());
+ };
+ // Sort patches to have a deterministic output.
+ DebugInfoSection.ListDebugTypeDeclFilePatch.sort(PatchesComparator);
+ }
+
+ // Update DW_AT_decl_file attribute
+ dwarf::Form DeclFileForm =
+ getScalarFormForValue(
+ DebugInfoSection.ListDebugTypeDeclFilePatch.size())
+ .first;
+
+ DebugInfoSection.ListDebugTypeDeclFilePatch.forEach(
+ [&](DebugTypeDeclFilePatch &Patch) {
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ uint32_t FileIdx =
+ addFileNameIntoLinetable(Patch.Directory, Patch.FilePath);
+
+ unsigned DIESize = Patch.Die->getSize();
+ DIEGenerator DIEGen(Patch.Die, Types.getThreadLocalAllocator(),
+ *this);
+
+ DIESize += DIEGen
+ .addScalarAttribute(dwarf::DW_AT_decl_file,
+ DeclFileForm, FileIdx)
+ .second;
+ Patch.Die->setSize(DIESize);
+ });
+ });
+
+ if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+ // Sort patches to have a deterministic output.
+ TG.spawn([&]() {
+ forEach([&](SectionDescriptor &OutSection) {
+ std::function<bool(const DebugStrPatch &LHS, const DebugStrPatch &RHS)>
+ StrPatchesComparator =
+ [&](const DebugStrPatch &LHS, const DebugStrPatch &RHS) {
+ return LHS.String->getKey() < RHS.String->getKey();
+ };
+ OutSection.ListDebugStrPatch.sort(StrPatchesComparator);
+
+ std::function<bool(const DebugTypeStrPatch &LHS,
+ const DebugTypeStrPatch &RHS)>
+ TypeStrPatchesComparator = [&](const DebugTypeStrPatch &LHS,
+ const DebugTypeStrPatch &RHS) {
+ return LHS.String->getKey() < RHS.String->getKey();
+ };
+ OutSection.ListDebugTypeStrPatch.sort(TypeStrPatchesComparator);
+ });
+ });
+ }
+
+ if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+ // Sort patches to have a deterministic output.
+ TG.spawn([&]() {
+ forEach([&](SectionDescriptor &OutSection) {
+ std::function<bool(const DebugLineStrPatch &LHS,
+ const DebugLineStrPatch &RHS)>
+ LineStrPatchesComparator = [&](const DebugLineStrPatch &LHS,
+ const DebugLineStrPatch &RHS) {
+ return LHS.String->getKey() < RHS.String->getKey();
+ };
+ OutSection.ListDebugLineStrPatch.sort(LineStrPatchesComparator);
+
+ std::function<bool(const DebugTypeLineStrPatch &LHS,
+ const DebugTypeLineStrPatch &RHS)>
+ TypeLineStrPatchesComparator =
+ [&](const DebugTypeLineStrPatch &LHS,
+ const DebugTypeLineStrPatch &RHS) {
+ return LHS.String->getKey() < RHS.String->getKey();
+ };
+ OutSection.ListDebugTypeLineStrPatch.sort(TypeLineStrPatchesComparator);
+ });
+ });
+ }
+}
+
+uint64_t TypeUnit::finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE,
+ TypeEntry *Entry) {
+ bool HasChildren = !Entry->getValue().load()->Children.empty();
+ DIEGenerator DIEGen(OutDIE, Types.getThreadLocalAllocator(), *this);
+ OutOffset += DIEGen.finalizeAbbreviations(HasChildren, nullptr);
+ OutOffset += OutDIE->getSize() - 1;
+
+ if (HasChildren) {
+ Entry->getValue().load()->Children.forEach([&](TypeEntry *ChildEntry) {
+ DIE *ChildDIE = &ChildEntry->getValue().load()->getFinalDie();
+ DIEGen.addChild(ChildDIE);
+
+ ChildDIE->setOffset(OutOffset);
+
+ OutOffset = finalizeTypeEntryRec(OutOffset, ChildDIE, ChildEntry);
+ });
+
+ // End of children marker.
+ OutOffset += sizeof(int8_t);
+ }
+
+ OutDIE->setSize(OutOffset - OutDIE->getOffset());
+ return OutOffset;
+}
+
+uint32_t TypeUnit::addFileNameIntoLinetable(StringEntry *Dir,
+ StringEntry *FileName) {
+ uint32_t DirIdx = 0;
+
+ if (Dir->first() == "") {
+ DirIdx = 0;
+ } else {
+ DirectoriesMapTy::iterator DirEntry = DirectoriesMap.find(Dir);
+ if (DirEntry == DirectoriesMap.end()) {
+ // We currently do not support more than UINT32_MAX directories.
+ assert(LineTable.Prologue.IncludeDirectories.size() < UINT32_MAX);
+ DirIdx = LineTable.Prologue.IncludeDirectories.size();
+ DirectoriesMap.insert({Dir, DirIdx});
+ LineTable.Prologue.IncludeDirectories.push_back(
+ DWARFFormValue::createFromPValue(dwarf::DW_FORM_string,
+ Dir->getKeyData()));
+ } else {
+ DirIdx = DirEntry->second;
+ }
+
+ if (getVersion() < 5)
+ DirIdx++;
+ }
+
+ uint32_t FileIdx = 0;
+ FilenamesMapTy::iterator FileEntry = FileNamesMap.find({FileName, DirIdx});
+ if (FileEntry == FileNamesMap.end()) {
+ // We currently do not support more than UINT32_MAX files.
+ assert(LineTable.Prologue.FileNames.size() < UINT32_MAX);
+ FileIdx = LineTable.Prologue.FileNames.size();
+ FileNamesMap.insert({{FileName, DirIdx}, FileIdx});
+ LineTable.Prologue.FileNames.push_back(DWARFDebugLine::FileNameEntry());
+ LineTable.Prologue.FileNames.back().Name = DWARFFormValue::createFromPValue(
+ dwarf::DW_FORM_string, FileName->getKeyData());
+ LineTable.Prologue.FileNames.back().DirIdx = DirIdx;
+ } else {
+ FileIdx = FileEntry->second;
+ }
+
+ return getVersion() < 5 ? FileIdx + 1 : FileIdx;
+}
+
+std::pair<dwarf::Form, uint8_t>
+TypeUnit::getScalarFormForValue(uint64_t Value) const {
+ if (Value > 0xFFFFFFFF)
+ return std::make_pair(dwarf::DW_FORM_data8, 8);
+
+ if (Value > 0xFFFF)
+ return std::make_pair(dwarf::DW_FORM_data4, 4);
+
+ if (Value > 0xFF)
+ return std::make_pair(dwarf::DW_FORM_data2, 2);
+
+ return std::make_pair(dwarf::DW_FORM_data1, 1);
+}
+
+uint8_t TypeUnit::getSizeByAttrForm(dwarf::Form Form) const {
+ if (Form == dwarf::DW_FORM_data1)
+ return 1;
+
+ if (Form == dwarf::DW_FORM_data2)
+ return 2;
+
+ if (Form == dwarf::DW_FORM_data4)
+ return 4;
+
+ if (Form == dwarf::DW_FORM_data8)
+ return 8;
+
+ if (Form == dwarf::DW_FORM_data16)
+ return 16;
+
+ llvm_unreachable("Unsupported Attr Form");
+}
+
+Error TypeUnit::finishCloningAndEmit(std::optional<Triple> TargetTriple) {
+ BumpPtrAllocator Allocator;
+ createDIETree(Allocator);
+
+ if (getGlobalData().getOptions().NoOutput || (getOutUnitDIE() == nullptr))
+ return Error::success();
+
+ // Create sections ahead so that they should not be created asynchronously
+ // later.
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets);
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugAbbrev);
+ if (llvm::is_contained(GlobalData.getOptions().AccelTables,
+ DWARFLinker::AccelTableKind::Pub)) {
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugPubNames);
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugPubTypes);
+ }
+
+ SmallVector<std::function<Error(void)>> Tasks;
+
+ // Add task for emitting .debug_line section.
+ if (!LineTable.Prologue.FileNames.empty()) {
+ Tasks.push_back([&]() -> Error {
+ assert(TargetTriple.has_value());
+ return emitDebugLine(*TargetTriple, LineTable);
+ });
+ }
+
+ // Add task for emitting .debug_info section.
+ Tasks.push_back([&]() -> Error { return emitDebugInfo(*TargetTriple); });
+
+ // Add task for emitting Pub accelerator sections.
+ if (llvm::is_contained(GlobalData.getOptions().AccelTables,
+ DWARFLinker::AccelTableKind::Pub)) {
+ Tasks.push_back([&]() -> Error {
+ emitPubAccelerators();
+ return Error::success();
+ });
+ }
+
+ // Add task for emitting .debug_str_offsets section.
+ Tasks.push_back([&]() -> Error { return emitDebugStringOffsetSection(); });
+
+ // Add task for emitting .debug_abbr section.
+ Tasks.push_back([&]() -> Error { return emitAbbreviations(); });
+
+ if (auto Err = parallelForEachError(
+ Tasks, [&](std::function<Error(void)> F) { return F(); }))
+ return Err;
+
+ return Error::success();
+}
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
new file mode 100644
index 000000000000000..97e620eee0c4245
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
@@ -0,0 +1,138 @@
+//===- DWARFLinkerTypeUnit.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_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H
+#define LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H
+
+#include "DWARFLinkerUnit.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// Type Unit is used to represent an artificial compilation unit
+/// which keeps all type information. This type information is referenced
+/// from other compilation units.
+class TypeUnit : public DwarfUnit {
+public:
+ TypeUnit(LinkingGlobalData &GlobalData, unsigned ID,
+ std::optional<uint16_t> Language, dwarf::FormParams Format,
+ llvm::endianness Endianess);
+
+ /// Generates DIE tree based on information from TypesMap.
+ void createDIETree(BumpPtrAllocator &Allocator);
+
+ /// Emits resulting dwarf based on information from DIE tree.
+ Error finishCloningAndEmit(std::optional<Triple> TargetTriple);
+
+ /// Returns global type pool.
+ TypePool &getTypePool() { return Types; }
+
+ /// TypeUnitAccelInfo extends AccelInfo structure with type specific fileds.
+ /// We need these additional fields to decide whether OutDIE should have an
+ /// accelerator record or not. The TypeEntryBodyPtr can refer to the
+ /// declaration DIE and definition DIE corresponding to the type entry.
+ /// Only one of them would be used in final output. So if TypeUnitAccelInfo
+ /// refers OutDIE which does not match with TypeEntryBodyPtr->getFinalDie()
+ /// then such record should be skipped.
+ struct TypeUnitAccelInfo : public AccelInfo {
+ /// Pointer to the output DIE which owns this accelerator record.
+ DIE *OutDIE = nullptr;
+
+ /// Pointer to the type entry body.
+ TypeEntryBody *TypeEntryBodyPtr = nullptr;
+ };
+
+ /// Enumerates all accelerator records and call \p Handler for each.
+ void
+ forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) override {
+ AcceleratorRecords.forEach([&](TypeUnitAccelInfo &Info) {
+ // Check whether current record is for the final DIE.
+ assert(Info.TypeEntryBodyPtr != nullptr);
+
+ if (&Info.TypeEntryBodyPtr->getFinalDie() != Info.OutDIE)
+ return;
+
+ Info.OutOffset = Info.OutDIE->getOffset();
+ Handler(Info);
+ });
+ }
+
+ /// Returns index for the specified \p String inside .debug_str_offsets.
+ uint64_t getDebugStrIndex(const StringEntry *String) override {
+ std::unique_lock<std::mutex> LockGuard(DebugStringIndexMapMutex);
+ return DebugStringIndexMap.getValueIndex(String);
+ }
+
+ /// Adds \p Info to the unit's accelerator records.
+ void saveAcceleratorInfo(const TypeUnitAccelInfo &Info) {
+ AcceleratorRecords.add(Info);
+ }
+
+private:
+ /// Type DIEs are partially created at clonning stage. They are organised
+ /// as a tree using type entries. This function links DIEs(corresponding
+ /// to the type entries) into the tree structure.
+ uint64_t finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE,
+ TypeEntry *Entry);
+
+ /// Prepares DIEs to be linked into the tree.
+ void prepareDataForTreeCreation();
+
+ /// Add specified \p Dir and \p Filename into the line table
+ /// of this type unit.
+ uint32_t addFileNameIntoLinetable(StringEntry *Dir, StringEntry *FileName);
+
+ std::pair<dwarf::Form, uint8_t> getScalarFormForValue(uint64_t Value) const;
+
+ uint8_t getSizeByAttrForm(dwarf::Form Form) const;
+
+ struct CmpStringEntryRef {
+ bool operator()(const StringEntry *LHS, const StringEntry *RHS) const {
+ return LHS->first() < RHS->first();
+ }
+ };
+ struct CmpDirIDStringEntryRef {
+ bool operator()(const std::pair<StringEntry *, uint64_t> &LHS,
+ const std::pair<StringEntry *, uint64_t> &RHS) const {
+ return LHS.second < RHS.second ||
+ (!(RHS.second < LHS.second) &&
+ LHS.first->first() < RHS.first->first());
+ }
+ };
+
+ /// The DW_AT_language of this unit.
+ std::optional<uint16_t> Language;
+
+ /// This unit line table.
+ DWARFDebugLine::LineTable LineTable;
+
+ /// Data members keeping file names for line table.
+ using DirectoriesMapTy = std::map<StringEntry *, size_t, CmpStringEntryRef>;
+ using FilenamesMapTy = std::map<std::pair<StringEntry *, uint64_t>, size_t,
+ CmpDirIDStringEntryRef>;
+
+ DirectoriesMapTy DirectoriesMap;
+ FilenamesMapTy FileNamesMap;
+
+ /// Type DIEs tree.
+ TypePool Types;
+
+ /// List of accelerator entries for this unit.
+ ArrayList<TypeUnitAccelInfo> AcceleratorRecords;
+
+ /// Guard for DebugStringIndexMap.
+ std::mutex DebugStringIndexMapMutex;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
index 1503015f015575b..b1da1900d65ef70 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
@@ -88,7 +88,7 @@ void DwarfUnit::emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
encodeULEB128(0, AbbrevSection.OS);
}
-Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) {
+Error DwarfUnit::emitDebugInfo(const Triple &TargetTriple) {
DIE *OutUnitDIE = getOutUnitDIE();
if (OutUnitDIE == nullptr)
return Error::success();
@@ -119,18 +119,60 @@ Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) {
return Error::success();
}
-Error DwarfUnit::emitDebugLine(Triple &TargetTriple,
+Error DwarfUnit::emitDebugLine(const Triple &TargetTriple,
const DWARFDebugLine::LineTable &OutLineTable) {
DebugLineSectionEmitter DebugLineEmitter(TargetTriple, *this);
return DebugLineEmitter.emit(OutLineTable);
}
+Error DwarfUnit::emitDebugStringOffsetSection() {
+ if (getVersion() < 5)
+ return Error::success();
+
+ if (DebugStringIndexMap.empty())
+ return Error::success();
+
+ SectionDescriptor &OutDebugStrOffsetsSection =
+ getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets);
+
+ // Emit section header.
+
+ // Emit length.
+ OutDebugStrOffsetsSection.emitUnitLength(0xBADDEF);
+ uint64_t OffsetAfterSectionLength = OutDebugStrOffsetsSection.OS.tell();
+
+ // Emit version.
+ OutDebugStrOffsetsSection.emitIntVal(5, 2);
+
+ // Emit padding.
+ OutDebugStrOffsetsSection.emitIntVal(0, 2);
+
+ // Emit index to offset map.
+ for (const StringEntry *String : DebugStringIndexMap.getValues()) {
+ // Note patch for string offset value.
+ OutDebugStrOffsetsSection.notePatch(
+ DebugStrPatch{{OutDebugStrOffsetsSection.OS.tell()}, String});
+
+ // Emit placeholder for offset value.
+ OutDebugStrOffsetsSection.emitOffset(0xBADDEF);
+ }
+
+ // Patch section length.
+ OutDebugStrOffsetsSection.apply(
+ OffsetAfterSectionLength -
+ OutDebugStrOffsetsSection.getFormParams().getDwarfOffsetByteSize(),
+ dwarf::DW_FORM_sec_offset,
+ OutDebugStrOffsetsSection.OS.tell() - OffsetAfterSectionLength);
+
+ return Error::success();
+}
+
/// Emit the pubnames or pubtypes section contribution for \p
/// Unit into \p Sec. The data is provided in \p Info.
std::optional<uint64_t>
DwarfUnit::emitPubAcceleratorEntry(SectionDescriptor &OutSection,
- DwarfUnit::AccelInfo &Info,
+ const DwarfUnit::AccelInfo &Info,
std::optional<uint64_t> LengthOffset) {
if (!LengthOffset) {
// Emit the header.
@@ -160,7 +202,7 @@ void DwarfUnit::emitPubAccelerators() {
std::optional<uint64_t> NamesLengthOffset;
std::optional<uint64_t> TypesLengthOffset;
- AcceleratorRecords.forEach([&](DwarfUnit::AccelInfo &Info) {
+ forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {
if (Info.AvoidForPubSections)
return;
diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
index 0835fad1e667a38..9640a8ee711eb0e 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
@@ -10,6 +10,7 @@
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
#include "DWARFLinkerGlobalData.h"
+#include "IndexedValuesMap.h"
#include "OutputSections.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
@@ -30,16 +31,11 @@ class DwarfUnit : public OutputSections {
DwarfUnit(LinkingGlobalData &GlobalData, unsigned ID,
StringRef ClangModuleName)
: OutputSections(GlobalData), ID(ID), ClangModuleName(ClangModuleName),
- OutUnitDIE(nullptr) {
- AcceleratorRecords.setAllocator(&GlobalData.getAllocator());
- }
+ OutUnitDIE(nullptr) {}
/// Unique id of the unit.
unsigned getUniqueID() const { return ID; }
- /// Return language of this unit.
- uint16_t getLanguage() const { return Language; }
-
/// Returns size of this(newly generated) compile unit.
uint64_t getUnitSize() const { return UnitSize; }
@@ -91,11 +87,14 @@ class DwarfUnit : public OutputSections {
Error emitAbbreviations();
/// Emit .debug_info section for unit DIEs.
- Error emitDebugInfo(Triple &TargetTriple);
+ Error emitDebugInfo(const Triple &TargetTriple);
/// Emit .debug_line section.
- Error emitDebugLine(Triple &TargetTriple,
+ Error emitDebugLine(const Triple &TargetTriple,
const DWARFDebugLine::LineTable &OutLineTable);
+
+ /// Emit the .debug_str_offsets section for current unit.
+ Error emitDebugStringOffsetSection();
/// @}
/// \defgroup Methods used for reporting warnings and errors:
@@ -124,7 +123,7 @@ class DwarfUnit : public OutputSections {
StringEntry *String = nullptr;
/// Output offset of the DIE this entry describes.
- uint64_t OutOffset = 0;
+ uint64_t OutOffset;
/// Hash of the fully qualified name.
uint32_t QualifiedNameHash = 0;
@@ -135,71 +134,27 @@ class DwarfUnit : public OutputSections {
/// Type of this accelerator record.
AccelType Type = AccelType::None;
- /// Avoid using this entry for pub sections.
+ /// Avoid emitting this entry for pub sections.
bool AvoidForPubSections : 1;
/// Is this an ObjC class implementation?
bool ObjcClassImplementation : 1;
};
- void rememberNameForAccelerators(StringEntry *Name, uint64_t OutOffset,
- dwarf::Tag Tag, bool AvoidForPubSections) {
- AccelInfo Info;
-
- Info.Type = AccelType::Name;
- Info.String = Name;
- Info.OutOffset = OutOffset;
- Info.Tag = Tag;
- Info.AvoidForPubSections = AvoidForPubSections;
-
- AcceleratorRecords.add(Info);
- }
- void rememberNamespaceForAccelerators(StringEntry *Name, uint64_t OutOffset,
- dwarf::Tag Tag) {
- AccelInfo Info;
-
- Info.Type = AccelType::Namespace;
- Info.String = Name;
- Info.OutOffset = OutOffset;
- Info.Tag = Tag;
-
- AcceleratorRecords.add(Info);
- }
- void rememberObjCNameForAccelerators(StringEntry *Name, uint64_t OutOffset,
- dwarf::Tag Tag) {
- AccelInfo Info;
-
- Info.Type = AccelType::ObjC;
- Info.String = Name;
- Info.OutOffset = OutOffset;
- Info.Tag = Tag;
- Info.AvoidForPubSections = true;
-
- AcceleratorRecords.add(Info);
- }
- void rememberTypeForAccelerators(StringEntry *Name, uint64_t OutOffset,
- dwarf::Tag Tag, uint32_t QualifiedNameHash,
- bool ObjcClassImplementation) {
- AccelInfo Info;
-
- Info.Type = AccelType::Type;
- Info.String = Name;
- Info.OutOffset = OutOffset;
- Info.Tag = Tag;
- Info.QualifiedNameHash = QualifiedNameHash;
- Info.ObjcClassImplementation = ObjcClassImplementation;
-
- AcceleratorRecords.add(Info);
- }
-
/// Emit .debug_pubnames and .debug_pubtypes for \p Unit.
void emitPubAccelerators();
- /// Accelerator tables data.
- ArrayList<AccelInfo> AcceleratorRecords;
+ /// Enumerates accelerator data.
+ virtual void
+ forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) = 0;
/// @}
+ /// Returns index(inside .debug_str_offsets) of specified string.
+ virtual uint64_t getDebugStrIndex(const StringEntry *String) {
+ return DebugStringIndexMap.getValueIndex(String);
+ }
+
protected:
/// Emit single abbreviation entry.
void emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
@@ -207,16 +162,12 @@ class DwarfUnit : public OutputSections {
/// Emit single pubnames/pubtypes accelerator entry.
std::optional<uint64_t>
- emitPubAcceleratorEntry(SectionDescriptor &OutSection,
- DwarfUnit::AccelInfo &Info,
+ emitPubAcceleratorEntry(SectionDescriptor &OutSection, const AccelInfo &Info,
std::optional<uint64_t> LengthOffset);
/// Unique ID for the unit.
unsigned ID = 0;
- /// The DW_AT_language of this unit.
- uint16_t Language = 0;
-
/// The name of this unit.
std::string UnitName;
@@ -239,8 +190,31 @@ class DwarfUnit : public OutputSections {
/// Output unit DIE.
DIE *OutUnitDIE = nullptr;
+
+ /// Cache for file names for this unit.
+ using FileNamesCache =
+ DenseMap<uint64_t, std::pair<std::string, std::string>>;
+ FileNamesCache FileNames;
+
+ /// Maps a string into the index inside .debug_str_offsets section.
+ IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
};
+inline bool isODRLanguage(uint16_t Language) {
+ switch (Language) {
+ case dwarf::DW_LANG_C_plus_plus:
+ case dwarf::DW_LANG_C_plus_plus_03:
+ case dwarf::DW_LANG_C_plus_plus_11:
+ case dwarf::DW_LANG_C_plus_plus_14:
+ case dwarf::DW_LANG_ObjC_plus_plus:
+ return true;
+ default:
+ return false;
+ };
+
+ return false;
+}
+
} // end of namespace dwarflinker_parallel
} // end namespace llvm
diff --git a/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h b/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
index 4aef0d0d67303da..fc7f8cbc4a8e7bd 100644
--- a/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
+++ b/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
@@ -149,6 +149,7 @@ class DebugLineSectionEmitter {
// A null-terminated string containing the full or relative path name of a
// source file.
Section.emitString(File.Name.getForm(), *FileNameStr);
+
// An unsigned LEB128 number representing the directory index of a
// directory in the include_directories section.
encodeULEB128(File.DirIdx, Section.OS);
diff --git a/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp b/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
index 3a69c3821e8b52b..8767cc0fc6e77c4 100644
--- a/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
@@ -12,18 +12,20 @@
namespace llvm {
namespace dwarflinker_parallel {
-#ifndef NDEBUG
/// A broken link in the keep chain. By recording both the parent and the child
/// we can show only broken links for DIEs with multiple children.
struct BrokenLink {
- BrokenLink(DWARFDie Parent, DWARFDie Child) : Parent(Parent), Child(Child) {}
+ BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
+ : Parent(Parent), Child(Child), Message(Message) {}
DWARFDie Parent;
DWARFDie Child;
+ std::string Message;
};
/// Verify the keep chain by looking for DIEs that are kept but who's parent
/// isn't.
-void DependencyTracker::verifyKeepChain(CompileUnit &CU) {
+void DependencyTracker::verifyKeepChain() {
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
SmallVector<DWARFDie> Worklist;
Worklist.push_back(CU.getOrigUnit().getUnitDIE());
@@ -37,176 +39,585 @@ void DependencyTracker::verifyKeepChain(CompileUnit &CU) {
if (!Current.isValid())
continue;
- const bool CurrentDieIsKept = CU.getDIEInfo(Current).getKeep() ||
- CU.getDIEInfo(Current).getKeepChildren();
+ CompileUnit::DIEInfo &CurrentInfo =
+ CU.getDIEInfo(Current.getDebugInfoEntry());
+ const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
+ const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
for (DWARFDie Child : reverse(Current.children())) {
Worklist.push_back(Child);
- const bool ChildDieIsKept = CU.getDIEInfo(Child).getKeep() ||
- CU.getDIEInfo(Child).getKeepChildren();
- if (!CurrentDieIsKept && ChildDieIsKept)
- BrokenLinks.emplace_back(Current, Child);
+ CompileUnit::DIEInfo &ChildInfo =
+ CU.getDIEInfo(Child.getDebugInfoEntry());
+ const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
+ const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
+
+ if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
+ BrokenLinks.emplace_back(Current, Child,
+ "Found invalid link in keep chain");
+
+ if (Child.getTag() == dwarf::DW_TAG_subprogram) {
+ if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
+ &CU, Child.getDebugInfoEntry()))) {
+ BrokenLinks.emplace_back(Current, Child,
+ "Live subprogram is not marked as kept");
+ }
+ }
+
+ if (!ChildInfo.getODRAvailable()) {
+ assert(!ChildTypeDieIsKept);
+ continue;
+ }
+
+ if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
+ BrokenLinks.emplace_back(Current, Child,
+ "Found invalid link in keep chain");
+
+ if (CurrentInfo.getIsInAnonNamespaceScope() &&
+ ChildInfo.needToPlaceInTypeTable()) {
+ BrokenLinks.emplace_back(Current, Child,
+ "Found invalid placement marking for member "
+ "of anonymous namespace");
+ }
}
}
if (!BrokenLinks.empty()) {
for (BrokenLink Link : BrokenLinks) {
- WithColor::error() << formatv(
- "Found invalid link in keep chain between {0:x} and {1:x}\n",
- Link.Parent.getOffset(), Link.Child.getOffset());
+ errs() << "\n=================================\n";
+ WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
+ Link.Parent.getOffset(),
+ Link.Child.getOffset());
- errs() << "Parent:";
+ errs() << "\nParent:";
Link.Parent.dump(errs(), 0, {});
+ errs() << "\n";
CU.getDIEInfo(Link.Parent).dump();
- errs() << "Child:";
+ errs() << "\nChild:";
Link.Child.dump(errs(), 2, {});
+ errs() << "\n";
CU.getDIEInfo(Link.Child).dump();
}
report_fatal_error("invalid keep chain");
}
-}
#endif
+}
-bool DependencyTracker::resolveDependenciesAndMarkLiveness(CompileUnit &CU) {
- // We do not track liveness inside Clang modules. We also do not track
- // liveness if UpdateIndexTablesOnly is requested.
- TrackLiveness = !(CU.isClangModule() ||
- CU.getGlobalData().getOptions().UpdateIndexTablesOnly);
+bool DependencyTracker::resolveDependenciesAndMarkLiveness(
+ bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
RootEntriesWorkList.clear();
// Search for live root DIEs.
- collectRootsToKeep(CU, CU.getDebugInfoEntry(0));
+ CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
+ CUInfo.setPlacement(CompileUnit::PlainDwarf);
+ collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
+ std::nullopt, false);
// Mark live DIEs as kept.
- return markLiveRootsAsKept();
+ return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
+ HasNewInterconnectedCUs);
}
-void DependencyTracker::collectRootsToKeep(CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry) {
- if (!TrackLiveness) {
- addItemToWorklist(CU, Entry);
+void DependencyTracker::addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
+ std::optional<UnitEntryPairTy> ReferencedBy) {
+ if (ReferencedBy) {
+ RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
return;
}
- switch (Entry->getTag()) {
- case dwarf::DW_TAG_subprogram:
- case dwarf::DW_TAG_label:
- if (isLiveSubprogramEntry(CU, Entry)) {
- addItemToWorklist(CU, Entry);
+ RootEntriesWorkList.emplace_back(Action, Entry);
+}
+
+void DependencyTracker::collectRootsToKeep(
+ const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
+ bool IsLiveParent) {
+ for (const DWARFDebugInfoEntry *CurChild =
+ Entry.CU->getFirstChildEntry(Entry.DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = Entry.CU->getSiblingEntry(CurChild)) {
+ UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
+ CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
+
+ bool IsLiveChild = false;
+
+ switch (CurChild->getTag()) {
+ case dwarf::DW_TAG_label: {
+ IsLiveChild = isLiveSubprogramEntry(ChildEntry);
+
+ // Keep label referencing live address.
+ // Keep label which is child of live parent entry.
+ if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
+ addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,
+ ReferencedBy);
+ }
+ } break;
+ case dwarf::DW_TAG_subprogram: {
+ IsLiveChild = isLiveSubprogramEntry(ChildEntry);
+
+ // Keep subprogram referencing live address.
+ if (IsLiveChild) {
+ // If subprogram is in module scope and this module allows ODR
+ // deduplication set "TypeTable" placement, otherwise set "" placement
+ LiveRootWorklistActionTy Action =
+ (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
+ ? LiveRootWorklistActionTy::MarkTypeEntryRec
+ : LiveRootWorklistActionTy::MarkLiveEntryRec;
+
+ addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
+ }
+ } break;
+ case dwarf::DW_TAG_constant:
+ case dwarf::DW_TAG_variable: {
+ IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
+
+ // Keep variable referencing live address.
+ if (IsLiveChild) {
+ // If variable is in module scope and this module allows ODR
+ // deduplication set "TypeTable" placement, otherwise set "" placement
+
+ LiveRootWorklistActionTy Action =
+ (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
+ ? LiveRootWorklistActionTy::MarkTypeEntryRec
+ : LiveRootWorklistActionTy::MarkLiveEntryRec;
+
+ addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
+ }
+ } break;
+ case dwarf::DW_TAG_base_type: {
+ // Always keep base types.
+ addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
+ ReferencedBy);
+ } break;
+ case dwarf::DW_TAG_imported_module:
+ case dwarf::DW_TAG_imported_declaration:
+ case dwarf::DW_TAG_imported_unit: {
+ // Always keep DIEs having DW_AT_import attribute.
+ if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
+ addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
+ ReferencedBy);
+ break;
+ }
+
+ addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,
+ ReferencedBy);
+ } break;
+ case dwarf::DW_TAG_type_unit:
+ case dwarf::DW_TAG_partial_unit:
+ case dwarf::DW_TAG_compile_unit: {
+ llvm_unreachable("Called for incorrect DIE");
+ } break;
+ default:
+ // Nothing to do.
break;
}
- [[fallthrough]];
- case dwarf::DW_TAG_compile_unit:
- case dwarf::DW_TAG_namespace:
- case dwarf::DW_TAG_module:
- case dwarf::DW_TAG_lexical_block: {
- for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry);
- CurChild && CurChild->getAbbreviationDeclarationPtr();
- CurChild = CU.getSiblingEntry(CurChild))
- collectRootsToKeep(CU, CurChild);
- } break;
- case dwarf::DW_TAG_constant:
- case dwarf::DW_TAG_variable: {
- if (isLiveVariableEntry(CU, Entry))
- addItemToWorklist(CU, Entry);
- } break;
- case dwarf::DW_TAG_base_type: {
- addItemToWorklist(CU, Entry);
- } break;
- case dwarf::DW_TAG_imported_module:
- case dwarf::DW_TAG_imported_declaration:
- case dwarf::DW_TAG_imported_unit: {
- addItemToWorklist(CU, Entry);
- } break;
- default:
- // Nothing to do.
- break;
+
+ collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
}
}
-bool DependencyTracker::markLiveRootsAsKept() {
+bool DependencyTracker::markCollectedLiveRootsAsKept(
+ bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
bool Res = true;
+ // Mark roots as kept.
while (!RootEntriesWorkList.empty()) {
- RootEntryTy CurrentItem = RootEntriesWorkList.pop_back_val();
-
- if (!markDIEEntryAsKeptRec(CurrentItem, CurrentItem.CU,
- CurrentItem.RootEntry))
+ LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
+
+ if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),
+ Root.getRootEntry(), InterCUProcessingStarted,
+ HasNewInterconnectedCUs)) {
+ if (Root.hasReferencedByOtherEntry())
+ Dependencies.push_back(Root);
+ } else
Res = false;
}
return Res;
}
-bool DependencyTracker::markDIEEntryAsKeptRec(
- const RootEntryTy &RootItem, CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry) {
- if (Entry->getAbbreviationDeclarationPtr() == nullptr)
- return true;
+bool DependencyTracker::updateDependenciesCompleteness() {
+ bool HasNewDependency = false;
+ for (LiveRootWorklistItemTy &Root : Dependencies) {
+ assert(Root.hasReferencedByOtherEntry() &&
+ "Root entry without dependency inside the dependencies list");
+
+ UnitEntryPairTy RootEntry = Root.getRootEntry();
+ CompileUnit::DIEInfo &RootInfo =
+ RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
+
+ UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
+ CompileUnit::DIEInfo &ReferencedByInfo =
+ ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
+
+ if (!RootInfo.needToPlaceInTypeTable() &&
+ ReferencedByInfo.needToPlaceInTypeTable()) {
+ HasNewDependency = true;
+ setPlainDwarfPlacementRec(ReferencedByEntry);
+
+ // FIXME: we probably need to update getKeepTypeChildren status for
+ // parents of *Root.ReferencedBy.
+ }
+ }
+
+ return HasNewDependency;
+}
+
+void DependencyTracker::setPlainDwarfPlacementRec(
+ const UnitEntryPairTy &Entry) {
+ CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+ if (Info.getPlacement() == CompileUnit::PlainDwarf &&
+ !Info.getKeepTypeChildren())
+ return;
- CompileUnit::DIEInfo &Info = CU.getDIEInfo(Entry);
+ Info.setPlacement(CompileUnit::PlainDwarf);
+ Info.unsetKeepTypeChildren();
+ markParentsAsKeepingChildren(Entry);
- if (Info.getKeep())
+ for (const DWARFDebugInfoEntry *CurChild =
+ Entry.CU->getFirstChildEntry(Entry.DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = Entry.CU->getSiblingEntry(CurChild))
+ setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
+}
+
+static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
+ switch (Entry->getTag()) {
+ case dwarf::DW_TAG_compile_unit:
+ case dwarf::DW_TAG_module:
+ case dwarf::DW_TAG_namespace:
return true;
- // Mark parents as 'KeepChildren'.
- std::optional<uint32_t> ParentIdx = Entry->getParentIdx();
+ default:
+ return false;
+ }
+}
+
+bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,
+ CompileUnit::DieOutputPlacement NewPlacement) {
+ if (!Info.getKeep())
+ return false;
+
+ switch (NewPlacement) {
+ case CompileUnit::TypeTable:
+ return Info.needToPlaceInTypeTable();
+
+ case CompileUnit::PlainDwarf:
+ return Info.needToKeepInPlainDwarf();
+
+ case CompileUnit::Both:
+ return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
+
+ case CompileUnit::NotSet:
+ llvm_unreachable("Unset placement type is specified.");
+ };
+}
+
+bool isAlreadyMarked(const UnitEntryPairTy &Entry,
+ CompileUnit::DieOutputPlacement NewPlacement) {
+ return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
+}
+
+void DependencyTracker::markParentsAsKeepingChildren(
+ const UnitEntryPairTy &Entry) {
+ if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
+ return;
+
+ CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+ bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
+ bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
+
+ bool AreTypeParentsDone = !NeedKeepTypeChildren;
+ bool ArePlainParentsDone = !NeedKeepPlainChildren;
+
+ // Mark parents as 'Keep*Children'.
+ std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
while (ParentIdx) {
- const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx);
- CompileUnit::DIEInfo &ParentInfo = CU.getDIEInfo(*ParentIdx);
- if (ParentInfo.getKeepChildren())
+ const DWARFDebugInfoEntry *ParentEntry =
+ Entry.CU->getDebugInfoEntry(*ParentIdx);
+ CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
+
+ if (!AreTypeParentsDone && NeedKeepTypeChildren) {
+ if (ParentInfo.getKeepTypeChildren())
+ AreTypeParentsDone = true;
+ else {
+ bool AddToWorklist = !isAlreadyMarked(
+ ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);
+ ParentInfo.setKeepTypeChildren();
+ if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
+ addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy::MarkTypeChildrenRec,
+ UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
+ }
+ }
+ }
+
+ if (!ArePlainParentsDone && NeedKeepPlainChildren) {
+ if (ParentInfo.getKeepPlainChildren())
+ ArePlainParentsDone = true;
+ else {
+ bool AddToWorklist = !isAlreadyMarked(
+ ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);
+ ParentInfo.setKeepPlainChildren();
+ if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
+ addActionToRootEntriesWorkList(
+ LiveRootWorklistActionTy::MarkLiveChildrenRec,
+ UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
+ }
+ }
+ }
+
+ if (AreTypeParentsDone && ArePlainParentsDone)
break;
- ParentInfo.setKeepChildren();
+
ParentIdx = ParentEntry->getParentIdx();
}
+}
+
+// This function tries to set specified \p Placement for the \p Entry.
+// Depending on the concrete entry, the placement could be:
+// a) changed to another.
+// b) joined with current entry placement.
+// c) set as requested.
+static CompileUnit::DieOutputPlacement
+getFinalPlacementForEntry(const UnitEntryPairTy &Entry,
+ CompileUnit::DieOutputPlacement Placement) {
+ assert((Placement != CompileUnit::NotSet) && "Placement is not set");
+ CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
+
+ if (!EntryInfo.getODRAvailable())
+ return CompileUnit::PlainDwarf;
+
+ if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
+ // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
+ // time.
+ if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
+ EntryInfo.getPlacement() == CompileUnit::Both)
+ return CompileUnit::PlainDwarf;
+
+ if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)
+ return CompileUnit::PlainDwarf;
+ }
+
+ switch (EntryInfo.getPlacement()) {
+ case CompileUnit::NotSet:
+ return Placement;
+
+ case CompileUnit::TypeTable:
+ return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;
+
+ case CompileUnit::PlainDwarf:
+ return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;
+
+ case CompileUnit::Both:
+ return CompileUnit::Both;
+ };
+
+ llvm_unreachable("Unknown placement type.");
+ return Placement;
+}
+
+bool DependencyTracker::markDIEEntryAsKeptRec(
+ LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
+ const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs) {
+ if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
+ return true;
+
+ CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+
+ // Calculate final placement placement.
+ CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(
+ Entry,
+ isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);
+ assert((Info.getODRAvailable() || isLiveAction(Action) ||
+ Placement == CompileUnit::PlainDwarf) &&
+ "Wrong kind of placement for ODR unavailable entry");
+
+ if (!isChildrenAction(Action))
+ if (isAlreadyMarked(Entry, Placement))
+ return true;
// Mark current DIE as kept.
Info.setKeep();
- setDIEPlacementAndTypename(Info);
+ Info.setPlacement(Placement);
- // Set liveness information.
- switch (Entry->getTag()) {
- case dwarf::DW_TAG_constant:
- case dwarf::DW_TAG_variable: {
- isLiveVariableEntry(CU, Entry);
- } break;
- case dwarf::DW_TAG_subprogram:
- case dwarf::DW_TAG_label: {
- isLiveSubprogramEntry(CU, Entry);
- } break;
- default:
- // Nothing to do.
- break;
- }
+ // Set keep children property for parents.
+ markParentsAsKeepingChildren(Entry);
+
+ UnitEntryPairTy FinalRootEntry =
+ Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
// Analyse referenced DIEs.
bool Res = true;
- if (!maybeAddReferencedRoots(RootItem, CU, Entry))
+ if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
+ InterCUProcessingStarted,
+ HasNewInterconnectedCUs))
Res = false;
- // Navigate children.
- for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry);
+ // Return if we do not need to process children.
+ if (isSingleAction(Action))
+ return Res;
+
+ // Process children.
+ // Check for subprograms special case.
+ if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
+ Info.getODRAvailable()) {
+ // Subprograms is a special case. As it can be root for type DIEs
+ // and itself may be subject to move into the artificial type unit.
+ // a) Non removable children(like DW_TAG_formal_parameter) should always
+ // be cloned. They are placed into the "PlainDwarf" and into the
+ // "TypeTable".
+ // b) ODR deduplication candidates(type DIEs) children should not be put
+ // into the "PlainDwarf".
+ // c) Children keeping addresses and locations(like DW_TAG_call_site)
+ // should not be put into the "TypeTable".
+ for (const DWARFDebugInfoEntry *CurChild =
+ Entry.CU->getFirstChildEntry(Entry.DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = Entry.CU->getSiblingEntry(CurChild)) {
+ CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
+
+ switch (CurChild->getTag()) {
+ case dwarf::DW_TAG_variable:
+ case dwarf::DW_TAG_constant:
+ case dwarf::DW_TAG_subprogram:
+ case dwarf::DW_TAG_label: {
+ if (ChildInfo.getHasAnAddress())
+ continue;
+ } break;
+
+ // Entries having following tags could not be removed from the subprogram.
+ case dwarf::DW_TAG_lexical_block:
+ case dwarf::DW_TAG_friend:
+ case dwarf::DW_TAG_inheritance:
+ case dwarf::DW_TAG_formal_parameter:
+ case dwarf::DW_TAG_unspecified_parameters:
+ case dwarf::DW_TAG_template_type_parameter:
+ case dwarf::DW_TAG_template_value_parameter:
+ case dwarf::DW_TAG_GNU_template_parameter_pack:
+ case dwarf::DW_TAG_GNU_formal_parameter_pack:
+ case dwarf::DW_TAG_GNU_template_template_param:
+ case dwarf::DW_TAG_thrown_type: {
+ // Go to the default child handling.
+ } break;
+
+ default: {
+ bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
+
+ // Skip child marked to be copied into the artificial type unit.
+ if (isLiveAction(Action) && ChildIsTypeTableCandidate)
+ continue;
+
+ // Skip child marked to be copied into the plain unit.
+ if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
+ continue;
+
+ // Go to the default child handling.
+ } break;
+ }
+
+ if (!markDIEEntryAsKeptRec(
+ Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
+ InterCUProcessingStarted, HasNewInterconnectedCUs))
+ Res = false;
+ }
+
+ return Res;
+ }
+
+ // Recursively process children.
+ for (const DWARFDebugInfoEntry *CurChild =
+ Entry.CU->getFirstChildEntry(Entry.DieEntry);
CurChild && CurChild->getAbbreviationDeclarationPtr();
- CurChild = CU.getSiblingEntry(CurChild)) {
- if (!markDIEEntryAsKeptRec(RootItem, CU, CurChild))
+ CurChild = Entry.CU->getSiblingEntry(CurChild)) {
+ CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
+ switch (CurChild->getTag()) {
+ case dwarf::DW_TAG_variable:
+ case dwarf::DW_TAG_constant:
+ case dwarf::DW_TAG_subprogram:
+ case dwarf::DW_TAG_label: {
+ if (ChildInfo.getHasAnAddress())
+ continue;
+ } break;
+ default:
+ break; // Nothing to do.
+ };
+
+ if (!markDIEEntryAsKeptRec(
+ Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
+ InterCUProcessingStarted, HasNewInterconnectedCUs))
Res = false;
}
return Res;
}
+bool DependencyTracker::isTypeTableCandidate(
+ const DWARFDebugInfoEntry *DIEEntry) {
+ switch (DIEEntry->getTag()) {
+ default:
+ return false;
+
+ case dwarf::DW_TAG_imported_module:
+ case dwarf::DW_TAG_imported_declaration:
+ case dwarf::DW_TAG_imported_unit:
+ 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_variant:
+ case dwarf::DW_TAG_module:
+ 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_enumerator:
+ case dwarf::DW_TAG_file_type:
+ case dwarf::DW_TAG_packed_type:
+ case dwarf::DW_TAG_thrown_type:
+ case dwarf::DW_TAG_volatile_type:
+ case dwarf::DW_TAG_dwarf_procedure:
+ case dwarf::DW_TAG_restrict_type:
+ case dwarf::DW_TAG_interface_type:
+ case dwarf::DW_TAG_namespace:
+ case dwarf::DW_TAG_unspecified_type:
+ case dwarf::DW_TAG_shared_type:
+ case dwarf::DW_TAG_rvalue_reference_type:
+ case dwarf::DW_TAG_coarray_type:
+ case dwarf::DW_TAG_dynamic_type:
+ case dwarf::DW_TAG_atomic_type:
+ case dwarf::DW_TAG_immutable_type:
+ case dwarf::DW_TAG_function_template:
+ case dwarf::DW_TAG_class_template:
+ return true;
+ }
+}
+
bool DependencyTracker::maybeAddReferencedRoots(
- const RootEntryTy &RootItem, CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry) {
- const auto *Abbrev = Entry->getAbbreviationDeclarationPtr();
+ LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
+ const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs) {
+ const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
if (Abbrev == nullptr)
return true;
- DWARFUnit &Unit = CU.getOrigUnit();
+ DWARFUnit &Unit = Entry.CU->getOrigUnit();
DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
- uint64_t Offset = Entry->getOffset() + getULEB128Size(Abbrev->getCode());
+ uint64_t Offset =
+ Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
// For each DIE attribute...
for (const auto &AttrSpec : Abbrev->attributes()) {
@@ -220,132 +631,157 @@ bool DependencyTracker::maybeAddReferencedRoots(
Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
// Resolve reference.
- std::optional<std::pair<CompileUnit *, uint32_t>> RefDie =
- CU.resolveDIEReference(
- Val, Context.InterCUProcessingStarted
- ? ResolveInterCUReferencesMode::Resolve
- : ResolveInterCUReferencesMode::AvoidResolving);
+ std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
+ Val, InterCUProcessingStarted
+ ? ResolveInterCUReferencesMode::Resolve
+ : ResolveInterCUReferencesMode::AvoidResolving);
if (!RefDie) {
- CU.warn("cann't find referenced DIE", Entry);
+ Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
continue;
}
- if (RefDie->second == 0) {
+ if (!RefDie->DieEntry) {
// Delay resolving reference.
- RefDie->first->setInterconnectedCU();
- CU.setInterconnectedCU();
- Context.HasNewInterconnectedCUs = true;
+ RefDie->CU->setInterconnectedCU();
+ Entry.CU->setInterconnectedCU();
+ HasNewInterconnectedCUs = true;
return false;
}
- assert(CU.getUniqueID() == RefDie->first->getUniqueID() ||
- Context.InterCUProcessingStarted);
+ assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
+ InterCUProcessingStarted) &&
+ "Inter-CU reference while inter-CU processing is not started");
+
+ CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
+ if (!RefInfo.getODRAvailable())
+ Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
+ else if (RefInfo.getODRAvailable() &&
+ llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
+ // Note: getODRAttributes does not include DW_AT_containing_type.
+ // It should be OK as we do getRootForSpecifiedEntry(). So any containing
+ // type would be found as the root for the entry.
+ Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
+ else if (isLiveAction(Action))
+ Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
+ else
+ Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
+
+ if (AttrSpec.Attr == dwarf::DW_AT_import) {
+ if (isNamespaceLikeEntry(RefDie->DieEntry)) {
+ addActionToRootEntriesWorkList(
+ isTypeAction(Action)
+ ? LiveRootWorklistActionTy::MarkSingleTypeEntry
+ : LiveRootWorklistActionTy::MarkSingleLiveEntry,
+ *RefDie, RootEntry);
+ continue;
+ }
- addItemToWorklist(*RefDie->first,
- RefDie->first->getDebugInfoEntry(RefDie->second));
+ addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
+ continue;
+ }
+
+ UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
+ addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
}
return true;
}
-// Returns true if the specified DIE type allows removing children.
-static bool childrenCanBeRemoved(uint32_t Tag) {
- switch (Tag) {
- default:
- return true;
- case dwarf::DW_TAG_class_type:
- case dwarf::DW_TAG_common_block:
- case dwarf::DW_TAG_lexical_block:
- case dwarf::DW_TAG_structure_type:
- case dwarf::DW_TAG_subprogram:
- case dwarf::DW_TAG_subroutine_type:
- case dwarf::DW_TAG_union_type:
- case dwarf::DW_TAG_array_type:
- return false;
- }
- llvm_unreachable("Invalid Tag");
-}
-
-void DependencyTracker::addItemToWorklist(CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry) {
- if (Entry->getAbbreviationDeclarationPtr() == nullptr)
- return;
+UnitEntryPairTy
+DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {
+ UnitEntryPairTy Result = Entry;
+
+ do {
+ switch (Entry.DieEntry->getTag()) {
+ case dwarf::DW_TAG_subprogram:
+ case dwarf::DW_TAG_label:
+ case dwarf::DW_TAG_variable:
+ case dwarf::DW_TAG_constant: {
+ return Result;
+ } break;
+
+ default: {
+ // Nothing to do.
+ }
+ }
- const DWARFDebugInfoEntry *EntryToAdd = Entry;
+ std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
+ if (!ParentIdx)
+ return Result;
- // If parent does not allow children removing then use that parent as a root
- // DIE.
- std::optional<uint32_t> ParentIdx = Entry->getParentIdx();
- while (ParentIdx) {
- const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx);
- if (childrenCanBeRemoved(ParentEntry->getTag()))
+ const DWARFDebugInfoEntry *ParentEntry =
+ Result.CU->getDebugInfoEntry(*ParentIdx);
+ if (isNamespaceLikeEntry(ParentEntry))
break;
- EntryToAdd = ParentEntry;
- ParentIdx = ParentEntry->getParentIdx();
- }
+ Result.DieEntry = ParentEntry;
+ } while (true);
- // Check if the DIE entry is already kept.
- if (CU.getDIEInfo(EntryToAdd).getKeep())
- return;
-
- RootEntriesWorkList.emplace_back(CU, EntryToAdd);
+ return Result;
}
-bool DependencyTracker::isLiveVariableEntry(CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry) {
- DWARFDie DIE = CU.getDIE(Entry);
- CompileUnit::DIEInfo &Info = CU.getDIEInfo(DIE);
+bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,
+ bool IsLiveParent) {
+ DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
+ CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
- if (TrackLiveness) {
+ if (Info.getTrackLiveness()) {
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
- // Global variables with constant value can always be kept.
if (!Info.getIsInFunctionScope() &&
- Abbrev->findAttributeIndex(dwarf::DW_AT_const_value))
- return true;
-
- // See if there is a relocation to a valid debug map entry inside this
- // variable's location. The order is important here. We want to always check
- // if the variable has a location expression address.
- // However, we don't want a static variable in a function to force us to
- // keep the enclosing function, unless requested explicitly.
- std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
- CU.getContaingFile().Addresses->getVariableRelocAdjustment(DIE);
-
- if (!LocExprAddrAndRelocAdjustment.second)
- return false;
+ Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
+ // Global variables with constant value can always be kept.
+ } else {
+ // See if there is a relocation to a valid debug map entry inside this
+ // variable's location. The order is important here. We want to always
+ // check if the variable has a location expression address. However, we
+ // don't want a static variable in a function to force us to keep the
+ // enclosing function, unless requested explicitly.
+ std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
+ Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
+ DIE);
+
+ if (LocExprAddrAndRelocAdjustment.first)
+ Info.setHasAnAddress();
+
+ if (!LocExprAddrAndRelocAdjustment.second)
+ return false;
- if ((Info.getIsInFunctionScope()) &&
- !LLVM_UNLIKELY(CU.getGlobalData().getOptions().KeepFunctionForStatic))
- return false;
+ if (!IsLiveParent && Info.getIsInFunctionScope() &&
+ !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
+ return false;
+ }
}
+ Info.setHasAnAddress();
- if (CU.getGlobalData().getOptions().Verbose) {
+ if (Entry.CU->getGlobalData().getOptions().Verbose) {
outs() << "Keeping variable DIE:";
DIDumpOptions DumpOpts;
DumpOpts.ChildRecurseDepth = 0;
- DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose;
+ DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
DIE.dump(outs(), 8 /* Indent */, DumpOpts);
}
return true;
}
-bool DependencyTracker::isLiveSubprogramEntry(
- CompileUnit &CU, const DWARFDebugInfoEntry *Entry) {
- DWARFDie DIE = CU.getDIE(Entry);
+bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {
+ DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
+ CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+ std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
std::optional<uint64_t> LowPc;
std::optional<uint64_t> HighPc;
std::optional<int64_t> RelocAdjustment;
-
- if (TrackLiveness) {
- LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc));
+ if (Info.getTrackLiveness()) {
+ LowPc = dwarf::toAddress(LowPCVal);
if (!LowPc)
return false;
+ Info.setHasAnAddress();
+
RelocAdjustment =
- CU.getContaingFile().Addresses->getSubprogramRelocAdjustment(DIE);
+ Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
+ DIE);
if (!RelocAdjustment)
return false;
@@ -354,16 +790,18 @@ bool DependencyTracker::isLiveSubprogramEntry(
HighPc = DIE.getHighPC(*LowPc);
if (!HighPc) {
- CU.warn("function without high_pc. Range will be discarded.", &DIE);
+ Entry.CU->warn("function without high_pc. Range will be discarded.",
+ &DIE);
return false;
}
if (*LowPc > *HighPc) {
- CU.warn("low_pc greater than high_pc. Range will be discarded.", &DIE);
+ Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
+ &DIE);
return false;
}
- } else if (DIE.getTag() == dwarf::DW_TAG_variable) {
- if (CU.hasLabelAt(*LowPc))
+ } else if (DIE.getTag() == dwarf::DW_TAG_label) {
+ if (Entry.CU->hasLabelAt(*LowPc))
return false;
// FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
@@ -371,33 +809,29 @@ bool DependencyTracker::isLiveSubprogramEntry(
// info generation bugs aside, this is really wrong in the case of labels,
// where a label marking the end of a function will have a PC == CU's
// high_pc.
- if (dwarf::toAddress(
- CU.getOrigUnit().getUnitDIE().find(dwarf::DW_AT_high_pc))
+ if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
.value_or(UINT64_MAX) <= LowPc)
return false;
- CU.addLabelLowPc(*LowPc, *RelocAdjustment);
+ Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
}
- }
+ } else
+ Info.setHasAnAddress();
- if (CU.getGlobalData().getOptions().Verbose) {
+ if (Entry.CU->getGlobalData().getOptions().Verbose) {
outs() << "Keeping subprogram DIE:";
DIDumpOptions DumpOpts;
DumpOpts.ChildRecurseDepth = 0;
- DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose;
+ DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
DIE.dump(outs(), 8 /* Indent */, DumpOpts);
}
- if (!TrackLiveness || DIE.getTag() == dwarf::DW_TAG_label)
+ if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
return true;
- CU.addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
+ Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
return true;
}
-void DependencyTracker::setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info) {
- Info.setPlacement(CompileUnit::PlainDwarf);
-}
-
} // end of namespace dwarflinker_parallel
} // namespace llvm
diff --git a/llvm/lib/DWARFLinkerParallel/DependencyTracker.h b/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
index 69e57bc3ea4d264..abd5371471eb95a 100644
--- a/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
+++ b/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
@@ -10,7 +10,7 @@
#define LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H
#include "DWARFLinkerCompileUnit.h"
-#include "DWARFLinkerImpl.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
namespace llvm {
@@ -19,10 +19,12 @@ class DWARFDie;
namespace dwarflinker_parallel {
-/// This class discovers DIEs dependencies and marks "live" DIEs.
+/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE
+/// locations (whether DIE should be cloned as regular DIE or it should be put
+/// into the artificial type unit).
class DependencyTracker {
public:
- DependencyTracker(DWARFLinkerImpl::LinkContext &Context) : Context(Context) {}
+ DependencyTracker(CompileUnit &CU) : CU(CU) {}
/// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
/// information in \p CU's DIEInfo.
@@ -30,70 +32,223 @@ class DependencyTracker {
/// This function is the entry point of the DIE selection algorithm. It is
/// expected to walk the DIE tree and(through the mediation of
/// Context.File.Addresses) ask for relocation adjustment value on each
- /// DIE that might be a 'root DIE'.
+ /// DIE that might be a 'root DIE'(f.e. subprograms, variables).
///
/// Returns true if all dependencies are correctly discovered. Inter-CU
/// dependencies cannot be discovered if referenced CU is not analyzed yet.
/// If that is the case this method returns false.
- bool resolveDependenciesAndMarkLiveness(CompileUnit &CU);
+ bool resolveDependenciesAndMarkLiveness(
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
- /// Recursively walk the \p DIE tree and check "keepness" information.
- /// It is an error if parent node does not have "keep" flag, while
- /// child have one. This function dump error at stderr in that case.
-#ifndef NDEBUG
- static void verifyKeepChain(CompileUnit &CU);
-#endif
+ /// Check if dependencies have incompatible placement.
+ /// If that is the case modify placement to be compatible.
+ /// \returns true if any placement was updated, otherwise returns false.
+ /// This method should be called as a followup processing after
+ /// resolveDependenciesAndMarkLiveness().
+ bool updateDependenciesCompleteness();
+
+ /// Recursively walk the \p DIE tree and check "keepness" and "placement"
+ /// information. It is an error if parent node does not have "keep" flag,
+ /// while child has one. It is an error if parent node has "TypeTable"
+ /// placement while child has "PlainDwarf" placement. This function dump error
+ /// at stderr in that case.
+ void verifyKeepChain();
protected:
- struct RootEntryTy {
- RootEntryTy(CompileUnit &CU, const DWARFDebugInfoEntry *RootEntry)
- : CU(CU), RootEntry(RootEntry) {}
+ enum class LiveRootWorklistActionTy : uint8_t {
+ /// Mark current item as live entry.
+ MarkSingleLiveEntry = 0,
+
+ /// Mark current item as type entry.
+ MarkSingleTypeEntry,
+
+ /// Mark current item and all its children as live entry.
+ MarkLiveEntryRec,
+
+ /// Mark current item and all its children as type entry.
+ MarkTypeEntryRec,
+
+ /// Mark all children of current item as live entry.
+ MarkLiveChildrenRec,
+
+ /// Mark all children of current item as type entry.
+ MarkTypeChildrenRec,
+ };
+
+ /// \returns true if the specified action is for the "PlainDwarf".
+ bool isLiveAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkSingleLiveEntry:
+ case LiveRootWorklistActionTy::MarkLiveEntryRec:
+ case LiveRootWorklistActionTy::MarkLiveChildrenRec:
+ return true;
+ }
+ }
+
+ /// \returns true if the specified action is for the "TypeTable".
+ bool isTypeAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkSingleTypeEntry:
+ case LiveRootWorklistActionTy::MarkTypeEntryRec:
+ case LiveRootWorklistActionTy::MarkTypeChildrenRec:
+ return true;
+ }
+ }
+
+ /// \returns true if the specified action affects only Root entry
+ /// itself and does not affect it`s children.
+ bool isSingleAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkSingleLiveEntry:
+ case LiveRootWorklistActionTy::MarkSingleTypeEntry:
+ return true;
+ }
+ }
- // Compile unit keeping root entry.
- CompileUnit &CU;
+ /// \returns true if the specified action affects only Root entry
+ /// itself and does not affect it`s children.
+ bool isChildrenAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
- // Root entry.
- const DWARFDebugInfoEntry *RootEntry;
+ case LiveRootWorklistActionTy::MarkLiveChildrenRec:
+ case LiveRootWorklistActionTy::MarkTypeChildrenRec:
+ return true;
+ }
+ }
+
+ /// Class keeping live worklist item data.
+ class LiveRootWorklistItemTy {
+ public:
+ LiveRootWorklistItemTy() = default;
+ LiveRootWorklistItemTy(const LiveRootWorklistItemTy &) = default;
+ LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
+ UnitEntryPairTy RootEntry) {
+ RootCU.setInt(static_cast<uint8_t>(Action));
+ RootCU.setPointer(RootEntry.CU);
+
+ RootDieEntry = RootEntry.DieEntry;
+ }
+ LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
+ UnitEntryPairTy RootEntry,
+ UnitEntryPairTy ReferencedBy) {
+ RootCU.setPointer(RootEntry.CU);
+ RootCU.setInt(static_cast<uint8_t>(Action));
+ RootDieEntry = RootEntry.DieEntry;
+
+ ReferencedByCU = ReferencedBy.CU;
+ ReferencedByDieEntry = ReferencedBy.DieEntry;
+ }
+
+ UnitEntryPairTy getRootEntry() const {
+ return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry};
+ }
+
+ CompileUnit::DieOutputPlacement getPlacement() const {
+ return static_cast<CompileUnit::DieOutputPlacement>(RootCU.getInt());
+ }
+
+ bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; }
+
+ UnitEntryPairTy getReferencedByEntry() const {
+ assert(ReferencedByCU);
+ assert(ReferencedByDieEntry);
+ return UnitEntryPairTy{ReferencedByCU, ReferencedByDieEntry};
+ }
+
+ LiveRootWorklistActionTy getAction() const {
+ return static_cast<LiveRootWorklistActionTy>(RootCU.getInt());
+ }
+
+ protected:
+ /// Root entry.
+ /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
+ /// Thus LiveRootWorklistActionTy should have no more eight elements.
+ PointerIntPair<CompileUnit *, 3> RootCU;
+ const DWARFDebugInfoEntry *RootDieEntry = nullptr;
+
+ /// Another root entry which references this RootDieEntry.
+ /// ReferencedByDieEntry is kept to update placement.
+ /// if RootDieEntry has placement incompatible with placement
+ /// of ReferencedByDieEntry then it should be updated.
+ CompileUnit *ReferencedByCU = nullptr;
+ const DWARFDebugInfoEntry *ReferencedByDieEntry = nullptr;
};
- using RootEntriesListTy = SmallVector<RootEntryTy>;
+ using RootEntriesListTy = SmallVector<LiveRootWorklistItemTy>;
/// This function navigates DIEs tree starting from specified \p Entry.
- /// It puts 'root DIE' into the worklist.
- void collectRootsToKeep(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+ /// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries
+ /// instructs to collect either live roots(like subprograms having live
+ /// DW_AT_low_pc) or otherwise roots which is not live(they need to be
+ /// collected if they are imported f.e. by DW_TAG_imported_module).
+ void collectRootsToKeep(const UnitEntryPairTy &Entry,
+ std::optional<UnitEntryPairTy> ReferencedBy,
+ bool IsLiveParent);
/// Returns true if specified variable references live code section.
- bool isLiveVariableEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+ static bool isLiveVariableEntry(const UnitEntryPairTy &Entry,
+ bool IsLiveParent);
/// Returns true if specified subprogram references live code section.
- bool isLiveSubprogramEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+ static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry);
- /// Examine worklist and mark all 'root DIE's as kept.
- bool markLiveRootsAsKept();
+ /// Examine worklist and mark all 'root DIE's as kept and set "Placement"
+ /// property.
+ bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
/// Mark whole DIE tree as kept recursively.
- bool markDIEEntryAsKeptRec(const RootEntryTy &RootItem, CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry);
+ bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,
+ const UnitEntryPairTy &RootEntry,
+ const UnitEntryPairTy &Entry,
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
+
+ /// Mark parents as keeping children.
+ void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry);
+
+ /// Mark whole DIE tree as placed in "PlainDwarf".
+ void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry);
+
+ /// Check referenced DIEs and add them into the worklist.
+ bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action,
+ const UnitEntryPairTy &RootEntry,
+ const UnitEntryPairTy &Entry,
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
- /// Check referenced DIEs and add them into the worklist if neccessary.
- bool maybeAddReferencedRoots(const RootEntryTy &RootItem, CompileUnit &CU,
- const DWARFDebugInfoEntry *Entry);
+ /// \returns true if \p DIEEntry can possibly be put into the artificial type
+ /// unit.
+ bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry);
- /// Add 'root DIE' into the worklist.
- void addItemToWorklist(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+ /// \returns root for the specified \p Entry.
+ UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry);
- /// Set kind of placement(whether it goes into type table, plain dwarf or
- /// both) for the specified die \p DieIdx.
- void setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info);
+ /// Add action item to the work list.
+ void
+ addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,
+ const UnitEntryPairTy &Entry,
+ std::optional<UnitEntryPairTy> ReferencedBy);
- /// Flag indicating whether liveness information should be examined.
- bool TrackLiveness = false;
+ CompileUnit &CU;
- /// List of CU, Entry pairs which are 'root DIE's.
+ /// List of entries which are 'root DIE's.
RootEntriesListTy RootEntriesWorkList;
- /// Link context for the analyzed CU.
- DWARFLinkerImpl::LinkContext &Context;
+ /// List of entries dependencies.
+ RootEntriesListTy Dependencies;
};
} // end namespace dwarflinker_parallel
diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp
index 8e7caa7bb407425..9c3e3ebd220aaf4 100644
--- a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp
+++ b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp
@@ -8,6 +8,7 @@
#include "OutputSections.h"
#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerTypeUnit.h"
#include "llvm/ADT/StringSwitch.h"
namespace llvm {
@@ -92,6 +93,33 @@ DebugULEB128DieRefPatch::DebugULEB128DieRefPatch(uint64_t PatchOffset,
RefCU(RefCU, SrcCU->getUniqueID() == RefCU->getUniqueID()),
RefDieIdxOrClonedOffset(RefIdx) {}
+DebugDieTypeRefPatch::DebugDieTypeRefPatch(uint64_t PatchOffset,
+ TypeEntry *RefTypeName)
+ : SectionPatch({PatchOffset}), RefTypeName(RefTypeName) {}
+
+DebugType2TypeDieRefPatch::DebugType2TypeDieRefPatch(uint64_t PatchOffset,
+ DIE *Die,
+ TypeEntry *TypeName,
+ TypeEntry *RefTypeName)
+ : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+ RefTypeName(RefTypeName) {}
+
+DebugTypeStrPatch::DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die,
+ TypeEntry *TypeName, StringEntry *String)
+ : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+ String(String) {}
+
+DebugTypeLineStrPatch::DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die,
+ TypeEntry *TypeName,
+ StringEntry *String)
+ : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+ String(String) {}
+
+DebugTypeDeclFilePatch::DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName,
+ StringEntry *Directory,
+ StringEntry *FilePath)
+ : Die(Die), TypeName(TypeName), Directory(Directory), FilePath(FilePath) {}
+
void SectionDescriptor::clearAllSectionData() {
StartOffset = 0;
clearSectionContent();
@@ -102,6 +130,10 @@ void SectionDescriptor::clearAllSectionData() {
ListDebugDieRefPatch.erase();
ListDebugULEB128DieRefPatch.erase();
ListDebugOffsetPatch.erase();
+ ListDebugType2TypeDieRefPatch.erase();
+ ListDebugTypeDeclFilePatch.erase();
+ ListDebugTypeLineStrPatch.erase();
+ ListDebugTypeStrPatch.erase();
}
void SectionDescriptor::clearSectionContent() { Contents = OutSectionDataTy(); }
@@ -144,6 +176,30 @@ void SectionDescriptor::setSizesForSectionCreatedByAsmPrinter() {
}
}
+void SectionDescriptor::emitString(dwarf::Form StringForm,
+ const char *StringVal) {
+ assert(StringVal != nullptr);
+
+ switch (StringForm) {
+ case dwarf::DW_FORM_string: {
+ emitInplaceString(StringVal);
+ } break;
+ case dwarf::DW_FORM_strp: {
+ notePatch(DebugStrPatch{
+ {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
+ emitStringPlaceholder();
+ } break;
+ case dwarf::DW_FORM_line_strp: {
+ notePatch(DebugLineStrPatch{
+ {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
+ emitStringPlaceholder();
+ } break;
+ default:
+ llvm_unreachable("Unsupported string form");
+ break;
+ };
+}
+
void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) {
switch (Size) {
case 1: {
@@ -171,30 +227,6 @@ void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) {
}
}
-void SectionDescriptor::emitString(dwarf::Form StringForm,
- const char *StringVal) {
- assert(StringVal != nullptr);
-
- switch (StringForm) {
- case dwarf::DW_FORM_string: {
- emitInplaceString(StringVal);
- } break;
- case dwarf::DW_FORM_strp: {
- notePatch(DebugStrPatch{
- {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
- emitStringPlaceholder();
- } break;
- case dwarf::DW_FORM_line_strp: {
- notePatch(DebugLineStrPatch{
- {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
- emitStringPlaceholder();
- } break;
- default:
- llvm_unreachable("Unsupported string form");
- break;
- };
-}
-
void SectionDescriptor::apply(uint64_t PatchOffset, dwarf::Form AttrForm,
uint64_t Val) {
switch (AttrForm) {
@@ -330,8 +362,8 @@ void SectionDescriptor::applySLEB128(uint64_t PatchOffset, uint64_t Val) {
void OutputSections::applyPatches(
SectionDescriptor &Section,
StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
- StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings) {
-
+ StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
+ TypeUnit *TypeUnitPtr) {
Section.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {
DwarfStringPoolEntryWithExtString *Entry =
DebugStrStrings.getExistingEntry(Patch.String);
@@ -339,6 +371,26 @@ void OutputSections::applyPatches(
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
});
+ Section.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ DwarfStringPoolEntryWithExtString *Entry =
+ DebugStrStrings.getExistingEntry(Patch.String);
+ assert(Entry != nullptr);
+
+ Patch.PatchOffset +=
+ Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
+ });
Section.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {
DwarfStringPoolEntryWithExtString *Entry =
@@ -347,6 +399,26 @@ void OutputSections::applyPatches(
Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
});
+ Section.ListDebugTypeLineStrPatch.forEach([&](DebugTypeLineStrPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ DwarfStringPoolEntryWithExtString *Entry =
+ DebugLineStrStrings.getExistingEntry(Patch.String);
+ assert(Entry != nullptr);
+
+ Patch.PatchOffset +=
+ Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
+ });
std::optional<SectionDescriptor *> RangeSection;
if (Format.Version >= 5)
@@ -404,6 +476,46 @@ void OutputSections::applyPatches(
Patch.RefDieIdxOrClonedOffset);
});
+ Section.ListDebugDieTypeRefPatch.forEach([&](DebugDieTypeRefPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ assert(Patch.RefTypeName != nullptr);
+
+ TypeEntryBody *TypeEntry = Patch.RefTypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.RefTypeName->getKey())
+ .str()
+ .c_str());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref_addr,
+ TypeEntry->getFinalDie().getOffset());
+ });
+
+ Section.ListDebugType2TypeDieRefPatch.forEach(
+ [&](DebugType2TypeDieRefPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ Patch.PatchOffset += Patch.Die->getOffset() +
+ getULEB128Size(Patch.Die->getAbbrevNumber());
+
+ assert(Patch.RefTypeName != nullptr);
+ TypeEntryBody *RefTypeEntry = Patch.RefTypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.RefTypeName->getKey())
+ .str()
+ .c_str());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref4,
+ RefTypeEntry->getFinalDie().getOffset());
+ });
+
Section.ListDebugOffsetPatch.forEach([&](DebugOffsetPatch &Patch) {
uint64_t FinalValue = Patch.SectionPtr.getPointer()->StartOffset;
diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.h b/llvm/lib/DWARFLinkerParallel/OutputSections.h
index b101ac61935c5cf..f23b2efb869da8e 100644
--- a/llvm/lib/DWARFLinkerParallel/OutputSections.h
+++ b/llvm/lib/DWARFLinkerParallel/OutputSections.h
@@ -31,6 +31,8 @@
namespace llvm {
namespace dwarflinker_parallel {
+class TypeUnit;
+
/// List of tracked debug tables.
enum class DebugSectionKind : uint8_t {
DebugInfo = 0,
@@ -113,7 +115,7 @@ struct DebugDieRefPatch : SectionPatch {
uint32_t RefIdx);
PointerIntPair<CompileUnit *, 1> RefCU;
- uint64_t RefDieIdxOrClonedOffset;
+ uint64_t RefDieIdxOrClonedOffset = 0;
};
/// This structure is used to update reference to the DIE of ULEB128 form.
@@ -122,7 +124,53 @@ struct DebugULEB128DieRefPatch : SectionPatch {
CompileUnit *RefCU, uint32_t RefIdx);
PointerIntPair<CompileUnit *, 1> RefCU;
- uint64_t RefDieIdxOrClonedOffset;
+ uint64_t RefDieIdxOrClonedOffset = 0;
+};
+
+/// This structure is used to update reference to the type DIE.
+struct DebugDieTypeRefPatch : SectionPatch {
+ DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName);
+
+ TypeEntry *RefTypeName = nullptr;
+};
+
+/// This structure is used to update reference to the type DIE.
+struct DebugType2TypeDieRefPatch : SectionPatch {
+ DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+ TypeEntry *RefTypeName);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ TypeEntry *RefTypeName = nullptr;
+};
+
+struct DebugTypeStrPatch : SectionPatch {
+ DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+ StringEntry *String);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ StringEntry *String = nullptr;
+};
+
+struct DebugTypeLineStrPatch : SectionPatch {
+ DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+ StringEntry *String);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ StringEntry *String = nullptr;
+};
+
+struct DebugTypeDeclFilePatch {
+ DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory,
+ StringEntry *FilePath);
+
+ DIE *Die = nullptr;
+ TypeEntry *TypeName = nullptr;
+ StringEntry *Directory = nullptr;
+ StringEntry *FilePath = nullptr;
+ uint32_t FileID = 0;
};
/// Type for section data.
@@ -140,16 +188,20 @@ struct SectionDescriptor {
SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
dwarf::FormParams Format, llvm::endianness Endianess)
- : OS(Contents), GlobalData(GlobalData), SectionKind(SectionKind),
- Format(Format), Endianess(Endianess) {
- ListDebugStrPatch.setAllocator(&GlobalData.getAllocator());
- ListDebugLineStrPatch.setAllocator(&GlobalData.getAllocator());
- ListDebugRangePatch.setAllocator(&GlobalData.getAllocator());
- ListDebugLocPatch.setAllocator(&GlobalData.getAllocator());
- ListDebugDieRefPatch.setAllocator(&GlobalData.getAllocator());
- ListDebugULEB128DieRefPatch.setAllocator(&GlobalData.getAllocator());
- ListDebugOffsetPatch.setAllocator(&GlobalData.getAllocator());
- }
+ : OS(Contents), ListDebugStrPatch(&GlobalData.getAllocator()),
+ ListDebugLineStrPatch(&GlobalData.getAllocator()),
+ ListDebugRangePatch(&GlobalData.getAllocator()),
+ ListDebugLocPatch(&GlobalData.getAllocator()),
+ ListDebugDieRefPatch(&GlobalData.getAllocator()),
+ ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()),
+ ListDebugOffsetPatch(&GlobalData.getAllocator()),
+ ListDebugDieTypeRefPatch(&GlobalData.getAllocator()),
+ ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()),
+ ListDebugTypeStrPatch(&GlobalData.getAllocator()),
+ ListDebugTypeLineStrPatch(&GlobalData.getAllocator()),
+ ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()),
+ GlobalData(GlobalData), SectionKind(SectionKind), Format(Format),
+ Endianess(Endianess) {}
/// Erase whole section contents(data bits, list of patches).
void clearAllSectionData();
@@ -178,9 +230,16 @@ struct SectionDescriptor {
ADD_PATCHES_LIST(DebugDieRefPatch)
ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
ADD_PATCHES_LIST(DebugOffsetPatch)
-
- /// Offsets to some fields are not known at the moment of noting patch.
- /// In that case we remember pointers to patch offset to update them later.
+ ADD_PATCHES_LIST(DebugDieTypeRefPatch)
+ ADD_PATCHES_LIST(DebugType2TypeDieRefPatch)
+ ADD_PATCHES_LIST(DebugTypeStrPatch)
+ ADD_PATCHES_LIST(DebugTypeLineStrPatch)
+ ADD_PATCHES_LIST(DebugTypeDeclFilePatch)
+
+ /// While creating patches, offsets to attributes may be partially
+ /// unknown(because size of abbreviation number is unknown). In such case we
+ /// remember patch itself and pointer to patch application offset to add size
+ /// of abbreviation number later.
template <typename T>
void notePatchWithOffsetUpdate(const T &Patch,
OffsetsPtrVector &PatchesOffsetsList) {
@@ -222,7 +281,6 @@ struct SectionDescriptor {
/// Emit specified integer value into the current section contents.
void emitIntVal(uint64_t Val, unsigned Size);
- /// Emit specified string value into the current section contents.
void emitString(dwarf::Form StringForm, const char *StringVal);
/// Emit specified inplace string value into the current section contents.
@@ -395,7 +453,8 @@ class OutputSections {
/// Enumerate all sections, for each section apply all section patches.
void applyPatches(SectionDescriptor &Section,
StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
- StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings);
+ StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
+ TypeUnit *TypeUnitPtr);
/// Endiannes for the sections.
llvm::endianness getEndianness() const { return Endianness; }
diff --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
new file mode 100644
index 000000000000000..e0900f7a8e3d3eb
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
@@ -0,0 +1,767 @@
+//===- SyntheticTypeNameBuilder.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 "SyntheticTypeNameBuilder.h"
+#include "DWARFLinkerCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+Error SyntheticTypeNameBuilder::assignName(
+ UnitEntryPairTy InputUnitEntryPair,
+ std::optional<std::pair<size_t, size_t>> ChildIndex) {
+ [[maybe_unused]] const CompileUnit::DIEInfo &Info =
+ InputUnitEntryPair.CU->getDIEInfo(InputUnitEntryPair.DieEntry);
+ assert(Info.needToPlaceInTypeTable() &&
+ "Cann't assign name for non-type DIE");
+
+ if (InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry) !=
+ nullptr)
+ return Error::success();
+
+ SyntheticName.resize(0);
+ RecursionDepth = 0;
+ return addDIETypeName(InputUnitEntryPair, ChildIndex, true);
+}
+
+void SyntheticTypeNameBuilder::addArrayDimension(
+ UnitEntryPairTy InputUnitEntryPair) {
+ for (const DWARFDebugInfoEntry *CurChild =
+ InputUnitEntryPair.CU->getFirstChildEntry(
+ InputUnitEntryPair.DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) {
+ if (CurChild->getTag() == dwarf::DW_TAG_subrange_type ||
+ CurChild->getTag() == dwarf::DW_TAG_generic_subrange) {
+ SyntheticName += "[";
+ if (std::optional<DWARFFormValue> Val =
+ InputUnitEntryPair.CU->find(CurChild, dwarf::DW_AT_count)) {
+ if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant()) {
+ SyntheticName += std::to_string(*ConstVal);
+ } else if (std::optional<int64_t> ConstVal =
+ Val->getAsSignedConstant()) {
+ SyntheticName += std::to_string(*ConstVal);
+ }
+ }
+
+ SyntheticName += "]";
+ }
+ }
+}
+
+static dwarf::Attribute TypeAttr[] = {dwarf::DW_AT_type};
+Error SyntheticTypeNameBuilder::addSignature(UnitEntryPairTy InputUnitEntryPair,
+ bool addTemplateParameters) {
+ // Add entry type.
+ if (Error Err = addReferencedODRDies(InputUnitEntryPair, false, TypeAttr))
+ return Err;
+ SyntheticName += ':';
+
+ SmallVector<const DWARFDebugInfoEntry *, 10> TemplateParameters;
+ SmallVector<const DWARFDebugInfoEntry *, 20> FunctionParameters;
+ for (const DWARFDebugInfoEntry *CurChild =
+ InputUnitEntryPair.CU->getFirstChildEntry(
+ InputUnitEntryPair.DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) {
+ dwarf::Tag ChildTag = CurChild->getTag();
+ if (addTemplateParameters &&
+ (ChildTag == dwarf::DW_TAG_template_type_parameter ||
+ ChildTag == dwarf::DW_TAG_template_value_parameter))
+ TemplateParameters.push_back(CurChild);
+ else if (ChildTag == dwarf::DW_TAG_formal_parameter ||
+ ChildTag == dwarf::DW_TAG_unspecified_parameters)
+ FunctionParameters.push_back(CurChild);
+ else if (addTemplateParameters &&
+ ChildTag == dwarf::DW_TAG_GNU_template_parameter_pack) {
+ for (const DWARFDebugInfoEntry *CurGNUChild =
+ InputUnitEntryPair.CU->getFirstChildEntry(CurChild);
+ CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr();
+ CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild))
+ TemplateParameters.push_back(CurGNUChild);
+ } else if (ChildTag == dwarf::DW_TAG_GNU_formal_parameter_pack) {
+ for (const DWARFDebugInfoEntry *CurGNUChild =
+ InputUnitEntryPair.CU->getFirstChildEntry(CurChild);
+ CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr();
+ CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild))
+ FunctionParameters.push_back(CurGNUChild);
+ }
+ }
+
+ // Add parameters.
+ if (Error Err = addParamNames(*InputUnitEntryPair.CU, FunctionParameters))
+ return Err;
+
+ // Add template parameters.
+ if (Error Err =
+ addTemplateParamNames(*InputUnitEntryPair.CU, TemplateParameters))
+ return Err;
+
+ return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addParamNames(
+ CompileUnit &CU,
+ SmallVector<const DWARFDebugInfoEntry *, 20> &FunctionParameters) {
+ SyntheticName += '(';
+ for (const DWARFDebugInfoEntry *FunctionParameter : FunctionParameters) {
+ if (SyntheticName.back() != '(')
+ SyntheticName += ", ";
+ if (dwarf::toUnsigned(CU.find(FunctionParameter, dwarf::DW_AT_artificial),
+ 0))
+ SyntheticName += "^";
+ if (Error Err = addReferencedODRDies(
+ UnitEntryPairTy{&CU, FunctionParameter}, false, TypeAttr))
+ return Err;
+ }
+ SyntheticName += ')';
+ return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addTemplateParamNames(
+ CompileUnit &CU,
+ SmallVector<const DWARFDebugInfoEntry *, 10> &TemplateParameters) {
+ if (!TemplateParameters.empty()) {
+ SyntheticName += '<';
+ for (const DWARFDebugInfoEntry *Parameter : TemplateParameters) {
+ if (SyntheticName.back() != '<')
+ SyntheticName += ", ";
+
+ if (Parameter->getTag() == dwarf::DW_TAG_template_value_parameter) {
+ if (std::optional<DWARFFormValue> Val =
+ CU.find(Parameter, dwarf::DW_AT_const_value)) {
+ if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant())
+ SyntheticName += std::to_string(*ConstVal);
+ else if (std::optional<int64_t> ConstVal = Val->getAsSignedConstant())
+ SyntheticName += std::to_string(*ConstVal);
+ }
+ }
+
+ if (Error Err = addReferencedODRDies(UnitEntryPairTy{&CU, Parameter},
+ false, TypeAttr))
+ return Err;
+ }
+ SyntheticName += '>';
+ }
+ return Error::success();
+}
+
+void SyntheticTypeNameBuilder::addOrderedName(
+ std::pair<size_t, size_t> ChildIdx) {
+ std::string Name;
+ llvm::raw_string_ostream stream(Name);
+ stream << format_hex_no_prefix(ChildIdx.first, ChildIdx.second);
+ SyntheticName += Name;
+}
+
+// Examine DIE and return type deduplication candidate: some DIEs could not be
+// deduplicated, namespace may refer to another namespace.
+static std::optional<UnitEntryPairTy>
+getTypeDeduplicationCandidate(UnitEntryPairTy UnitEntryPair) {
+ switch (UnitEntryPair.DieEntry->getTag()) {
+ case dwarf::DW_TAG_null:
+ case dwarf::DW_TAG_compile_unit:
+ case dwarf::DW_TAG_partial_unit:
+ case dwarf::DW_TAG_type_unit:
+ case dwarf::DW_TAG_skeleton_unit: {
+ return std::nullopt;
+ }
+ case dwarf::DW_TAG_namespace: {
+ // Check if current namespace refers another.
+ if (UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_extension))
+ UnitEntryPair = UnitEntryPair.getNamespaceOrigin();
+
+ // Content of anonimous namespaces should not be deduplicated.
+ if (!UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_name))
+ llvm_unreachable("Cann't deduplicate anonimous namespace");
+
+ return UnitEntryPair;
+ }
+ default:
+ return UnitEntryPair;
+ }
+}
+
+Error SyntheticTypeNameBuilder::addParentName(
+ UnitEntryPairTy &InputUnitEntryPair) {
+ std::optional<UnitEntryPairTy> UnitEntryPair = InputUnitEntryPair.getParent();
+ if (!UnitEntryPair)
+ return Error::success();
+
+ UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair);
+ if (!UnitEntryPair)
+ return Error::success();
+
+ if (TypeEntry *ImmediateParentName =
+ UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry)) {
+ SyntheticName += ImmediateParentName->getKey();
+ SyntheticName += ".";
+ return Error::success();
+ }
+
+ // Collect parent entries.
+ SmallVector<UnitEntryPairTy, 10> Parents;
+ do {
+ Parents.push_back(*UnitEntryPair);
+
+ UnitEntryPair = UnitEntryPair->getParent();
+ if (!UnitEntryPair)
+ break;
+
+ UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair);
+ if (!UnitEntryPair)
+ break;
+
+ } while (!UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry));
+
+ // Assign name for each parent entry.
+ size_t NameStart = SyntheticName.size();
+ for (UnitEntryPairTy Parent : reverse(Parents)) {
+ SyntheticName.resize(NameStart);
+ if (Error Err = addDIETypeName(Parent, std::nullopt, true))
+ return Err;
+ }
+
+ // Add parents delimiter.
+ SyntheticName += ".";
+ return Error::success();
+}
+
+void SyntheticTypeNameBuilder::addDieNameFromDeclFileAndDeclLine(
+ UnitEntryPairTy &InputUnitEntryPair, bool &HasDeclFileName) {
+ if (std::optional<DWARFFormValue> DeclFileVal = InputUnitEntryPair.CU->find(
+ InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_file)) {
+ if (std::optional<DWARFFormValue> DeclLineVal = InputUnitEntryPair.CU->find(
+ InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_line)) {
+ if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename =
+ InputUnitEntryPair.CU->getDirAndFilenameFromLineTable(
+ *DeclFileVal)) {
+ SyntheticName += DirAndFilename->first;
+ SyntheticName += DirAndFilename->second;
+
+ if (std::optional<uint64_t> DeclLineIntVal =
+ dwarf::toUnsigned(*DeclLineVal)) {
+ SyntheticName += " ";
+ SyntheticName += utohexstr(*DeclLineIntVal);
+ }
+
+ HasDeclFileName = true;
+ }
+ }
+ }
+}
+
+void SyntheticTypeNameBuilder::addValueName(UnitEntryPairTy InputUnitEntryPair,
+ dwarf::Attribute Attr) {
+ if (std::optional<DWARFFormValue> Val =
+ InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) {
+ if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant()) {
+ SyntheticName += " ";
+ SyntheticName += std::to_string(*ConstVal);
+ } else if (std::optional<int64_t> ConstVal = Val->getAsSignedConstant()) {
+ SyntheticName += " ";
+ SyntheticName += std::to_string(*ConstVal);
+ }
+ }
+}
+
+Error SyntheticTypeNameBuilder::addReferencedODRDies(
+ UnitEntryPairTy InputUnitEntryPair, bool AssignNameToTypeDescriptor,
+ ArrayRef<dwarf::Attribute> ODRAttrs) {
+ bool FirstIteration = true;
+ for (dwarf::Attribute Attr : ODRAttrs) {
+ if (std::optional<DWARFFormValue> AttrValue =
+ InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) {
+ std::optional<UnitEntryPairTy> RefDie =
+ InputUnitEntryPair.CU->resolveDIEReference(
+ *AttrValue, ResolveInterCUReferencesMode::Resolve);
+
+ if (!RefDie)
+ continue;
+
+ if (!RefDie->DieEntry)
+ return createStringError(std::errc::invalid_argument,
+ "Cann't resolve DIE reference");
+
+ if (!FirstIteration)
+ SyntheticName += ",";
+
+ RecursionDepth++;
+ if (RecursionDepth > 1000)
+ return createStringError(
+ std::errc::invalid_argument,
+ "Cann't parse input DWARF. Recursive dependence.");
+
+ if (Error Err =
+ addDIETypeName(*RefDie, std::nullopt, AssignNameToTypeDescriptor))
+ return Err;
+ RecursionDepth--;
+ FirstIteration = false;
+ }
+ }
+
+ return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addTypeName(UnitEntryPairTy InputUnitEntryPair,
+ bool AddParentNames) {
+ bool HasLinkageName = false;
+ bool HasShortName = false;
+ bool HasTemplatesInShortName = false;
+ bool HasDeclFileName = false;
+
+ // Try to get name from the DIE.
+ if (std::optional<DWARFFormValue> Val = InputUnitEntryPair.CU->find(
+ InputUnitEntryPair.DieEntry,
+ {dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_AT_linkage_name})) {
+ // Firstly check for linkage name.
+ SyntheticName += dwarf::toStringRef(Val);
+ HasLinkageName = true;
+ } else if (std::optional<DWARFFormValue> Val = InputUnitEntryPair.CU->find(
+ InputUnitEntryPair.DieEntry, dwarf::DW_AT_name)) {
+ // Then check for short name.
+ StringRef Name = dwarf::toStringRef(Val);
+ SyntheticName += Name;
+
+ HasShortName = true;
+ HasTemplatesInShortName =
+ Name.endswith(">") && Name.count("<") != 0 && !Name.endswith("<=>");
+ } else {
+ // Finally check for declaration attributes.
+ addDieNameFromDeclFileAndDeclLine(InputUnitEntryPair, HasDeclFileName);
+ }
+
+ // Add additional name parts for some DIEs.
+ switch (InputUnitEntryPair.DieEntry->getTag()) {
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_interface_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_subroutine_type:
+ case dwarf::DW_TAG_subprogram: {
+ if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry,
+ dwarf::DW_AT_artificial))
+ SyntheticName += "^";
+
+ // No need to add signature information for linkage name,
+ // also no need to add template parameters name if short name already
+ // includes them.
+ if (!HasLinkageName)
+ if (Error Err =
+ addSignature(InputUnitEntryPair, !HasTemplatesInShortName))
+ return Err;
+ } break;
+ case dwarf::DW_TAG_coarray_type:
+ case dwarf::DW_TAG_array_type: {
+ addArrayDimension(InputUnitEntryPair);
+ } break;
+ case dwarf::DW_TAG_subrange_type: {
+ addValueName(InputUnitEntryPair, dwarf::DW_AT_count);
+ } break;
+ case dwarf::DW_TAG_template_value_parameter: {
+ if (!HasTemplatesInShortName) {
+ // TODO add support for DW_AT_location
+ addValueName(InputUnitEntryPair, dwarf::DW_AT_const_value);
+ }
+ } break;
+ default: {
+ // Nothing to do.
+ } break;
+ }
+
+ // If name for the DIE is not determined yet add referenced types to the name.
+ if (!HasLinkageName && !HasShortName && !HasDeclFileName) {
+ if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry,
+ getODRAttributes()))
+ if (Error Err = addReferencedODRDies(InputUnitEntryPair, AddParentNames,
+ getODRAttributes()))
+ return Err;
+ }
+
+ return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addDIETypeName(
+ UnitEntryPairTy InputUnitEntryPair,
+ std::optional<std::pair<size_t, size_t>> ChildIndex,
+ bool AssignNameToTypeDescriptor) {
+ std::optional<UnitEntryPairTy> UnitEntryPair =
+ getTypeDeduplicationCandidate(InputUnitEntryPair);
+ if (!UnitEntryPair)
+ return Error::success();
+
+ TypeEntry *TypeEntryPtr =
+ InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry);
+ // Check if DIE already has a name.
+ if (!TypeEntryPtr) {
+ size_t NameStart = SyntheticName.size();
+ if (AssignNameToTypeDescriptor) {
+ if (Error Err = addParentName(*UnitEntryPair))
+ return Err;
+ }
+ addTypePrefix(UnitEntryPair->DieEntry);
+
+ if (ChildIndex) {
+ addOrderedName(*ChildIndex);
+ } else {
+ if (Error Err = addTypeName(*UnitEntryPair, AssignNameToTypeDescriptor))
+ return Err;
+ }
+
+ if (AssignNameToTypeDescriptor) {
+ // Add built name to the DIE.
+ TypeEntryPtr = TypePoolRef.insert(SyntheticName.substr(NameStart));
+ InputUnitEntryPair.CU->setDieTypeEntry(InputUnitEntryPair.DieEntry,
+ TypeEntryPtr);
+ }
+ } else
+ SyntheticName += TypeEntryPtr->getKey();
+
+ return Error::success();
+}
+
+void SyntheticTypeNameBuilder::addTypePrefix(
+ const DWARFDebugInfoEntry *DieEntry) {
+ switch (DieEntry->getTag()) {
+ case dwarf::DW_TAG_base_type: {
+ SyntheticName += "{0}";
+ } break;
+ case dwarf::DW_TAG_namespace: {
+ SyntheticName += "{1}";
+ } break;
+ case dwarf::DW_TAG_formal_parameter: {
+ SyntheticName += "{2}";
+ } break;
+ // dwarf::DW_TAG_unspecified_parameters have the same prefix as before.
+ case dwarf::DW_TAG_unspecified_parameters: {
+ SyntheticName += "{2}";
+ } break;
+ case dwarf::DW_TAG_template_type_parameter: {
+ SyntheticName += "{3}";
+ } break;
+ // dwarf::DW_TAG_template_value_parameter have the same prefix as before.
+ case dwarf::DW_TAG_template_value_parameter: {
+ SyntheticName += "{3}";
+ } break;
+ case dwarf::DW_TAG_GNU_formal_parameter_pack: {
+ SyntheticName += "{4}";
+ } break;
+ case dwarf::DW_TAG_GNU_template_parameter_pack: {
+ SyntheticName += "{5}";
+ } break;
+ case dwarf::DW_TAG_inheritance: {
+ SyntheticName += "{6}";
+ } break;
+ case dwarf::DW_TAG_array_type: {
+ SyntheticName += "{7}";
+ } break;
+ case dwarf::DW_TAG_class_type: {
+ SyntheticName += "{8}";
+ } break;
+ case dwarf::DW_TAG_enumeration_type: {
+ SyntheticName += "{9}";
+ } break;
+ case dwarf::DW_TAG_imported_declaration: {
+ SyntheticName += "{A}";
+ } break;
+ case dwarf::DW_TAG_member: {
+ SyntheticName += "{B}";
+ } break;
+ case dwarf::DW_TAG_pointer_type: {
+ SyntheticName += "{C}";
+ } break;
+ case dwarf::DW_TAG_reference_type: {
+ SyntheticName += "{D}";
+ } break;
+ case dwarf::DW_TAG_string_type: {
+ SyntheticName += "{E}";
+ } break;
+ case dwarf::DW_TAG_structure_type: {
+ SyntheticName += "{F}";
+ } break;
+ case dwarf::DW_TAG_subroutine_type: {
+ SyntheticName += "{G}";
+ } break;
+ case dwarf::DW_TAG_typedef: {
+ SyntheticName += "{H}";
+ } break;
+ case dwarf::DW_TAG_union_type: {
+ SyntheticName += "{I}";
+ } break;
+ case dwarf::DW_TAG_variant: {
+ SyntheticName += "{J}";
+ } break;
+ case dwarf::DW_TAG_inlined_subroutine: {
+ SyntheticName += "{K}";
+ } break;
+ case dwarf::DW_TAG_module: {
+ SyntheticName += "{L}";
+ } break;
+ case dwarf::DW_TAG_ptr_to_member_type: {
+ SyntheticName += "{M}";
+ } break;
+ case dwarf::DW_TAG_set_type: {
+ SyntheticName += "{N}";
+ } break;
+ case dwarf::DW_TAG_subrange_type: {
+ SyntheticName += "{O}";
+ } break;
+ case dwarf::DW_TAG_with_stmt: {
+ SyntheticName += "{P}";
+ } break;
+ case dwarf::DW_TAG_access_declaration: {
+ SyntheticName += "{Q}";
+ } break;
+ case dwarf::DW_TAG_catch_block: {
+ SyntheticName += "{R}";
+ } break;
+ case dwarf::DW_TAG_const_type: {
+ SyntheticName += "{S}";
+ } break;
+ case dwarf::DW_TAG_constant: {
+ SyntheticName += "{T}";
+ } break;
+ case dwarf::DW_TAG_enumerator: {
+ SyntheticName += "{U}";
+ } break;
+ case dwarf::DW_TAG_file_type: {
+ SyntheticName += "{V}";
+ } break;
+ case dwarf::DW_TAG_friend: {
+ SyntheticName += "{W}";
+ } break;
+ case dwarf::DW_TAG_namelist: {
+ SyntheticName += "{X}";
+ } break;
+ case dwarf::DW_TAG_namelist_item: {
+ SyntheticName += "{Y}";
+ } break;
+ case dwarf::DW_TAG_packed_type: {
+ SyntheticName += "{Z}";
+ } break;
+ case dwarf::DW_TAG_subprogram: {
+ SyntheticName += "{a}";
+ } break;
+ case dwarf::DW_TAG_thrown_type: {
+ SyntheticName += "{b}";
+ } break;
+ case dwarf::DW_TAG_variant_part: {
+ SyntheticName += "{c}";
+ } break;
+ case dwarf::DW_TAG_variable: {
+ SyntheticName += "{d}";
+ } break;
+ case dwarf::DW_TAG_volatile_type: {
+ SyntheticName += "{e}";
+ } break;
+ case dwarf::DW_TAG_dwarf_procedure: {
+ SyntheticName += "{f}";
+ } break;
+ case dwarf::DW_TAG_restrict_type: {
+ SyntheticName += "{g}";
+ } break;
+ case dwarf::DW_TAG_interface_type: {
+ SyntheticName += "{h}";
+ } break;
+ case dwarf::DW_TAG_imported_module: {
+ SyntheticName += "{i}";
+ } break;
+ case dwarf::DW_TAG_unspecified_type: {
+ SyntheticName += "{j}";
+ } break;
+ case dwarf::DW_TAG_imported_unit: {
+ SyntheticName += "{k}";
+ } break;
+ case dwarf::DW_TAG_condition: {
+ SyntheticName += "{l}";
+ } break;
+ case dwarf::DW_TAG_shared_type: {
+ SyntheticName += "{m}";
+ } break;
+ case dwarf::DW_TAG_rvalue_reference_type: {
+ SyntheticName += "{n}";
+ } break;
+ case dwarf::DW_TAG_template_alias: {
+ SyntheticName += "{o}";
+ } break;
+ case dwarf::DW_TAG_coarray_type: {
+ SyntheticName += "{p}";
+ } break;
+ case dwarf::DW_TAG_generic_subrange: {
+ SyntheticName += "{q}";
+ } break;
+ case dwarf::DW_TAG_dynamic_type: {
+ SyntheticName += "{r}";
+ } break;
+ case dwarf::DW_TAG_atomic_type: {
+ SyntheticName += "{s}";
+ } break;
+ case dwarf::DW_TAG_call_site: {
+ SyntheticName += "{t}";
+ } break;
+ case dwarf::DW_TAG_call_site_parameter: {
+ SyntheticName += "{u}";
+ } break;
+ case dwarf::DW_TAG_immutable_type: {
+ SyntheticName += "{v}";
+ } break;
+ case dwarf::DW_TAG_entry_point: {
+ SyntheticName += "{w}";
+ } break;
+ case dwarf::DW_TAG_label: {
+ SyntheticName += "{x}";
+ } break;
+ case dwarf::DW_TAG_lexical_block: {
+ SyntheticName += "{y}";
+ } break;
+ case dwarf::DW_TAG_common_block: {
+ SyntheticName += "{z}";
+ } break;
+ case dwarf::DW_TAG_common_inclusion: {
+ SyntheticName += "{|}";
+ } break;
+ case dwarf::DW_TAG_try_block: {
+ SyntheticName += "{~}";
+ } break;
+
+ case dwarf::DW_TAG_null: {
+ llvm_unreachable("No type prefix for DW_TAG_null");
+ } break;
+ case dwarf::DW_TAG_compile_unit: {
+ llvm_unreachable("No type prefix for DW_TAG_compile_unit");
+ } break;
+ case dwarf::DW_TAG_partial_unit: {
+ llvm_unreachable("No type prefix for DW_TAG_partial_unit");
+ } break;
+ case dwarf::DW_TAG_type_unit: {
+ llvm_unreachable("No type prefix for DW_TAG_type_unit");
+ } break;
+ case dwarf::DW_TAG_skeleton_unit: {
+ llvm_unreachable("No type prefix for DW_TAG_skeleton_unit");
+ } break;
+
+ default: {
+ SyntheticName += "{~~";
+ SyntheticName += utohexstr(DieEntry->getTag());
+ SyntheticName += "}";
+ } break;
+ }
+}
+
+OrderedChildrenIndexAssigner::OrderedChildrenIndexAssigner(
+ CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) {
+ switch (DieEntry->getTag()) {
+ case dwarf::DW_TAG_array_type:
+ case dwarf::DW_TAG_coarray_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_common_block:
+ case dwarf::DW_TAG_lexical_block:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_subprogram:
+ case dwarf::DW_TAG_subroutine_type:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_GNU_template_template_param:
+ case dwarf::DW_TAG_GNU_formal_parameter_pack: {
+ NeedCountChildren = true;
+ } break;
+ case dwarf::DW_TAG_enumeration_type: {
+ // TODO : do we need to add condition
+ NeedCountChildren = true;
+ } break;
+ default: {
+ // Nothing to do.
+ }
+ }
+
+ // Calculate maximal index value
+ if (NeedCountChildren) {
+ for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(DieEntry);
+ CurChild && CurChild->getAbbreviationDeclarationPtr();
+ CurChild = CU.getSiblingEntry(CurChild)) {
+ std::optional<size_t> ArrayIndex = tagToArrayIndex(CU, CurChild);
+ if (!ArrayIndex)
+ continue;
+
+ assert((*ArrayIndex < ChildIndexesWidth.size()) &&
+ "Wrong index for ChildIndexesWidth");
+ ChildIndexesWidth[*ArrayIndex]++;
+ }
+
+ // Calculate index field width(number of digits in hexadecimal
+ // representation).
+ for (size_t &Width : ChildIndexesWidth) {
+ size_t digitsCounter = 1;
+ size_t NumToCompare = 15;
+
+ while (NumToCompare < Width) {
+ NumToCompare <<= 4;
+ digitsCounter++;
+ }
+
+ Width = digitsCounter;
+ }
+ }
+}
+
+std::optional<size_t> OrderedChildrenIndexAssigner::tagToArrayIndex(
+ CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) {
+ if (!NeedCountChildren)
+ return std::nullopt;
+
+ switch (DieEntry->getTag()) {
+ case dwarf::DW_TAG_unspecified_parameters:
+ case dwarf::DW_TAG_formal_parameter:
+ return 0;
+ case dwarf::DW_TAG_template_value_parameter:
+ case dwarf::DW_TAG_template_type_parameter:
+ return 1;
+ case dwarf::DW_TAG_enumeration_type:
+ if (std::optional<uint32_t> ParentIdx = DieEntry->getParentIdx()) {
+ if (*ParentIdx && CU.getDebugInfoEntry(*ParentIdx)->getTag() ==
+ dwarf::DW_TAG_array_type)
+ return 2;
+ }
+ return std::nullopt;
+ case dwarf::DW_TAG_subrange_type:
+ return 3;
+ case dwarf::DW_TAG_generic_subrange:
+ return 4;
+ case dwarf::DW_TAG_enumerator:
+ return 5;
+ case dwarf::DW_TAG_namelist_item:
+ return 6;
+ case dwarf::DW_TAG_member:
+ return 7;
+ default:
+ return std::nullopt;
+ };
+}
+
+std::optional<std::pair<size_t, size_t>>
+OrderedChildrenIndexAssigner::getChildIndex(
+ CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry) {
+ std::optional<size_t> ArrayIndex = tagToArrayIndex(CU, ChildDieEntry);
+ if (!ArrayIndex)
+ return std::nullopt;
+
+ assert((*ArrayIndex < OrderedChildIdxs.size()) &&
+ "Wrong index for ChildIndexesWidth");
+ assert(ChildIndexesWidth[*ArrayIndex] < 16 &&
+ "Index width exceeds 16 digits.");
+
+ std::pair<size_t, size_t> Result = std::make_pair(
+ OrderedChildIdxs[*ArrayIndex], ChildIndexesWidth[*ArrayIndex]);
+ OrderedChildIdxs[*ArrayIndex]++;
+ return Result;
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm
diff --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
new file mode 100644
index 000000000000000..c9dce4e94fb0dc3
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
@@ -0,0 +1,155 @@
+//===- SyntheticTypeNameBuilder.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_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H
+#define LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H
+
+#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerGlobalData.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+class DWARFDebugInfoEntry;
+
+namespace dwarflinker_parallel {
+struct LinkContext;
+class TypeTableUnit;
+class CompileUnit;
+
+/// The helper class to build type name based on DIE properties.
+/// It builds synthetic name based on explicit attributes: DW_AT_name,
+/// DW_AT_linkage_name or based on implicit attributes(DW_AT_decl*).
+/// Names for specific DIEs(like subprograms, template classes...) include
+/// additional attributes: subprogram parameters, template parameters,
+/// array ranges. Examples of built name:
+///
+/// class A { } : {8}A
+///
+/// namspace llvm { class A { } } : {1}llvm{8}A
+///
+/// template <int> structure B { } : {F}B<{0}int>
+///
+/// void foo ( int p1, float p3 ) : {a}void foo({0}int, {0}int)
+///
+/// int *ptr; : {c}ptr {0}int
+///
+/// int var; : {d}var
+///
+/// These names is used to refer DIEs describing types.
+class SyntheticTypeNameBuilder {
+public:
+ SyntheticTypeNameBuilder(TypePool &TypePoolRef) : TypePoolRef(TypePoolRef) {}
+
+ /// Create synthetic name for the specified DIE \p InputUnitEntryPair
+ /// and assign created name to the DIE type info. \p ChildIndex is used
+ /// to create name for ordered DIEs(function arguments f.e.).
+ Error assignName(UnitEntryPairTy InputUnitEntryPair,
+ std::optional<std::pair<size_t, size_t>> ChildIndex);
+
+protected:
+ /// Add array type dimension.
+ void addArrayDimension(UnitEntryPairTy InputUnitEntryPair);
+
+ /// Add signature( entry type plus type of parameters plus type of template
+ /// parameters(if \p addTemplateParameters is true).
+ Error addSignature(UnitEntryPairTy InputUnitEntryPair,
+ bool addTemplateParameters);
+
+ /// Add specified \p FunctionParameters to the built name.
+ Error addParamNames(
+ CompileUnit &CU,
+ SmallVector<const DWARFDebugInfoEntry *, 20> &FunctionParameters);
+
+ /// Add specified \p TemplateParameters to the built name.
+ Error addTemplateParamNames(
+ CompileUnit &CU,
+ SmallVector<const DWARFDebugInfoEntry *, 10> &TemplateParameters);
+
+ /// Add ordered name to the built name.
+ void addOrderedName(CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry);
+
+ /// Analyze \p InputUnitEntryPair's ODR attributes and put names
+ /// of the referenced type dies to the built name.
+ Error addReferencedODRDies(UnitEntryPairTy InputUnitEntryPair,
+ bool AssignNameToTypeDescriptor,
+ ArrayRef<dwarf::Attribute> ODRAttrs);
+
+ /// Add names of parent dies to the built name.
+ Error addParentName(UnitEntryPairTy &InputUnitEntryPair);
+
+ /// \returns synthetic name of the specified \p DieEntry.
+ /// The name is constructed from the dwarf::DW_AT_decl_file
+ /// and dwarf::DW_AT_decl_line attributes.
+ void addDieNameFromDeclFileAndDeclLine(UnitEntryPairTy &InputUnitEntryPair,
+ bool &HasDeclFileName);
+
+ /// Add type prefix to the built name.
+ void addTypePrefix(const DWARFDebugInfoEntry *DieEntry);
+
+ /// Add type name to the built name.
+ Error addTypeName(UnitEntryPairTy InputUnitEntryPair, bool AddParentNames);
+
+ /// Analyze \p InputUnitEntryPair for the type name and possibly assign
+ /// built type name to the DIE's type info.
+ /// NOTE: while analyzing types we may create
diff erent kind of names
+ /// for the same type depending on whether the type is part of another type.
+ /// f.e. DW_TAG_formal_parameter would receive "{02}01" name when
+ /// examined alone. Or "{0}int" name when it is a part of a function name:
+ /// {a}void foo({0}int). The \p AssignNameToTypeDescriptor tells whether
+ /// the type name is part of another type name and then should not be assigned
+ /// to DIE type descriptor.
+ Error addDIETypeName(UnitEntryPairTy InputUnitEntryPair,
+ std::optional<std::pair<size_t, size_t>> ChildIndex,
+ bool AssignNameToTypeDescriptor);
+
+ /// Add ordered name to the built name.
+ void addOrderedName(std::pair<size_t, size_t> ChildIdx);
+
+ /// Add value name to the built name.
+ void addValueName(UnitEntryPairTy InputUnitEntryPair, dwarf::Attribute Attr);
+
+ /// Buffer keeping bult name.
+ SmallString<1000> SyntheticName;
+
+ /// Recursion counter
+ size_t RecursionDepth = 0;
+
+ /// Type pool
+ TypePool &TypePoolRef;
+};
+
+/// This class helps to assign indexes for DIE children.
+/// Indexes are used to create type name for children which
+/// should be presented in the original order(function parameters,
+/// array dimensions, enumeration members, class/structure members).
+class OrderedChildrenIndexAssigner {
+public:
+ OrderedChildrenIndexAssigner(CompileUnit &CU,
+ const DWARFDebugInfoEntry *DieEntry);
+
+ /// Returns index of the specified child and width of hexadecimal
+ /// representation.
+ std::optional<std::pair<size_t, size_t>>
+ getChildIndex(CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry);
+
+protected:
+ using OrderedChildrenIndexesArrayTy = std::array<size_t, 8>;
+
+ std::optional<size_t> tagToArrayIndex(CompileUnit &CU,
+ const DWARFDebugInfoEntry *DieEntry);
+
+ bool NeedCountChildren = false;
+ OrderedChildrenIndexesArrayTy OrderedChildIdxs = {0};
+ OrderedChildrenIndexesArrayTy ChildIndexesWidth = {0};
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H
diff --git a/llvm/lib/DWARFLinkerParallel/TypePool.h b/llvm/lib/DWARFLinkerParallel/TypePool.h
new file mode 100644
index 000000000000000..bbb3261027ce894
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/TypePool.h
@@ -0,0 +1,177 @@
+//===- TypePool.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_DWARFLINKERPARALLEL_TYPEPOOL_H
+#define LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H
+
+#include "ArrayList.h"
+#include "llvm/ADT/ConcurrentHashtable.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/Support/Allocator.h"
+#include <atomic>
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+class TypePool;
+class CompileUnit;
+class TypeEntryBody;
+
+using TypeEntry = StringMapEntry<std::atomic<TypeEntryBody *>>;
+
+/// Keeps cloned data for the type DIE.
+class TypeEntryBody {
+public:
+ /// Returns copy of type DIE which should be emitted into resulting file.
+ DIE &getFinalDie() const {
+ if (Die)
+ return *Die;
+
+ assert(DeclarationDie);
+ return *DeclarationDie;
+ }
+
+ /// Returns true if type die entry has only declaration die.
+ bool hasOnlyDeclaration() const { return Die == nullptr; }
+
+ /// Creates type DIE for the specified name.
+ static TypeEntryBody *create(parallel::PerThreadBumpPtrAllocator &Allocator) {
+ TypeEntryBody *Result = Allocator.Allocate<TypeEntryBody>();
+ new (Result) TypeEntryBody(Allocator);
+ return Result;
+ }
+
+ /// TypeEntryBody keeps partially cloned DIEs corresponding to this type.
+ /// The two kinds of DIE can be kept: declaration and definition.
+ /// If definition DIE was met while parsing input DWARF then this DIE would
+ /// be used as a final DIE for this type. If definition DIE is not met then
+ /// declaration DIE would be used as a final DIE.
+
+ // Keeps definition die.
+ std::atomic<DIE *> Die = {nullptr};
+
+ // Keeps declaration die.
+ std::atomic<DIE *> DeclarationDie = {nullptr};
+
+ // True if parent type die is declaration.
+ std::atomic<bool> ParentIsDeclaration = {true};
+
+ /// Children for current type.
+ ArrayList<TypeEntry *, 5> Children;
+
+protected:
+ TypeEntryBody() = delete;
+ TypeEntryBody(const TypeEntryBody &RHS) = delete;
+ TypeEntryBody(TypeEntryBody &&RHS) = delete;
+ TypeEntryBody &operator=(const TypeEntryBody &RHS) = delete;
+ TypeEntryBody &operator=(const TypeEntryBody &&RHS) = delete;
+
+ TypeEntryBody(parallel::PerThreadBumpPtrAllocator &Allocator)
+ : Children(&Allocator) {}
+};
+
+class TypeEntryInfo {
+public:
+ /// \returns Hash value for the specified \p Key.
+ static inline uint64_t getHashValue(const StringRef &Key) {
+ return xxh3_64bits(Key);
+ }
+
+ /// \returns true if both \p LHS and \p RHS are equal.
+ static inline bool isEqual(const StringRef &LHS, const StringRef &RHS) {
+ return LHS == RHS;
+ }
+
+ /// \returns key for the specified \p KeyData.
+ static inline StringRef getKey(const TypeEntry &KeyData) {
+ return KeyData.getKey();
+ }
+
+ /// \returns newly created object of KeyDataTy type.
+ static inline TypeEntry *
+ create(const StringRef &Key, parallel::PerThreadBumpPtrAllocator &Allocator) {
+ return TypeEntry::create(Key, Allocator);
+ }
+};
+
+/// TypePool keeps type descriptors which contain partially cloned DIE
+/// correspinding to each type. Types are identified by names.
+class TypePool : ConcurrentHashTableByPtr<StringRef, TypeEntry,
+ parallel::PerThreadBumpPtrAllocator,
+ TypeEntryInfo> {
+public:
+ TypePool()
+ : ConcurrentHashTableByPtr<StringRef, TypeEntry,
+ parallel::PerThreadBumpPtrAllocator,
+ TypeEntryInfo>(Allocator) {
+ Root = TypeEntry::create("", Allocator);
+ Root->getValue().store(TypeEntryBody::create(Allocator));
+ }
+
+ TypeEntry *insert(StringRef Name) {
+ return ConcurrentHashTableByPtr<StringRef, TypeEntry,
+ parallel::PerThreadBumpPtrAllocator,
+ TypeEntryInfo>::insert(Name)
+ .first;
+ }
+
+ /// Create or return existing type entry body for the specified \p Entry.
+ /// Link that entry as child for the specified \p ParentEntry.
+ /// \returns The existing or created type entry body.
+ TypeEntryBody *getOrCreateTypeEntryBody(TypeEntry *Entry,
+ TypeEntry *ParentEntry) {
+ TypeEntryBody *DIE = Entry->getValue().load();
+ if (DIE)
+ return DIE;
+
+ TypeEntryBody *NewDIE = TypeEntryBody::create(Allocator);
+ if (Entry->getValue().compare_exchange_weak(DIE, NewDIE)) {
+ ParentEntry->getValue().load()->Children.add(Entry);
+ return NewDIE;
+ }
+
+ return DIE;
+ }
+
+ /// Sort children for each kept type entry.
+ void sortTypes() {
+ std::function<void(TypeEntry * Entry)> SortChildrenRec =
+ [&](TypeEntry *Entry) {
+ Entry->getValue().load()->Children.sort(TypesComparator);
+ Entry->getValue().load()->Children.forEach(SortChildrenRec);
+ };
+
+ SortChildrenRec(getRoot());
+ }
+
+ /// Return root for all type entries.
+ TypeEntry *getRoot() const { return Root; }
+
+ /// Return thread local allocator used by pool.
+ BumpPtrAllocator &getThreadLocalAllocator() {
+ return Allocator.getThreadLocalAllocator();
+ }
+
+protected:
+ std::function<bool(const TypeEntry *LHS, const TypeEntry *RHS)>
+ TypesComparator = [](const TypeEntry *LHS, const TypeEntry *RHS) -> bool {
+ return LHS->getKey() < RHS->getKey();
+ };
+
+ // Root of all type entries.
+ TypeEntry *Root = nullptr;
+
+private:
+ parallel::PerThreadBumpPtrAllocator Allocator;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H
diff --git a/llvm/lib/DWARFLinkerParallel/Utils.h b/llvm/lib/DWARFLinkerParallel/Utils.h
new file mode 100644
index 000000000000000..91f9dca46a82b1c
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/Utils.h
@@ -0,0 +1,40 @@
+//===- Utils.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_UTILS_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// This function calls \p Iteration() until it returns false.
+/// If number of iterations exceeds \p MaxCounter then an Error is returned.
+/// This function should be used for loops which assumed to have number of
+/// iterations significantly smaller than \p MaxCounter to avoid infinite
+/// looping in error cases.
+inline Error finiteLoop(function_ref<Expected<bool>()> Iteration,
+ size_t MaxCounter = 100000) {
+ size_t iterationsCounter = 0;
+ while (iterationsCounter++ < MaxCounter) {
+ Expected<bool> IterationResultOrError = Iteration();
+ if (!IterationResultOrError)
+ return IterationResultOrError.takeError();
+
+ if (!IterationResultOrError.get())
+ return Error::success();
+ }
+
+ return createStringError(std::errc::invalid_argument, "Infinite recursion");
+}
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H
diff --git a/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
new file mode 100644
index 000000000000000..3f75991cdc471e1
--- /dev/null
+++ b/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
@@ -0,0 +1,80 @@
+RUN: dsymutil --linker llvm -accelerator=Dwarf \
+RUN: -oso-prepend-path=%p/../../Inputs \
+RUN: %p/../../Inputs/accel-imported-declaration.macho-arm64 -o %t.dwarf.dSYM
+RUN: dsymutil --linker llvm -accelerator=Apple \
+RUN: -oso-prepend-path=%p/../../Inputs \
+RUN: %p/../../Inputs/accel-imported-declaration.macho-arm64 -o %t.apple.dSYM
+
+RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON
+RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON
+
+COMMON: .debug_info contents
+COMMON: DW_TAG_compile_unit
+COMMON: DW_AT_name{{.*}}"__artificial_type_unit"
+COMMON: DW_TAG_base_type
+COMMON: DW_AT_name{{.*}}"int"
+COMMON: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"A"
+COMMON: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"B"
+COMMON: 0x[[NAMESPACE_C_1:[0-9a-f]*]]: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"C"
+COMMON-NOT: DW_TAG_variable
+COMMON: 0x[[NAMESPACE_C_2:[0-9a-f]*]]: DW_TAG_imported_declaration
+COMMON: DW_AT_import{{.*}}[[NAMESPACE_C_1]]
+COMMON: DW_AT_name{{.*}}"C"
+COMMON: DW_TAG_imported_module
+COMMON: DW_AT_import{{.*}}[[NAMESPACE_C_1]]
+
+
+COMMON: DW_TAG_compile_unit
+COMMON: {{.*}}DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"A"
+COMMON: {{.*}}DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"B"
+COMMON: 0x[[NAMESPACE_C_3:[0-9a-f]*]]: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"C"
+COMMON: 0x[[VAR_A:[0-9a-f]*]]: DW_TAG_variable
+COMMON: DW_TAG_imported_declaration
+COMMON: DW_AT_import{{.*}}[[VAR_A]]
+
+DWARF: .debug_names contents:
+DWARF: Bucket 0 [
+DWARF-NEXT: Name {{.*}} {
+DWARF-NEXT: Hash: {{.*}}
+DWARF-NEXT: String: {{.*}} "C"
+DWARF-NEXT: Entry {{.*}} {
+DWARF-NEXT: Abbrev: {{.*}}
+DWARF-NEXT: Tag: DW_TAG_namespace
+DWARF: DW_IDX_die_offset: 0x0000002f
+DWARF-NEXT: }
+DWARF-NEXT: Entry {{.*}} {
+DWARF-NEXT: Abbrev: {{.*}}
+DWARF: Tag: DW_TAG_imported_declaration
+DWARF: DW_IDX_die_offset: 0x00000035
+DWARF-NEXT: }
+DWARF-NEXT: Entry {{.*}} {
+DWARF-NEXT: Abbrev: {{.*}}
+DWARF-NEXT: Tag: DW_TAG_namespace
+DWARF: DW_IDX_die_offset: 0x0000003c
+DWARF-NEXT: }
+
+DWARF-NEXT: }
+
+APPLE: .apple_namespaces contents:
+APPLE: Bucket 1 [
+APPLE-NEXT: Hash {{.*}} [
+APPLE-NEXT: Name@{{.*}} {
+APPLE-NEXT: String: {{.*}} "C"
+APPLE-NEXT: Data 0 [
+APPLE-NEXT: Atom[0]: 0x[[NAMESPACE_C_1]]
+APPLE-NEXT: ]
+APPLE-NEXT: Data 1 [
+APPLE-NEXT: Atom[0]: 0x[[NAMESPACE_C_2]]
+APPLE-NEXT: ]
+APPLE-NEXT: Data 2 [
+APPLE-NEXT: Atom[0]: 0x[[NAMESPACE_C_3]]
+APPLE-NEXT: ]
+APPLE: }
+APPLE-NEXT: ]
+APPLE-NEXT: ]
diff --git a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
index f1680ced6e5b4f0..057e89d060b1d27 100644
--- a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
+++ b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
@@ -4,14 +4,6 @@ RUN: dsymutil -accelerator=Apple -oso-prepend-path=%p/../Inputs %p/../Inputs/acc
RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON
RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON
-RUN: dsymutil --linker llvm -accelerator=Dwarf -oso-prepend-path=%p/../Inputs \
-RUN: %p/../Inputs/accel-imported-declaration.macho-arm64 -o %t.dwarf.dSYM
-RUN: dsymutil --linker llvm -accelerator=Apple -oso-prepend-path=%p/../Inputs \
-RUN: %p/../Inputs/accel-imported-declaration.macho-arm64 -o %t.apple.dSYM
-
-RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON
-RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON
-
COMMON: .debug_info contents
COMMON: {{.*}}DW_TAG_namespace
COMMON: DW_AT_name{{.*}}"A"
@@ -19,7 +11,7 @@ COMMON: {{.*}}DW_TAG_namespace
COMMON: DW_AT_name{{.*}}"B"
COMMON: [[NAMESPACE:0x[0-9a-f]*]]:{{.*}}DW_TAG_namespace
COMMON: DW_AT_name{{.*}}"C"
-COMMON: [[IMPORTED:0x[0-9a-f]*]]:{{.*}}DW_TAG_imported_declaration
+COMMON: 0x0000005c:{{.*}}DW_TAG_imported_declaration
COMMON: DW_AT_name{{.*}}"C"
DWARF: .debug_names contents:
@@ -30,12 +22,12 @@ DWARF-NEXT: String: {{.*}} "C"
DWARF-NEXT: Entry {{.*}} {
DWARF-NEXT: Abbrev: {{.*}}
DWARF-NEXT: Tag: DW_TAG_namespace
-DWARF-NEXT: DW_IDX_die_offset: [[NAMESPACE]]
+DWARF: DW_IDX_die_offset: [[NAMESPACE]]
DWARF-NEXT: }
DWARF-NEXT: Entry {{.*}} {
DWARF-NEXT: Abbrev: {{.*}}
-DWARF-NEXT: Tag: DW_TAG_imported_declaration
-DWARF-NEXT: DW_IDX_die_offset: [[IMPORTED]]
+DWARF: Tag: DW_TAG_imported_declaration
+DWARF: DW_IDX_die_offset: 0x0000005c
DWARF-NEXT: }
DWARF-NEXT: }
@@ -48,8 +40,8 @@ APPLE-NEXT: Data 0 [
APPLE-NEXT: Atom[0]: [[NAMESPACE]]
APPLE-NEXT: ]
APPLE-NEXT: Data 1 [
-APPLE-NEXT: Atom[0]: [[IMPORTED]]
+APPLE-NEXT: Atom[0]: {{0x0000005c|0x0000006f}}
APPLE-NEXT: ]
-APPLE-NEXT: }
+APPLE: }
APPLE-NEXT: ]
APPLE-NEXT: ]
diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test b/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
index 00dcde718e36225..ca4a951e770ba2a 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
@@ -50,15 +50,30 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
RUN: rm -rf %t.dir && mkdir -p %t.dir
-RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
RUN: -o %t.dir/dwarf5-addr-base.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
+RUN: rm -rf %t.dir && mkdir -p %t.dir
+RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN: -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN: FileCheck %s --check-prefixes=CHECK,CHECK-LLVM
+
+
RUN: rm -rf %t.dir && mkdir -p %t.dir
RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefix=UPD
+RUN: rm -rf %t.dir && mkdir -p %t.dir
+RUN: dsymutil --linker llvm --no-odr --update -y %p/dummy-debug-map-amr64.map \
+RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN: -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN: FileCheck %s --check-prefix=UPD
+
RUN: rm -rf %t.dir && mkdir -p %t.dir
RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
@@ -66,30 +81,36 @@ RUN: -o %t.dir/dwarf5-addr-base.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
RUN: FileCheck %s --check-prefix=UPD
+
CHECK: .debug_info contents:
-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
-CHECK: 0x0000000c: DW_TAG_compile_unit [1] *
-CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
-CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
+CHECK: DW_TAG_subprogram
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR1:[0-9a-f]+]])
-CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
-CHECK: 0x0000005a: DW_TAG_compile_unit [1] *
+CHECK: DW_TAG_compile_unit
CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000018)
-CHECK: 0x0000007a: DW_TAG_subprogram [2] * (0x0000005a)
+CHECK: DW_TAG_subprogram
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR2:[0-9a-f]+]])
-CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08
+CHECK: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
-CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} *
+CHECK: DW_TAG_compile_unit
CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000028)
-CHECK: 0x000000c1: DW_TAG_subprogram [2] * (0x000000a8)
+CHECK: DW_TAG_subprogram
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR3:[0-9a-f]+]])
CHECK: .debug_addr contents:
diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
index 324a156484119f8..0199bf28681bc4f 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
@@ -34,17 +34,31 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA
RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM -a --verbose | FileCheck %s
RUN: rm -rf %t.dir && mkdir -p %t.dir
-RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: dsymutil --no-odr --linker llvm -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \
RUN: -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \
RUN: -a --verbose | FileCheck %s
+### Uncomment following when llvm-dwarfdump will dump address ranges
+### correctly for severall compile units case.
+COM: rm -rf %t.dir && mkdir -p %t.dir
+COM: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+COM: -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \
+COM: -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
+COM: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \
+COM: -a --verbose | FileCheck %s --check-prefixes=CHECK,CHECK-LLVM
+
+
CHECK:.debug_abbrev contents:
CHECK-NEXT: Abbrev table for offset: 0x00000000
CHECK: .debug_info contents:
-CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp")
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
@@ -54,17 +68,17 @@ CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/sh
CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]]
CHECK-NEXT: [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]]))
CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
-CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
+CHECK: DW_TAG_subprogram
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]])
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000005) string = "_Z4foo2i")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000006) string = "foo2")
-CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c)
+CHECK: DW_TAG_formal_parameter
CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOCLIST_OFFSET:[0-9a-f]+]]:
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]]
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]])
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a")
-CHECK: 0x0000004e: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08
+CHECK: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = {{.*}}, addr_size = 0x08
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)")
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000e0] = "b.cpp")
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strp] ( .debug_str[0x00000039] = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
@@ -74,11 +88,11 @@ CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x000000a3] = "/Users/shub
CHECK: DW_AT_low_pc [DW_FORM_addr] (0x[[#%.16x,RANGE_LOWPC:]])
CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
CHECK-NEXT: [0x[[#%.16x,RANGE_START:]], 0x[[#%.16x,RANGE_END:]]))
-CHECK: 0x00000080: DW_TAG_subprogram {{.*}} * (0x00000059)
+CHECK: DW_TAG_subprogram
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x[[#%.16x,LOC_LOWPC:]])
CHECK: DW_AT_linkage_name [DW_FORM_strp] ( .debug_str[0x000000e6] = "_Z3bari")
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000ee] = "bar")
-CHECK: 0x0000009d: DW_TAG_formal_parameter {{.*}} (0x00000080)
+CHECK: DW_TAG_formal_parameter
CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOC_OFFSET:[0-9a-f]+]]:
CHECK-NEXT: [0x[[#%.16x,LOC_PAIR_START:]], 0x[[#%.16x,LOC_PAIR_END:]]): [[LOC_EXPR:.*]]
CHECK-NEXT: [0x[[#%.16x,LOC_PAIR_START2:]], 0x[[#%.16x,LOC_PAIR_END2:]]): [[LOC_EXPR2:.*]])
diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
index 3008db9a0d63c21..13409b2a07a31f6 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
@@ -22,21 +22,33 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA
RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s
RUN: rm -rf %t.dir && mkdir -p %t.dir
-RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s
+### Uncomment following when llvm-dwarfdump will print resolved address ranges
+### for the case mutiplue compile units.
+COM: rm -rf %t.dir && mkdir -p %t.dir
+COM: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+COM: -oso-prepend-path=%p/../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM
+COM: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s \
+COM: --check-prefixes=CHECK,CHECK-LLVM
+
+
CHECK:.debug_abbrev contents:
CHECK-NEXT: Abbrev table for offset: 0x00000000
CHECK: .debug_info contents:
-CHECK-NEXT: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]]
CHECK-NEXT: [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]]))
CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
-CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
+CHECK: DW_TAG_subprogram
CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]])
-CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c)
+CHECK: DW_TAG_formal_parameter
CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOC_OFFSET:[0-9a-f]+]]:
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]]
CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]])
diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test b/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
index ac813fc6203708d..73decc497ea36ee 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
@@ -56,21 +56,40 @@ RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --c
RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,GLOBALUPD
+RUN: rm -rf %t.dir && mkdir -p %t.dir
+RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \
+RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN: -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN: FileCheck %s --check-prefixes=CHECK,LOCAL
+
RUN: rm -rf %t.dir && mkdir -p %t.dir
RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
RUN: -o %t.dir/dwarf5-addr-base.dSYM
-RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=CHECK,LOCAL
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN: FileCheck %s --check-prefixes=CHECK,LOCAL,CHECK-LLVM
+
+RUN: dsymutil --linker llvm --no-odr --update -y %p/dummy-debug-map-amr64.map \
+RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN: -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN: FileCheck %s --check-prefixes=UPD,LOCALUPD
RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \
RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
RUN: -o %t.dir/dwarf5-addr-base.dSYM
-RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,LOCALUPD
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN: FileCheck %s --check-prefixes=UPD,LOCALUPD
+
CHECK: .debug_info contents:
-CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000004e)
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
-CHECK: 0x0000000c: DW_TAG_compile_unit [1] *
+CHECK: DW_TAG_compile_unit
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp")
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
@@ -78,24 +97,24 @@ CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) strin
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
-CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c)
+CHECK: DW_TAG_subprogram
CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000010000)
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000005) string = "_Z4foo2i")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000006) string = "foo2")
-CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c)
+CHECK: DW_TAG_formal_parameter
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a")
-CHECK: 0x00000048: NULL
+CHECK: NULL
-CHECK: 0x00000049: DW_TAG_base_type [4] (0x0000000c)
+CHECK: DW_TAG_base_type
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) string = "int")
-CHECK: 0x0000004d: NULL
+CHECK: NULL
-CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 (next unit at 0x0000009c)
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
-CHECK: 0x0000005a: DW_TAG_compile_unit [1] *
+CHECK: DW_TAG_compile_unit
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{9|1}}) string = "b.cpp")
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
@@ -103,23 +122,23 @@ CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) strin
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|34}})
CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
-CHECK: 0x0000007a: DW_TAG_subprogram [2] * (0x0000005a)
+CHECK: DW_TAG_subprogram
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000{{a|5}}) string = "_Z4bar2i")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{b|6}}) string = "bar2")
-CHECK: 0x0000008a: DW_TAG_formal_parameter [3] (0x0000007a)
+CHECK: DW_TAG_formal_parameter
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a")
-CHECK: 0x00000096: NULL
+CHECK: NULL
-CHECK: 0x00000097: DW_TAG_base_type [4] (0x0000005a)
+CHECK: DW_TAG_base_type
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) string = "int")
-CHECK: 0x0000009b: NULL
+CHECK: NULL
-CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08 (next unit at 0x000000e3)
+CHECK: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
-CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} *
+CHECK: DW_TAG_compile_unit
CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{c|1}}) string = "c.cpp")
CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
@@ -127,19 +146,19 @@ CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) strin
CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|60}})
CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485")
-CHECK: 0x000000c1: DW_TAG_subprogram [2] * (0x000000a8)
+CHECK: DW_TAG_subprogram
CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000{{d|5}}) string = "_Z3bazi")
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{e|6}}) string = "baz")
-CHECK: 0x000000d1: DW_TAG_formal_parameter [3] (0x000000c1)
+CHECK: DW_TAG_formal_parameter
CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{f|7}}) string = "x")
-CHECK: 0x000000dd: NULL
+CHECK: NULL
-CHECK: 0x000000de: DW_TAG_base_type [4] (0x000000a8)
+CHECK: DW_TAG_base_type
CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) string = "int")
-CHECK: 0x000000e2: NULL
+CHECK: NULL
CHECK: .debug_str contents:
CHECK-NEXT: 0x00000000: ""
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
new file mode 100644
index 000000000000000..a94d06f2ab64d27
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
@@ -0,0 +1,67 @@
+// RUN: dsymutil --linker llvm --no-odr -f -y %p/../dummy-debug-map.map -oso-prepend-path \
+// RUN: %p/../../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
+// RUN: FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
+//
+// RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path \
+// RUN: %p/../../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
+// RUN: FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN: --check-prefixes=CHECK-LLVM
+
+// The test was compiled with:
+// clang++ -O2 -g -c dead-strip.cpp -o 1.o
+
+// The goal of the test is to exercise dsymutil's behavior in presence of
+// functions/variables that have been dead-stripped by the linker but
+// that are still present in the linked debug info (in this case because
+// they have been DW_TAG_import'd in another namespace).
+
+// CHECK-LLVM: DW_TAG_compile_unit
+// CHECK-LLVM: DW_AT_name{{.*}}"__artificial_type_unit"
+// CHECK-LLVM: DW_TAG_namespace
+// CHECK-LLVM: DW_AT_name{{.*}}"N"
+// CHECK-LLVM: NULL
+//
+// CHECK-LLVM: DW_TAG_compile_unit
+// CHECK-LLVM: DW_AT_low_pc
+// CHECK-LLVM: DW_AT_high_pc
+// CHECK-LLVM: DW_TAG_base_type
+// CHECK-LLVM: DW_TAG_imported_module
+// CHECK-LLVM: DW_TAG_subprogram
+// CHECK-LLVM: DW_AT_low_pc
+// CHECK-LLVM: DW_AT_high_pc
+// CHECK-LLVM: DW_TAG_base_type
+// CHECK-LLVM: NULL
+
+// Everything in the N namespace below doesn't have a debug map entry, and
+// thus is considered dead (::foo() has a debug map entry, otherwise dsymutil
+// would just drop the CU altogether).
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+// CHECK: DW_TAG_namespace
+namespace N {
+int blah = 42;
+
+__attribute__((always_inline)) int foo() { return blah; }
+
+int bar(unsigned i) {
+ int val = foo();
+ if (i)
+ return val + bar(i-1);
+ return foo();
+}
+}
+// CHECK: DW_TAG_base_type
+// CHECK: DW_TAG_imported_module
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+// CHECK: DW_TAG_base_type
+// CHECK: NULL
+
+using namespace N;
+
+void foo() {}
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
new file mode 100644
index 000000000000000..b2d178cee0282cc
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
@@ -0,0 +1,5 @@
+RUN: llvm-mc %p/../../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o
+RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
+
+CHECK: .debug_info contents:
+CHECK-NOT: DW_TAG_compile_unit
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
new file mode 100644
index 000000000000000..97d7e630e7c6722
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
@@ -0,0 +1,74 @@
+// RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path \
+// RUN: %p/../../Inputs/inlined-static-variable -o - -keep-function-for-static | \
+// RUN: llvm-dwarfdump - | FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN: --check-prefixes=CHECK
+
+// clang -g -c inlined-static-variable.cpp -o 4.o
+
+// The functions removed and not_removed are not in the debug map and are
+// considered dead, but they are also inlined into the function foo which is
+// in the debug map. Those function-local globals are alive and thus should
+// have locations in the debug info even if their functions do not.
+
+inline __attribute__((always_inline)) int removed() {
+ static int a = 0;
+ return ++a;
+}
+
+__attribute__((always_inline)) int not_removed() {
+ static int b = 0;
+ return ++b;
+}
+
+int unused() {
+ static int c = 0;
+ return ++c;
+}
+
+int foo() {
+ return removed() + not_removed();
+}
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+// CHECK: DW_TAG_base_type
+// CHECK: DW_AT_name{{.*}}"int"
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_name{{.*}}"not_removed"
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_name{{.*}}"removed"
+// CHECK: NULL
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_name{{.*}}"removed"
+// CHECK-NOT: DW_AT_low_pc
+// CHECK-NOT: DW_AT_low_pc
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"a"
+// CHECK: {{.*}}DW_OP_addr
+// CHECK: NULL
+// CHECK: DW_TAG_base_type
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_name{{.*}}"not_removed"
+// CHECK-NOT: DW_AT_low_pc
+// CHECK-NOT: DW_AT_low_pc
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"b"
+// CHECK: {{.*}}DW_OP_addr
+// CHECK: NULL
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+// CHECK: DW_AT_name ("foo")
+// CHECK: DW_TAG_inlined_subroutine
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+// CHECK: DW_TAG_inlined_subroutine
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+// CHECK: NULL
+// CHECK: NULL
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
new file mode 100644
index 000000000000000..6d8757391d6c68d
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
@@ -0,0 +1,36 @@
+$ cat main.cpp
+#include <stdio.h>
+
+static void Foo(void)
+{
+ typedef struct {
+ int x1;
+ int x2;
+ } FOO_VAR_TYPE;
+ static FOO_VAR_TYPE MyDummyVar __attribute__((aligned(4), used, section("TAD_VIRTUAL, TAD_DUMMY_DATA"), nocommon));
+ printf("Foo called");
+}
+
+int main()
+{
+ Foo();
+ return 1;
+}
+
+$ clang++ -O2 -g main.cpp -c -o main.o
+$ clang++ main.o -o main.out
+
+RUN: dsymutil --linker llvm -oso-prepend-path %p/../../Inputs %p/../../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM
+RUN: dsymutil --linker llvm -oso-prepend-path %p/../../Inputs %p/../../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static
+RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
+RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
+
+KEEP: DW_AT_name ("x1")
+KEEP: DW_AT_name ("x2")
+KEEP: DW_AT_name ("FOO_VAR_TYPE")
+KEEP: DW_AT_name ("MyDummyVar")
+
+OMIT-NOT: DW_AT_name ("MyDummyVar")
+OMIT-NOT: DW_AT_name ("FOO_VAR_TYPE")
+OMIT-NOT: DW_AT_name ("x1")
+OMIT-NOT: DW_AT_name ("x2")
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
new file mode 100644
index 000000000000000..16aacd57517bd2e
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
@@ -0,0 +1,68 @@
+/* Compile with:
+ for FILE in `seq 2`; do
+ clang -g -c odr-anon-namespace.cpp -DFILE$FILE -o odr-anon-namespace/$FILE.o
+ done
+ */
+
+// RUN: dsymutil --linker llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-anon-namespace \
+// RUN: -y %p/../dummy-debug-map.map -o - | \
+// RUN: llvm-dwarfdump -debug-info - | FileCheck %s
+
+#ifdef FILE1
+// Currently dsymutil will unique the contents of anonymous
+// namespaces if they are from the same file/line. Force this
+// namespace to appear
diff erent eventhough it's the same (this
+// uniquing is actually a bug kept for backward compatibility, see the
+// comments in DeclContextTree::getChildDeclContext()).
+#line 42
+#endif
+namespace {
+class C {};
+}
+
+void foo() {
+ C c;
+}
+
+// Keep the ifdef guards for FILE1 and FILE2 even if all the code is
+// above to clearly show what the CHECK lines are testing.
+#ifdef FILE1
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-anon-namespace.cpp"
+
+// CHECK: DW_TAG_variable
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name {{.*}}"c"
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_type {{.*}}0x[[C_FILE1:[0-9a-f]*]]
+
+// CHECK: DW_TAG_namespace
+// CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}}
+// CHECK: 0x[[C_FILE1]]:{{.*}}DW_TAG_class_type
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name{{.*}}"C"
+
+#elif defined(FILE2)
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-anon-namespace.cpp"
+
+// CHECK: DW_TAG_variable
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name {{.*}}"c"
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_type {{.*}}0x[[C_FILE2:[0-9a-f]*]]
+
+// CHECK: DW_TAG_namespace
+// CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}}
+// CHECK: 0x[[C_FILE2]]:{{.*}}DW_TAG_class_type
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name{{.*}}"C"
+
+#else
+#error "You must define which file you generate"
+#endif
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
new file mode 100644
index 000000000000000..3e8d8557689e36d
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
@@ -0,0 +1,101 @@
+/* Compile with:
+ for FILE in `seq 3`; do
+ clang -g -c X86/odr-fwd-declaration.cpp -DFILE$FILE -o
+ Inputs/odr-fwd-declaration/$FILE.o done
+*/
+
+// RUN: dsymutil --linker=llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-fwd-declaration \
+// RUN: -y %p/../dummy-debug-map.map -o %t1.out
+// RUN: llvm-dwarfdump -v -debug-info %t1.out | FileCheck %s
+
+#ifdef FILE1
+# 1 "Header.h" 1
+typedef struct S *Sptr;
+typedef Sptr *Sptrptr;
+# 3 "Source1.cpp" 2
+void foo() { Sptrptr ptr1 = 0; }
+
+// First we confirm that types are in type table.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+// CHECK: DW_TAG_base_type
+
+// CHECK: 0x[[PTR_S:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[STRUCT_S:[a-f0-9]*]]} "S"
+
+// CHECK: 0x[[PTR_PTR_S:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[TYPEDEF_PTR_S:[a-f0-9]*]]} "Sptr"
+
+// CHECK: 0x[[STRUCT_S]]: DW_TAG_structure_type
+// CHECK-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: DW_AT_name{{.*}}"field"
+
+// CHECK: 0x[[TYPEDEF_PTR_S]]: DW_TAG_typedef
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[PTR_S]]} "S *"
+// CHECK-NEXT: DW_AT_name{{.*}}"Sptr"
+
+// CHECK: 0x[[TYPEDEF_PTR_PTR_S:[a-f0-9]*]]: DW_TAG_typedef
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[PTR_PTR_S]]} "Sptr *"
+// CHECK-NEXT: DW_AT_name{{.*}}"Sptrptr"
+
+// First we confirm that first compile unit properly references type.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp"
+//
+// CHECK: TAG_variable
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}} "ptr1"
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]]
+
+#elif defined(FILE2)
+# 1 "Header.h" 1
+typedef struct S *Sptr;
+typedef Sptr *Sptrptr;
+# 3 "Source2.cpp" 2
+struct S {
+ int field;
+};
+void bar() { Sptrptr ptr2 = 0; }
+
+// Next we confirm that the second compile unit properly references types.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp"
+//
+// CHECK: TAG_variable
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}} "ptr2"
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]]
+
+#elif defined(FILE3)
+# 1 "Header.h" 1
+typedef struct S *Sptr;
+typedef Sptr *Sptrptr;
+# 3 "Source1.cpp" 2
+void foo() { Sptrptr ptr1 = 0; }
+
+// Finally we confirm that third compile unit references types correctly.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp"
+//
+// CHECK: TAG_variable
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}} "ptr1"
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]]
+// CHECK-NOT: TAG_typedef
+// CHECK-NOT: TAG_pointer
+// CHECK-NOT: TAG_structure_type
+
+#else
+#error "You must define which file you generate"
+#endif
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
new file mode 100644
index 000000000000000..439b7d76bb69bf4
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
@@ -0,0 +1,131 @@
+/* Compile with:
+ for FILE in `seq 3`; do
+ clang -g -c X86/odr-fwd-declaration2.cpp -DFILE$FILE -o
+ Inputs/odr-fwd-declaration2/$FILE.o done
+*/
+
+// RUN: dsymutil --linker=llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-fwd-declaration2 \
+// RUN: -y %p/../dummy-debug-map.map -o %t1.out
+// RUN: llvm-dwarfdump -v %t1.out -debug-info | FileCheck %s
+
+#ifdef FILE1
+# 1 "Header.h" 1
+struct A {
+ struct B;
+ B *bPtr;
+ B &bRef;
+ int B::*bPtrToField;
+};
+# 3 "Source1.cpp" 2
+void foo() { A *ptr1 = 0; }
+
+// First we check that types are in type table unit.
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"__artificial_type_unit"
+
+// CHECK: 0x[[INT_BASE:[a-f0-9]*]]: DW_TAG_base_type
+// CHECK: AT_name{{.*}}"int"
+
+// CHECK: 0x[[PTR_A:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}0x[[STRUCT_A:[a-f0-9]*]]} "A")
+
+// CHECK: 0x[[PTR_B:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}0x[[STRUCT_B:[a-f0-9]*]]} "A::B")
+
+// CHECK: 0x[[REF_B:[a-f0-9]*]]: DW_TAG_reference_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}0x[[STRUCT_B]]} "A::B")
+
+// CHECK: 0x[[STRUCT_A]]: DW_TAG_structure_type
+// CHECK: AT_name{{.*}}"A"
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: AT_name{{.*}}"bPtr"
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[PTR_B]]} "A::B *")
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: AT_name{{.*}}"bRef"
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[REF_B]]} "A::B &"
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: AT_name{{.*}}"bPtrToField"
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[PTR_TO_FIELD:[a-f0-9]*]]} "int A::B::*"
+
+// CHECK: 0x[[STRUCT_B]]: DW_TAG_structure_type
+// CHECK: AT_name{{.*}}"B"
+
+// CHECK: DW_TAG_member
+// CHECK: AT_name{{.*}}"x"
+
+// CHECK: 0x[[PTR_TO_FIELD]]: DW_TAG_ptr_to_member_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[INT_BASE]]} "int"
+// CHECK-NEXT: DW_AT_containing_type [DW_FORM_ref4] {{.*}}{0x[[STRUCT_B]]} "A::B")
+
+// Next we check that second compile unit references type from type table unit.
+//
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp"
+
+// CHECK: DW_TAG_subprogram
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"ptr1"
+// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *"
+
+#elif defined(FILE2)
+# 1 "Header.h" 1
+struct A {
+ struct B;
+ B *bPtr;
+ B &bRef;
+ int B::*bPtrToField;
+};
+# 3 "Source2.cpp" 2
+struct A::B {
+ int x;
+};
+void bar() { A *ptr2 = 0; }
+
+// Next we check that thrid compile unit references type from type table unit.
+//
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp"
+
+// CHECK: DW_TAG_subprogram
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"ptr2"
+// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *"
+
+#elif defined(FILE3)
+# 1 "Header.h" 1
+struct A {
+ struct B;
+ B *bPtr;
+ B &bRef;
+ int B::*bPtrToField;
+};
+# 3 "Source2.cpp" 2
+struct A::B {
+ int x;
+};
+void bar() { A *ptr2 = 0; }
+
+// Next we check that fourth compile unit references type from type table unit.
+//
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp"
+
+// CHECK: DW_TAG_subprogram
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"ptr2"
+// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *"
+
+#else
+#error "You must define which file you generate"
+#endif
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
new file mode 100644
index 000000000000000..9758e4ad4213033
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
@@ -0,0 +1,381 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks debug info for the case when one compilation unit
+## contains forward declaration of the type and another compilation unit
+## contains definition for that type. The result should have type table
+## containing definition for that type and corresponding variables should
+## properly reference that type.
+
+## CU1:
+##
+## class class1;
+## template<int> class class2;
+##
+## class1 *var1;
+## class2<int> *var2;
+##
+## CU2:
+##
+## class class1 {
+## char member1;
+## float member2;
+## };
+##
+## template<int> class class2 {
+## char member1;
+## };
+##
+## class1 *var1;
+## class2<int> *var2;
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"char"
+
+# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"float"
+
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[CHAR]] "char"
+# CHECK: DW_AT_name{{.*}}"member1"
+
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[FLOAT]] "float"
+# CHECK: DW_AT_name{{.*}}"member2"
+
+# CHECK: 0x[[CLASS2:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class2"
+# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[CHAR]] "char"
+# CHECK: DW_AT_name{{.*}}"member1"
+
+# CHECK: 0x[[PTR_CLASS1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CLASS1]] "class1"
+
+# CHECK: 0x[[PTR_CLASS2:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CLASS2]] "class2<int>"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS1]] "class1 *"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS2]] "class2<int> *"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS1]] "class1 *"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS2]] "class2<int> *"
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x9c
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0xed
+ offset: 0x0000041c
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x000001FC
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: false
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 1
+ stroff: 0x710
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_template_type_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_template_type_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - AbbrCode: 4
+ Values:
+ - CStr: class1
+ - AbbrCode: 5
+ Values:
+ - CStr: class2
+ - AbbrCode: 6
+ Values:
+ - Value: 0x00000030
+ - AbbrCode: 0
+ - AbbrCode: 7
+ Values:
+ - CStr: int
+ - AbbrCode: 8
+ Values:
+ - Value: 0x0000001a
+ - AbbrCode: 8
+ Values:
+ - Value: 0x00000022
+ - AbbrCode: 9
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x00000035
+ - AbbrCode: 9
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x0000003a
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU2
+ - AbbrCode: 2
+ Values:
+ - CStr: class1
+ - AbbrCode: 3
+ Values:
+ - Value: 0x000000b9
+ - CStr: member1
+ - AbbrCode: 3
+ Values:
+ - Value: 0x000000bf
+ - CStr: member2
+ - AbbrCode: 0
+ - AbbrCode: 2
+ Values:
+ - CStr: class2
+ - AbbrCode: 6
+ Values:
+ - Value: 0x000000b4
+ - AbbrCode: 3
+ Values:
+ - Value: 0x000000b9
+ - CStr: member1
+ - AbbrCode: 0
+ - AbbrCode: 7
+ Values:
+ - CStr: int
+ - AbbrCode: 7
+ Values:
+ - CStr: char
+ - AbbrCode: 7
+ Values:
+ - CStr: float
+ - AbbrCode: 8
+ Values:
+ - Value: 0x00000076
+ - AbbrCode: 8
+ Values:
+ - Value: 0x00000099
+ - AbbrCode: 9
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x000000c6
+ - AbbrCode: 9
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x000000cb
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
new file mode 100644
index 000000000000000..7135c46630e13a9
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
@@ -0,0 +1,192 @@
+/* Compile with:
+ for FILE in `seq 3`; do
+ clang -g -c odr-member-functions.cpp -DFILE$FILE -o
+ odr-member-functions/$FILE.o done
+ */
+
+// RUN: dsymutil --linker=llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-member-functions \
+// RUN: -y %p/../dummy-debug-map.map -o %t1.out
+// RUN: llvm-dwarfdump -debug-info %t1.out | FileCheck %s
+
+struct S {
+ __attribute__((always_inline)) void foo() { bar(); }
+ __attribute__((always_inline)) void foo(int i) {
+ if (i)
+ bar();
+ }
+ void bar();
+
+ template <typename T> void baz(T t) {}
+};
+
+#ifdef FILE1
+void foo() { S s; }
+
+// First chack that types are moved into the type table unit.
+
+// CHECK: TAG_compile_unit
+// CHECK: AT_name{{.*}}"__artificial_type_unit"
+
+// CHECK: 0x[[INT_BASE:[0-9a-f]*]]: DW_TAG_base_type
+// CHECK-NEXT: DW_AT_name{{.*}}"int"
+
+// CHECK: 0x[[PTR_S:[0-9a-f]*]]:{{.*}}DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[STRUCT_S:[0-9a-f]*]] "S")
+
+// CHECK: 0x[[STRUCT_S]]:{{.*}}DW_TAG_structure_type
+// CHECK-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3barEv"
+// CHECK: DW_AT_name{{.*}}"bar"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// CHECK: 0x[[BAZ_SUBPROGRAM:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3bazIiEEvT_"
+// CHECK: DW_AT_name{{.*}}"baz<int>"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int"
+
+// CHECK: DW_TAG_template_type_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int"
+// CHECK-NEXT: DW_AT_name{{.*}}"T"
+
+// CHECK: 0x[[FOO_Ei:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEi"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int"
+
+// CHECK: 0x[[FOO_Ev:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEv"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// For the second unit check that it references structure "S"
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}}"odr-member-functions.cpp"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK-NEXT: AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"s"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S"
+
+#elif defined(FILE2)
+void foo() {
+ S s;
+ // Check that the overloaded member functions are resolved correctly
+ s.foo();
+ s.foo(1);
+}
+
+// For the third unit check that it references member functions of structure S.
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-member-functions.cpp"
+
+// CHECK: 0x[[ABASE_FOO_Ev:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK-NEXT: DW_AT_specification {{.*}}(0x00000000[[FOO_Ev]] "_ZN1S3fooEv"
+// CHECK-NEXT: DW_AT_inline (DW_INL_inlined)
+// CHECK-NEXT: DW_AT_object_pointer {{.*}}(0x[[ABASE_FOO_Ev_PARAM1:[0-9a-f]*]]
+
+// CHECK: 0x[[ABASE_FOO_Ev_PARAM1]]:{{.*}}DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_name{{.*}}"this"
+// CHECK-NEXT: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *"
+
+// CHECK: 0x[[ABASE_FOO_Ei:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK-NEXT: DW_AT_specification {{.*}}(0x00000000[[FOO_Ei]] "_ZN1S3fooEi"
+// CHECK-NEXT: DW_AT_inline (DW_INL_inlined)
+// CHECK-NEXT: DW_AT_object_pointer {{.*}}(0x[[ABASE_FOO_Ei_PARAM1:[0-9a-f]*]]
+
+// CHECK: 0x[[ABASE_FOO_Ei_PARAM1]]:{{.*}}DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_name{{.*}}"this"
+// CHECK-NEXT: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *"
+
+// CHECK: 0x[[ABASE_FOO_Ei_PARAM2:[0-9a-f]*]]:{{.*}}DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_name{{.*}}"i"
+// CHECK: DW_AT_type (0x00000000[[INT_BASE]] "int"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"s"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S"
+
+// CHECK: DW_TAG_inlined_subroutine
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ev]] "_ZN1S3fooEv"
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ev_PARAM1]] "this"
+
+// CHECK: DW_TAG_inlined_subroutine
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei]] "_ZN1S3fooEi"
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei_PARAM1]] "this"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei_PARAM2]] "i"
+
+#elif defined(FILE3)
+void foo() {
+ S s;
+ s.baz<int>(42);
+}
+
+// For the fourth unit check that it references member functions of structure S.
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-member-functions.cpp"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"s"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_object_pointer{{.*}}(0x[[INST_PARAM2:[0-9a-f]*]]
+// CHECK: DW_AT_specification{{.*}}(0x00000000[[BAZ_SUBPROGRAM]] "_ZN1S3bazIiEEvT_"
+
+// CHECK: 0x[[INST_PARAM2]]:{{.*}}DW_TAG_formal_parameter
+// CHECK: DW_AT_name{{.*}}"this"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_name{{.*}}"t"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[INT_BASE]] "int"
+
+// CHECK: DW_TAG_template_type_parameter
+// CHECK: DW_AT_type{{.*}}(0x00000000[[INT_BASE]] "int"
+// CHECK: DW_AT_name{{.*}}"T"
+
+#else
+#error "You must define which file you generate"
+#endif
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
new file mode 100644
index 000000000000000..6c31b48978e9828
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
@@ -0,0 +1,157 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks that DW_TAG_namespace with DW_AT_extension
+## attribute is joined with referenced namespace.
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: 0x0000000b: DW_TAG_compile_unit
+# CHECK: DW_TAG_namespace
+# CHECK: DW_AT_name{{.*}}"parent_namespace"
+# CHECK-NOT: DW_TAG_namespace
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_type (0x00000000[[INT]]
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x2A
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0x42
+ offset: 0x000003AA
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x000001FC
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: false
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 1
+ stroff: 0x710
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_extension
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - AbbrCode: 2
+ Values:
+ - CStr: parent_namespace
+ - AbbrCode: 3
+ Values:
+ - Value: 0x00000016
+ - AbbrCode: 4
+ Values:
+ - CStr: int
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 5
+ Values:
+ - CStr: var
+ - Value: 0x000000FF
+ - Value: 0x0000002d
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
new file mode 100644
index 000000000000000..22a142ab97657c6
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
@@ -0,0 +1,384 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks that nested structure containing field of anonymuos type
+## partially moved into the type table. Anonymous part of the structure should be
+## left in the original containg compile unit:
+##
+## CU1:
+##
+## struct s1 { struct s2; }
+##
+## namespace {
+## struct s3 {};
+## }
+##
+## struct s1::s2 { s3 m; };
+##
+## struct s1::s2 *var1;
+## struct s1::s2::s3 *var2;
+##
+## CU2:
+##
+## struct s1 { struct s2; }
+##
+## struct s1::s2 *var3;
+##
+##
+## Final type table should contain:
+##
+## DW_TAG_compile_unit
+## DW_AT_name ("__type_table")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s1")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s2")
+## DW_AT_declaration (true)
+##
+## CU1 should contain:
+##
+## DW_TAG_compile_unit
+## DW_AT_name ("CU1")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s1")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s2")
+##
+## DW_TAG_member
+## DW_AT_name ("m")
+## DW_AT_type ("(anonymous namespace)::s3")
+##
+## DW_TAG_namespace
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s3")
+##
+## DW_TAG_variable
+## DW_AT_name ("var1")
+## DW_AT_type ("s1::s2 *")
+##
+## DW_TAG_variable
+## DW_AT_name ("var2")
+## DW_AT_type ("s1::s2::m *")
+##
+## CU2 should contain:
+##
+## DW_TAG_compile_unit
+## DW_AT_name ("CU2")
+##
+## DW_TAG_variable
+## DW_AT_name ("var3")
+## DW_AT_type ("s1::s2 *")
+##
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2")
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s1"
+
+# CHECK: 0x[[INNER_STRUCT:[0-9a-f]*]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s2"
+# CHECK: DW_AT_declaration{{.*}}true
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s1"
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s2"
+
+# CHECK: 0x[[INNER_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"m"
+# CHECK: DW_AT_type{{.*}}0x[[ANON_STRUCT:[0-9a-f]*]] "(anonymous namespace)::s3"
+
+# CHECK: DW_TAG_namespace
+# CHECK: 0x[[ANON_STRUCT]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s3"
+
+# CHECK: 0x[[ANON_PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2")
+
+# CHECK: 0x[[PTR_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT_MEMBER]] "m"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x[[ANON_PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x[[PTR_STRUCT_MEMBER]] "m *"
+
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var3"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var4"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x76
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0xa7
+ offset: 0x000003f6
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x0
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: true
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 2
+ stroff: 0x720
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - AbbrCode: 2
+ Values:
+ - CStr: s1
+ - AbbrCode: 2
+ Values:
+ - CStr: s2
+ - AbbrCode: 4
+ Values:
+ - CStr: m
+ - Value: 0x0000002c
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 7
+ - AbbrCode: 3
+ Values:
+ - CStr: s3
+ - AbbrCode: 0
+ - AbbrCode: 5
+ Values:
+ - CStr: int
+ - AbbrCode: 6
+ Values:
+ - Value: 0x0000001e
+ - AbbrCode: 6
+ Values:
+ - Value: 0x00000022
+ - AbbrCode: 8
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x00000036
+ - AbbrCode: 8
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x0000003b
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU2
+ - AbbrCode: 2
+ Values:
+ - CStr: s1
+ - AbbrCode: 3
+ Values:
+ - CStr: s2
+ - AbbrCode: 0
+ - AbbrCode: 4
+ Values:
+ - CStr: int
+ - AbbrCode: 5
+ Values:
+ - Value: 0x0000007b
+ - AbbrCode: 6
+ Values:
+ - CStr: var3
+ - Value: 0x00000000
+ - Value: 0x00000085
+ - AbbrCode: 6
+ Values:
+ - CStr: var4
+ - Value: 0x00000000
+ - Value: 0x00000085
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
new file mode 100644
index 000000000000000..35d3261e591cb3b
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
@@ -0,0 +1,374 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks that nested structure containing field of type from other namespace
+## fully moved into the type table.
+##
+## CU1:
+##
+## struct s1 { struct s2; }
+##
+## namespace namespace1 {
+## struct s3 {};
+## }
+##
+## struct s1::s2 { s3 m; };
+##
+## struct s1::s2 *var1;
+## struct s1::s2::s3 *var2;
+##
+## CU2:
+##
+## struct s1 { struct s2; }
+##
+## struct s1::s2 *var3;
+##
+##
+## Final type table should contain:
+##
+## DW_TAG_compile_unit
+## DW_AT_name ("__type_table")
+##
+## DW_TAG_namespace
+## DW_AT_name ("namespace1")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s3")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s1")
+##
+## DW_TAG_structure_type
+## DW_AT_name ("s2")
+##
+## DW_TAG_member
+## DW_AT_name ("m")
+## DW_AT_type ("namespace1::s3")
+##
+## CU1 should contain:
+##
+## DW_TAG_compile_unit
+## DW_AT_name ("CU1")
+##
+## DW_TAG_variable
+## DW_AT_name ("var1")
+## DW_AT_type ("s1::s2 *")
+##
+## DW_TAG_variable
+## DW_AT_name ("var2")
+## DW_AT_type ("s1::s2::m *")
+##
+## CU2 should contain:
+##
+## DW_TAG_compile_unit
+## DW_AT_name ("CU2")
+##
+## DW_TAG_variable
+## DW_AT_name ("var1")
+## DW_AT_type ("s1::s2 *")
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: DW_TAG_namespace
+# CHECK: DW_AT_name{{.*}}"namespace1"
+# CHECK: 0x[[NAMESPACE_STRUCT:[0-9a-f]*]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s3"
+
+# CHECK: 0x[[PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2")
+
+# CHECK: 0x[[PTR_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT_MEMBER:[0-9a-f]*]] "m"
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s1"
+
+# CHECK: 0x[[INNER_STRUCT]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s2"
+# CHECK-NOT: DW_AT_declaration
+
+# CHECK: 0x[[INNER_STRUCT_MEMBER]]: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"m"
+# CHECK: DW_AT_type{{.*}}0x[[NAMESPACE_STRUCT]] "namespace1::s3"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_STRUCT_MEMBER]] "m *"
+
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var3"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var4"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x78
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0xb2
+ offset: 0x000003F8
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x0
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: true
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 2
+ stroff: 0x720
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - AbbrCode: 2
+ Values:
+ - CStr: s1
+ - AbbrCode: 2
+ Values:
+ - CStr: s2
+ - AbbrCode: 4
+ Values:
+ - CStr: m
+ - Value: 0x00000037
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 7
+ Values:
+ - CStr: namespace1
+ - AbbrCode: 3
+ Values:
+ - CStr: s3
+ - AbbrCode: 0
+ - AbbrCode: 5
+ Values:
+ - CStr: int
+ - AbbrCode: 6
+ Values:
+ - Value: 0x0000001e
+ - AbbrCode: 6
+ Values:
+ - Value: 0x00000022
+ - AbbrCode: 8
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x00000041
+ - AbbrCode: 8
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x00000046
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU2
+ - AbbrCode: 2
+ Values:
+ - CStr: s1
+ - AbbrCode: 3
+ Values:
+ - CStr: s2
+ - AbbrCode: 0
+ - AbbrCode: 4
+ Values:
+ - CStr: int
+ - AbbrCode: 5
+ Values:
+ - Value: 0x00000086
+ - AbbrCode: 6
+ Values:
+ - CStr: var3
+ - Value: 0x00000000
+ - Value: 0x00000090
+ - AbbrCode: 6
+ Values:
+ - CStr: var4
+ - Value: 0x00000000
+ - Value: 0x00000090
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
new file mode 100644
index 000000000000000..7c1c0d1b52e0eec
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
@@ -0,0 +1,238 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+## This test checks debug info for the equally named structures from
+##
diff erent namespaces. The result should contain two variables which
+## reference
diff erent types("A::C1::I1 *const" and "B::C1::I1 *const")
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK: DW_TAG_namespace{{.*[[:space:]].*}}DW_AT_name{{.*}}"A"
+
+# CHECK: 0x[[A_C1:[0-9a-f]*]]: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"C1"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[INT]] "int"
+# CHECK: DW_AT_name{{.*}}"I1"
+
+# CHECK: DW_TAG_namespace{{.*[[:space:]].*}}DW_AT_name{{.*}}"B"
+
+# CHECK: 0x[[B_C1:[0-9a-f]*]]: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"C1"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[INT]] "int"
+# CHECK: DW_AT_name{{.*}}"I1"
+
+# CHECK: 0x[[PTR_A_C1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[A_C1:[0-9a-f]*]] "A::C1"
+
+# CHECK: 0x[[PTR_B_C1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[B_C1:[0-9a-f]*]] "B::C1"
+
+# CHECK: 0x[[CONST_A_C1:[0-9a-f]*]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[PTR_A_C1]] "A::C1 *"
+
+# CHECK: 0x[[CONST_B_C1:[0-9a-f]*]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[PTR_B_C1]] "B::C1 *"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONST_A_C1]] "A::C1 *const"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONST_B_C1]] "B::C1 *const"
+
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x41
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0x6e
+ offset: 0x000003C1
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x000001FC
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: false
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 1
+ stroff: 0x710
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Tag: DW_TAG_namespace
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_structure_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_const_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - AbbrCode: 2
+ Values:
+ - CStr: A
+ - AbbrCode: 3
+ Values:
+ - CStr: C1
+ - AbbrCode: 4
+ Values:
+ - Value: 0x00000038
+ - CStr: I1
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 2
+ Values:
+ - CStr: B
+ - AbbrCode: 3
+ Values:
+ - CStr: C1
+ - AbbrCode: 4
+ Values:
+ - Value: 0x00000038
+ - CStr: I1
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 5
+ Values:
+ - CStr: int
+ - AbbrCode: 6
+ Values:
+ - Value: 0x00000019
+ - AbbrCode: 6
+ Values:
+ - Value: 0x0000002a
+ - AbbrCode: 7
+ Values:
+ - Value: 0x0000003D
+ - AbbrCode: 7
+ Values:
+ - Value: 0x00000042
+ - AbbrCode: 8
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x00000047
+ - AbbrCode: 8
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x0000004C
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
new file mode 100644
index 000000000000000..187a2ea9ecffdcd
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
@@ -0,0 +1,117 @@
+# RUN: dsymutil --linker=llvm -f -o %t1.o -oso-prepend-path=%p/ -y %s
+# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 1 | llvm-dwarfdump -a - -o %t1
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 3 | llvm-dwarfdump -a - -o %t2
+# RUN:
diff %t1 %t2
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 4 | llvm-dwarfdump -a - -o %t3
+# RUN:
diff %t1 %t3
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s | llvm-dwarfdump -a - -o %t4
+# RUN:
diff %t1 %t4
+
+# This test checks that generated output does not
diff er between runs.
+#
+# To recreate a test compile following example:
+#
+# main.cpp:
+#
+# include <string>
+#
+# void PrintSize ( const std::string& String );
+# void PrintNewString ( const std::string& String );
+# void PrintNewString2 ( const char* String );
+#
+# int main ( void ) {
+#
+# PrintSize("hello");
+# PrintNewString("hello");
+# PrintNewString2("hello");
+# printf("\n");
+#
+# return 0;
+# }
+#
+# foo1.cpp:
+#
+# #include <string>
+#
+# void PrintSize ( const std::string& String ) {
+# printf("\n String size %lu", String.size() );
+# };
+#
+# foo2.cpp:
+#
+# #include <string>
+#
+# void PrintNewString ( const std::string& String ) {
+# std::string NewString(String);
+# NewString += "++";
+# printf("\n String %s", NewString.c_str());
+#};
+#
+# foo3.cpp:
+# #include <string>
+#
+# void PrintNewString2 ( const char* String ) {
+# std::string NewString(String);
+# NewString += "++";
+# printf("\n String2 %s", NewString.c_str());
+# };
+#
+# with clang++ -O -fno-inline -g -std=c++11
+
+---
+triple: 'x86_64-apple-darwin'
+objects:
+ - filename: 'Inputs/String/foo1.o'
+ timestamp: 1638904719
+ symbols:
+ - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 }
+ - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 }
+ - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 }
+ - filename: 'Inputs/String/foo2.o'
+ timestamp: 1638904723
+ symbols:
+ - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 }
+ - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 }
+ - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 }
+ - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 }
+ - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 }
+ - filename: 'Inputs/String/foo3.o'
+ timestamp: 1638904727
+ symbols:
+ - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D50, size: 0x00000040 }
+ - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 }
+ - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D40, size: 0x00000010 }
+ - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 }
+ - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 }
+ - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 }
+ - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 }
+ - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 }
+ - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 }
+ - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 }
+ - filename: 'Inputs/String/main.o'
+ timestamp: 1638904734
+ symbols:
+ - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 }
+ - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 }
+...
+
+VERIFY: Verifying .debug_abbrev...
+VERIFY: Verifying .debug_info Unit Header Chain...
+VERIFY: Verifying .apple_names...
+VERIFY: Verifying .apple_types...
+VERIFY: Verifying .apple_namespaces...
+VERIFY: Verifying .apple_objc...
+VERIFY: No errors.
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
new file mode 100644
index 000000000000000..93925c61c46b8b4
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
@@ -0,0 +1,120 @@
+# RUN: dsymutil --linker=llvm -f -o %t1.o -oso-prepend-path=%p/../ -y %s
+# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --linker=llvm -f -o %t2.o -oso-prepend-path=%p/../ -y %s
+# RUN: dsymutil --linker=llvm -f -o %t3.o -oso-prepend-path=%p/../ -y %s \
+# RUN: --num-threads 1
+# RUN: dsymutil --linker=llvm -f -o %t4.o -oso-prepend-path=%p/../ -y %s \
+# RUN: --num-threads 3
+# ### Following comparision will fail if files do not match
+# RUN:
diff %t1.o %t2.o
+# RUN:
diff %t1.o %t3.o
+# RUN:
diff %t1.o %t4.o
+
+# This test checks that generated output does not
diff er between runs.
+#
+# To recreate a test compile following example:
+#
+# main.cpp:
+#
+# include <string>
+#
+# void PrintSize ( const std::string& String );
+# void PrintNewString ( const std::string& String );
+# void PrintNewString2 ( const char* String );
+#
+# int main ( void ) {
+#
+# PrintSize("hello");
+# PrintNewString("hello");
+# PrintNewString2("hello");
+# printf("\n");
+#
+# return 0;
+# }
+#
+# foo1.cpp:
+#
+# #include <string>
+#
+# void PrintSize ( const std::string& String ) {
+# printf("\n String size %lu", String.size() );
+# };
+#
+# foo2.cpp:
+#
+# #include <string>
+#
+# void PrintNewString ( const std::string& String ) {
+# std::string NewString(String);
+# NewString += "++";
+# printf("\n String %s", NewString.c_str());
+#};
+#
+# foo3.cpp:
+# #include <string>
+#
+# void PrintNewString2 ( const char* String ) {
+# std::string NewString(String);
+# NewString += "++";
+# printf("\n String2 %s", NewString.c_str());
+# };
+#
+# with clang++ -O -fno-inline -g -std=c++11
+
+---
+triple: 'x86_64-apple-darwin'
+objects:
+ - filename: 'Inputs/String/foo1.o'
+ timestamp: 1638904719
+ symbols:
+ - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 }
+ - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 }
+ - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 }
+ - filename: 'Inputs/String/foo2.o'
+ timestamp: 1638904723
+ symbols:
+ - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 }
+ - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 }
+ - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 }
+ - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 }
+ - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 }
+ - filename: 'Inputs/String/foo3.o'
+ timestamp: 1638904727
+ symbols:
+ - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D40, size: 0x00000040 }
+ - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 }
+ - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D50, size: 0x00000010 }
+ - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 }
+ - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 }
+ - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 }
+ - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 }
+ - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 }
+ - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 }
+ - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 }
+ - filename: 'Inputs/String/main.o'
+ timestamp: 1638904734
+ symbols:
+ - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 }
+ - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 }
+...
+
+VERIFY: Verifying .debug_abbrev...
+VERIFY: Verifying .debug_info Unit Header Chain...
+VERIFY: Verifying .debug_types Unit Header Chain...
+VERIFY: Verifying .apple_names...
+VERIFY: Verifying .apple_types...
+VERIFY: Verifying .apple_namespaces...
+VERIFY: Verifying .apple_objc...
+VERIFY: No errors.
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
new file mode 100644
index 000000000000000..619bc8c15b8229c
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
@@ -0,0 +1,245 @@
+## This test checks output of dsymutil for the incorrect DWARF.
+## CU1 has a type which references type in CU2. This referenced
+## type references the same type in CU1 back. There is a recursive
+## dependence between these two types. dsymutil should report a error,
+## remove CU1 and CU2, put only CU3 into the output.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker llvm -y %t2.map --num-threads 1 -f -o %t1.out 2>&1 \
+# RUN: | FileCheck --check-prefix ERROR %s
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+# ERROR: error: Cann't parse input DWARF. Recursive dependence.
+# ERROR: while processing CU1
+# ERROR: error: Cann't resolve DIE reference
+# ERROR: while processing CU2
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1"
+
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK-NOT: "CU1"
+# CHECK-NOT: "CU2"
+# CHECK: DW_AT_name{{.*}}"CU3"
+# CHECK-NOT: DW_TAG_class_type
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var3"
+# CHECK: DW_AT_const_value
+# CHECK: DW_AT_type (0x00000000[[CLASS1]]
+
+# CHECK-NOT: Compile Unit:
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x5a
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0x8d
+ offset: 0x00000410
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x1FC
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: true
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 2
+ stroff: 0x720
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - AbbrCode: 2
+ Values:
+ - Value: 0x48
+ - AbbrCode: 3
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x0000001a
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU2
+ - AbbrCode: 2
+ Values:
+ - Value: 0x1a
+ - AbbrCode: 3
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x0000001a
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU3
+ - AbbrCode: 2
+ Values:
+ - CStr: class1
+ - AbbrCode: 3
+ Values:
+ - CStr: var3
+ - Value: 0x00000000
+ - Value: 0x0000001a
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
new file mode 100644
index 000000000000000..a8fc3e82311ca50
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
@@ -0,0 +1,180 @@
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/../ -y %s | llvm-dwarfdump --verify - | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/../ -y %s | llvm-dwarfdump -a - | FileCheck %s
+
+# This test checks that types from several object files are
+# uniqued(moved into the artificial compile unit for types).
+# It also checks that information between
diff erent debug
+# tables is consistent.
+#
+# To recreate a test compile following example:
+#
+# main.cpp:
+#
+# include <string>
+#
+# void PrintSize ( const std::string& String );
+# void PrintNewString ( const std::string& String );
+# void PrintNewString2 ( const char* String );
+#
+# int main ( void ) {
+#
+# PrintSize("hello");
+# PrintNewString("hello");
+# PrintNewString2("hello");
+# printf("\n");
+#
+# return 0;
+# }
+#
+# foo1.cpp:
+#
+# #include <string>
+#
+# void PrintSize ( const std::string& String ) {
+# printf("\n String size %lu", String.size() );
+# };
+#
+# foo2.cpp:
+#
+# #include <string>
+#
+# void PrintNewString ( const std::string& String ) {
+# std::string NewString(String);
+# NewString += "++";
+# printf("\n String %s", NewString.c_str());
+#};
+#
+# foo3.cpp:
+# #include <string>
+#
+# void PrintNewString2 ( const char* String ) {
+# std::string NewString(String);
+# NewString += "++";
+# printf("\n String2 %s", NewString.c_str());
+# };
+#
+# with clang++ -O -fno-inline -g -std=c++11
+
+---
+triple: 'x86_64-apple-darwin'
+objects:
+ - filename: 'Inputs/String/foo1.o'
+ timestamp: 1638904719
+ symbols:
+ - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 }
+ - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 }
+ - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 }
+ - filename: 'Inputs/String/foo2.o'
+ timestamp: 1638904723
+ symbols:
+ - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 }
+ - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 }
+ - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 }
+ - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 }
+ - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 }
+ - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 }
+ - filename: 'Inputs/String/foo3.o'
+ timestamp: 1638904727
+ symbols:
+ - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D40, size: 0x00000040 }
+ - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 }
+ - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D50, size: 0x00000010 }
+ - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 }
+ - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 }
+ - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 }
+ - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 }
+ - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 }
+ - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 }
+ - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 }
+ - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 }
+ - filename: 'Inputs/String/main.o'
+ timestamp: 1638904734
+ symbols:
+ - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 }
+ - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 }
+...
+
+VERIFY: Verifying .debug_abbrev...
+VERIFY: Verifying .debug_info Unit Header Chain...
+VERIFY: Verifying .debug_types Unit Header Chain...
+VERIFY: Verifying .apple_names...
+VERIFY: Verifying .apple_types...
+VERIFY: Verifying .apple_namespaces...
+VERIFY: Verifying .apple_objc...
+VERIFY: No errors.
+
+CHECK: .debug_info contents:
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+CHECK:DW_TAG_base_type
+
+CHECK: 0x[[BASE_INT:[0-9a-f]*]]: DW_TAG_base_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"int"
+
+CHECK:DW_TAG_class_type
+
+CHECK: 0x[[BASIC_STRING:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_calling_convention{{.*}}{{.*[[:space:]].*}}DW_AT_name{{.*}}"basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"
+
+CHECK:DW_TAG_typedef
+
+CHECK: 0x[[STRING:[0-9a-f]*]]: DW_TAG_typedef{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[BASIC_STRING]] "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"){{.*[[:space:]].*}}DW_AT_name{{.*}}"string"
+
+CHECK:DW_TAG_reference_type
+
+CHECK: 0x[[CONST_STR_REF:[0-9a-f]*]]: DW_TAG_reference_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CONST_STRING:[0-9a-f]*]] "const string"
+
+CHECK:DW_TAG_const_type
+
+CHECK: 0x[[CONST_STRING]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[STRING]] "string"
+
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"foo1.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"PrintSize"
+CHECK: DW_TAG_formal_parameter
+CHECK: DW_AT_name{{.*}}"String"
+CHECK: DW_AT_type{{.*}}0x00000000[[CONST_STR_REF]] "const string &"
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"foo2.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"PrintNewString"
+CHECK: DW_TAG_formal_parameter
+CHECK: DW_AT_name{{.*}}"String"
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"foo3.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"PrintNewString2"
+CHECK: DW_TAG_formal_parameter
+CHECK: DW_AT_name{{.*}}"String"
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"main.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"main"
+CHECK: DW_AT_type{{.*}}0x00000000[[BASE_INT]] "int"
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
new file mode 100644
index 000000000000000..67b5616ebd5922e
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
@@ -0,0 +1,201 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+## This test checks debug info for the template parameters of the class.
+## (i.e. number of the parameters is correct, names of the parameters
+## are correct, types of the parameters are correct)
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: 0x0000000b: DW_TAG_compile_unit
+# CHECK: DW_AT_producer{{.*}}"llvm DWARFLinkerParallel library version
+# CHECK: DW_AT_language{{.*}}DW_LANG_C_plus_plus
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"char"
+# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"float"
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+# CHECK: 0x[[CLASS:[0-9a-f]*]]: DW_TAG_class_type
+# CHECK: DW_AT_name{{.*}}"parametrized-class"
+# CHECK: DW_TAG_template_type_parameter
+# CHECK: DW_AT_type{{.*}}(0x[[INT]] "int"
+# CHECK: DW_AT_name{{.*}}"Type1"
+# CHECK: DW_AT_type{{.*}}(0x[[CHAR]] "char"
+# CHECK: DW_AT_name{{.*}}"Type2"
+# CHECK: DW_AT_type{{.*}}(0x[[FLOAT]] "float"
+# CHECK: DW_AT_name{{.*}}"Type3"
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_type (0x00000000[[CLASS]]
+
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x37
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0x7B
+ offset: 0x000003B7
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x000001FC
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: false
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 1
+ stroff: 0x710
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_template_type_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_template_value_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - AbbrCode: 2
+ Values:
+ - CStr: parametrized-class
+ - AbbrCode: 3
+ Values:
+ - Value: 0x0000005B
+ - CStr: Type1
+ - AbbrCode: 3
+ Values:
+ - Value: 0x00000060
+ - CStr: Type2
+ - AbbrCode: 4
+ Values:
+ - Value: 0x0000005B
+ - CStr: Type1
+ - Value: 0x0FE
+ - AbbrCode: 3
+ Values:
+ - Value: 0x00000066
+ - CStr: Type3
+ - AbbrCode: 0
+ - AbbrCode: 5
+ Values:
+ - CStr: int
+ - AbbrCode: 5
+ Values:
+ - CStr: char
+ - AbbrCode: 5
+ Values:
+ - CStr: float
+ - AbbrCode: 6
+ Values:
+ - CStr: var
+ - Value: 0x000000FF
+ - Value: 0x00000016
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
new file mode 100644
index 000000000000000..5bc034b54df8300
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
@@ -0,0 +1,205 @@
+## This test checks debug info for the types located into the
+##
diff erent compilation units from the single object file.
+## Type definition for the "class1" should be moved to the
+## artificial type unit from the first and second compilation unit.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1"
+
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+# CHECK-NOT: DW_TAG_class_type
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_const_value
+# CHECK: DW_AT_type (0x00000000[[CLASS1]]
+
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+# CHECK-NOT: DW_TAG_class_type
+# CHECK-NOT: "class1"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_const_value
+# CHECK: DW_AT_type (0x00000000[[CLASS1]]
+
+
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x3c
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0x62
+ offset: 0x00000410
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x1FC
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: true
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 2
+ stroff: 0x720
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - AbbrCode: 2
+ Values:
+ - CStr: class1
+ - AbbrCode: 3
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x0000001a
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU2
+ - AbbrCode: 2
+ Values:
+ - CStr: class1
+ - AbbrCode: 3
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x0000001a
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
new file mode 100644
index 000000000000000..1af38080c705fb7
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
@@ -0,0 +1,431 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:' >> %t2.map
+# RUN: echo " - filename: '%t.o'" >> %t2.map
+# RUN: echo ' symbols:' >> %t2.map
+# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+## This test checks debug info for the types located into the subprograms.
+## Subprogram "float foo(int)" contains type "clas1". First compile unit
+## contains partially defined class "Container" which has parametrized
+## subprogram "ParametrizedFunc" which template parameter is the type
+## "clas1" defined in the subprogram "foo". The second compilation unit
+## contains partially defined class "Container" which has parametrized
+## subprogram "ParametrizedFunc" which template parameter is the type
+## "int". The type table in the final debug info should contain class
+## "Container" which has two "ParametrizedFunc"(one has template parameter
+## "clas1" and another has template parameter "int").
+
+## class Container {
+## template<T> void ParametrizedFunc ();
+## };
+##
+## CU1:
+##
+## int foo (float) {
+## class clas1 {
+## char first;
+## float second;
+## } clas1;
+## };
+##
+## class Container {
+## template<foo:clas1> void ParametrizedFunc ();
+## };
+##
+## CU2:
+##
+## class Container {
+## template<int> void ParametrizedFunc ();
+## };
+##
+##
+## The final type table :
+##
+## class Container {
+## template<int> void ParametrizedFunc ();
+## };
+##
+## CU1:
+##
+## int foo (float) {
+## class clas1 {
+## char first;
+## float second;
+## } clas1;
+## };
+##
+## class Container {
+## template<foo:clas1> void ParametrizedFunc ();
+## };
+##
+##
+
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"char"
+
+# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"float"
+
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK: 0x[[CONTAINER:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"Container"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"ParametrizedFunc"
+# CHECK: DW_AT_type{{.*}}[[INT]] "int"
+# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"ParametrizedFunc"
+# CHECK: DW_AT_type{{.*}}[[INT]] "int"
+# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_CLASS:[0-9a-f]*]] "clas1"
+
+# CHECK: 0x[[GLOBAL_CLASS:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"clas1"
+
+# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"first"
+
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"foo"
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+# CHECK: DW_TAG_formal_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int"
+
+# CHECK: 0x[[INNER_CLASS]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"clas1"
+# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"first"
+# CHECK: DW_AT_type{{.*}}[[CHAR]] "char"
+# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"second"
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"foo"
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+# CHECK: DW_AT_low_pc
+# CHECK: DW_AT_high_pc
+# CHECK: DW_TAG_formal_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}[[INT]] "int"
+
+# CHECK-NOT: DW_TAG_class_type
+# CHECK-NOT: DW_TAG_member
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[GLOBAL_CLASS]] "clas1"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONTAINER]] "Container"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONTAINER]] "Container"
+
+
+--- !mach-o
+FileHeader:
+ magic: 0xFEEDFACF
+ cputype: 0x01000007
+ cpusubtype: 0x00000003
+ filetype: 0x00000001
+ ncmds: 2
+ sizeofcmds: 376
+ flags: 0x00002000
+ reserved: 0x00000000
+LoadCommands:
+ - cmd: LC_SEGMENT_64
+ cmdsize: 232
+ segname: ''
+ vmaddr: 0x00
+ vmsize: 0x300
+ fileoff: 0x300
+ filesize: 0x300
+ maxprot: 7
+ initprot: 7
+ nsects: 2
+ flags: 0
+ Sections:
+ - sectname: __debug_abbrev
+ segname: __DWARF
+ addr: 0x000000000000000F
+ size: 0x90
+ offset: 0x00000380
+ align: 0
+ reloff: 0x00000000
+ nreloc: 0
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ - sectname: __debug_info
+ segname: __DWARF
+ addr: 0x000000000000100
+ size: 0x124
+ offset: 0x00000410
+ align: 0
+ reloff: 0x00000600
+ nreloc: 1
+ flags: 0x02000000
+ reserved1: 0x00000000
+ reserved2: 0x00000000
+ reserved3: 0x00000000
+ relocations:
+ - address: 0x2C
+ symbolnum: 1
+ pcrel: true
+ length: 3
+ extern: true
+ type: 0
+ scattered: false
+ value: 0
+ - cmd: LC_SYMTAB
+ cmdsize: 24
+ symoff: 0x700
+ nsyms: 2
+ stroff: 0x720
+ strsize: 10
+LinkEditData:
+ NameList:
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ - n_strx: 1
+ n_type: 0x0F
+ n_sect: 1
+ n_desc: 0
+ n_value: 0
+ StringTable:
+ - ''
+ - '__Z3foov'
+ - ''
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_linkage_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data4
+ - Tag: DW_TAG_formal_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_template_type_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_pointer_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_template_type_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_variable
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_const_value
+ Form: DW_FORM_data4
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref_addr
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - AbbrCode: 2
+ Values:
+ - CStr: foo
+ - CStr: __Z3foov
+ - Value: 0x000000a3
+ - Value: 0x00010000
+ - Value: 0x00000010
+ - AbbrCode: 3
+ Values:
+ - Value: 0x00000098
+ - AbbrCode: 4
+ Values:
+ - CStr: clas1
+ - AbbrCode: 5
+ Values:
+ - CStr: first
+ - Value: 0x0000009d
+ - AbbrCode: 5
+ Values:
+ - CStr: second
+ - Value: 0x000000a3
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 4
+ Values:
+ - CStr: clas1
+ - AbbrCode: 5
+ Values:
+ - CStr: first
+ - Value: 0x000000a3
+ - AbbrCode: 0
+ - AbbrCode: 4
+ Values:
+ - CStr: Container
+ - AbbrCode: 6
+ Values:
+ - CStr: ParametrizedFunc
+ - Value: 0x00000098
+ - AbbrCode: 7
+ Values:
+ - Value: 0x0000003d
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 8
+ Values:
+ - CStr: int
+ - AbbrCode: 8
+ Values:
+ - CStr: char
+ - AbbrCode: 8
+ Values:
+ - CStr: float
+ - AbbrCode: 10
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x0000005d
+ - AbbrCode: 10
+ Values:
+ - CStr: var2
+ - Value: 0x00000000
+ - Value: 0x00000070
+ - AbbrCode: 0
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU2
+ - AbbrCode: 2
+ Values:
+ - CStr: Container
+ - AbbrCode: 3
+ Values:
+ - CStr: ParametrizedFunc
+ - Value: 0x00000109
+ - AbbrCode: 4
+ Values:
+ - Value: 0x00000109
+ - AbbrCode: 0
+ - AbbrCode: 0
+ - AbbrCode: 5
+ Values:
+ - CStr: int
+ - AbbrCode: 5
+ Values:
+ - CStr: float
+ - AbbrCode: 6
+ Values:
+ - CStr: var1
+ - Value: 0x00000000
+ - Value: 0x000000e1
+ - AbbrCode: 0
+...
diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
new file mode 100644
index 000000000000000..c7cb663d42febb9
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
@@ -0,0 +1,475 @@
+/* Compile with:
+ clang -g -c odr-uniquing.cpp -o odr-uniquing/1.o
+ cp odr-uniquing/1.o odr-uniquing/2.o
+ The aim of these test is to check that all the 'type types' that
+ should be uniqued through the ODR really are.
+
+ The resulting object file is linked against itself using a fake
+ debug map. The end result is:
+ - with ODR uniquing: all types in second and third CUs should point back
+ to the types of the first CU(except types from anonymous namespace).
+ - without ODR uniquing: all types are re-emited in the second CU.
+ */
+
+/* Check by llvm-dwarfdump --verify */
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -o - | llvm-dwarfdump --verify - | \
+// RUN: FileCheck -check-prefixes=VERIFY %s
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -no-odr -o - | llvm-dwarfdump --verify - | \
+// RUN: FileCheck -check-prefixes=VERIFY %s
+
+/* Check for llvm-dwarfdump -a output */
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -o - | llvm-dwarfdump -v -a - | \
+// RUN: FileCheck -check-prefixes=CHECK %s
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -a - | \
+// RUN: FileCheck -check-prefixes=CHECK-NOODR %s
+
+struct S {
+ struct Nested {};
+};
+
+namespace N {
+class C {};
+} // namespace N
+
+union U {
+ class C {
+ } C;
+ struct S {
+ } S;
+};
+
+typedef S AliasForS;
+
+namespace {
+class AnonC {};
+} // namespace
+
+// This function is only here to hold objects that refer to the above types.
+void foo() {
+ AliasForS s;
+ S::Nested n;
+ N::C nc;
+ AnonC ac;
+ U u;
+}
+
+// VERIFY: Verifying .debug_abbrev...
+// VERIFY: Verifying .debug_info Unit Header Chain...
+// VERIFY: Verifying .debug_types Unit Header Chain...
+// VERIFY: Verifying .apple_names...
+// VERIFY: Verifying .apple_types...
+// VERIFY: Verifying .apple_namespaces...
+// VERIFY: Verifying .apple_objc...
+// VERIFY: No errors.
+
+// The first compile unit contains all the types:
+// CHECK: .debug_info contents
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_language{{.*}} (DW_LANG_C_plus_plus)
+// CHECK: DW_AT_name{{.*}}"__artificial_type_unit")
+// CHECK: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF1:[0-9a-f]*]])
+
+// CHECK:0x[[N_NAMESPACE:[0-9a-f]*]]:{{.*}}DW_TAG_namespace
+// CHECK:DW_AT_name{{.*}}"N"
+
+// CHECK:0x[[C_CLASS:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"C"
+// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01)
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (35)
+
+// CHECK:0x[[S_STRUCTURE:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+// CHECK:DW_AT_name{{.*}}"S"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (22)
+
+// CHECK:0x[[S_STRUCTURE_NESTED:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+// CHECK:DW_AT_name{{.*}}"Nested"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp")
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (23)
+
+// CHECK:0x[[TYPEDEF_ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef
+// CHECK:DW_AT_name{{.*}}"AliasForS"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (58)
+
+// CHECK:0x[[U_UNION:[0-9a-f]*]]:{{.*}}DW_TAG_union_type
+// CHECK:DW_AT_name{{.*}}"U"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (45)
+
+// CHECK:0x[[U_C_CLASS:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"C"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (46)
+
+// CHECK:0x[[U_C_MEMBER:[0-9a-f]*]]:{{.*}}DW_TAG_member
+// CHECK:DW_AT_name{{.*}}"C"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (46)
+
+// CHECK:0x[[U_S_MEMBER:[0-9a-f]*]]:{{.*}}DW_TAG_member
+// CHECK:DW_AT_name{{.*}}"S"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (47)
+
+// CHECK:0x[[U_S_STRUCT:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+// CHECK:DW_AT_name{{.*}}"S"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (47)
+
+// The second compile unit contains subprogram and its variables:
+// CHECK:DW_TAG_compile_unit
+// CHECK:DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF2:[0-9a-f]*]])
+
+// CHECK:DW_TAG_subprogram
+// CHECK:DW_AT_low_pc
+// CHECK:DW_AT_high_pc
+// CHECK:DW_AT_frame_base
+// CHECK:DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK:DW_AT_name{{.*}}"foo"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (74)
+// CHECK:DW_AT_external
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"s"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (75)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[TYPEDEF_ALIASFORS]] "AliasForS
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"n"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (76)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[S_STRUCTURE_NESTED]] "S::Neste
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"nc"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (77)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[C_CLASS]] "N::C"
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"ac"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (78)
+// CHECK:DW_AT_type [DW_FORM_ref4]{{.*}} {0x[[ANON_CLASS1:[0-9a-f]*]]} "(anonymous namespace)::AnonC")
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"u"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (79)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[U_UNION]] "U"
+
+// CHECK:0x[[ANON_NAMESPACE1:[0-9a-f]*]]:{{.*}}DW_TAG_namespace
+// CHECK-NEXT:DW_AT_decl_file{{.*}}"{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp"
+
+// CHECK:0x[[ANON_CLASS1]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"AnonC"
+// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01)
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (65)
+
+// The third compile unit contains subprogram and its variables:
+// CHECK:DW_TAG_compile_unit
+// CHECK:DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NEXT:DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF3:[0-9a-f]*]])
+
+// CHECK:DW_TAG_subprogram
+// CHECK:DW_AT_low_pc
+// CHECK:DW_AT_high_pc
+// CHECK:DW_AT_frame_base
+// CHECK:DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK:DW_AT_name{{.*}}"foo"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (74)
+// CHECK:DW_AT_external
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"s"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (75)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[TYPEDEF_ALIASFORS]] "AliasForS
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"n"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (76)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[S_STRUCTURE_NESTED]] "S::Neste
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"nc"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (77)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[C_CLASS]] "N::C"
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"ac"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (78)
+// CHECK:DW_AT_type [DW_FORM_ref4]{{.*}} {0x[[ANON_CLASS2:[0-9a-f]*]]} "(anonymous namespace)::AnonC")
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"u"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (79)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[U_UNION]] "U"
+
+// CHECK:0x[[ANON_NAMESPACE2:[0-9a-f]*]]:{{.*}}DW_TAG_namespace
+// CHECK-NEXT:DW_AT_decl_file{{.*}}"{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp"
+
+// CHECK:0x[[ANON_CLASS2]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"AnonC"
+// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01)
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (65)
+
+// CHECK:.debug_aranges contents
+
+// CHECK:debug_line[0x[[LINE_TABLE_OFF1]]]
+
+// CHECK:debug_line[0x[[LINE_TABLE_OFF2]]]
+
+// CHECK:debug_line[0x[[LINE_TABLE_OFF3]]]
+
+// CHECK:.debug_str contents:
+// CHECK:0x00000000: ""
+// CHECK:0x00000001: "clang version 3.8.0 (trunk 244290) (llvm/trunk 244270)"
+// CHECK:0x00000038: "odr-uniquing.cpp"
+// CHECK:0x00000049: "/tmp"
+// CHECK:0x0000004e: "_Z3foov"
+// CHECK:0x00000056: "foo"
+// CHECK:0x0000005a: "s"
+// CHECK:0x0000005c: "n"
+// CHECK:0x0000005e: "nc"
+// CHECK:0x00000061: "ac"
+// CHECK:0x00000064: "u"
+// CHECK:0x00000066: "AnonC"
+// CHECK:0x0000006c: "(anonymous namespace)"
+// CHECK:0x00000082: "llvm DWARFLinkerParallel library version "
+// CHECK:0x000000ac: "__artificial_type_unit"
+// CHECK:0x000000c3: ""
+// CHECK:0x000000c4: "AliasForS"
+// CHECK:0x000000ce: "C"
+// CHECK:0x000000d0: "N"
+// CHECK:0x000000d2: "Nested"
+// CHECK:0x000000d9: "S"
+// CHECK:0x000000db: "U"
+
+
+// CHECK:.apple_names
+// CHECK: Bucket count: 2
+// CHECK: String: {{.*}} "foo"
+// CHECK: String: {{.*}} "_Z3foov"
+
+// CHECK:.apple_types
+// CHECK: Bucket count: 6
+// CHECK: String: {{.*}} "AnonC"
+// CHECK: String: {{.*}} "Nested"
+// CHECK: String: {{.*}} "S"
+// CHECK: String: {{.*}} "C"
+// CHECK: String: {{.*}} "U"
+// CHECK: String: {{.*}} "AliasForS"
+
+// CHECK:.apple_namespaces
+// CHECK: Bucket count: 2
+// CHECK: String: {{.*}} "(anonymous namespace)"
+// CHECK: String: {{.*}} "N"
+
+// CHECK:.apple_objc
+// CHECK:Bucket count: 1
+
+// CHECK-NOODR: .debug_info contents
+
+// CHECK-NOODR: DW_TAG_compile_unit
+// CHECK-NOODR: DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NOODR-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF1:[0-9a-f]*]])
+// CHECK-NOODR: DW_AT_low_pc{{.*}}(0x{{0*}}[[LOW_PC1:[0-9a-f]*]])
+// CHECK-NOODR-NEXT: DW_AT_high_pc{{.*}}(0x{{0*}}[[HIGH_PC1:[0-9a-f]*]])
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"Nested"
+
+// CHECK-NOODR: DW_TAG_namespace
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"N"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_union_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_subprogram
+// CHECK-NOODR-NEXT: DW_AT_low_pc
+// CHECK-NOODR-NEXT: DW_AT_high_pc
+// CHECK-NOODR: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"foo"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"s"
+// CHECK-NOODR: DW_AT_type{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"n"
+// CHECK-NOODR: DW_AT_type{{.*}}"S::Nested"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"nc"
+// CHECK-NOODR: DW_AT_type{{.*}}"N::C"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"ac"
+// CHECK-NOODR: DW_AT_type{{.*}}"(anonymous namespace)::AnonC"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"u"
+// CHECK-NOODR: DW_AT_type{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_typedef
+// CHECK-NOODR: DW_AT_type{{.*}}"S"
+// CHECK-NOODR: DW_AT_name{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_namespace
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"AnonC"
+
+// CHECK-NOODR: DW_TAG_compile_unit
+// CHECK-NOODR: DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NOODR-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF2:[0-9a-f]*]])
+// CHECK-NOODR: DW_AT_low_pc
+// CHECK-NOODR: DW_AT_high_pc
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR: DW_AT_name{{.*}}"Nested"
+
+// CHECK-NOODR: DW_TAG_namespace
+// CHECK-NOODR: DW_AT_name{{.*}}"N"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_union_type
+// CHECK-NOODR: DW_AT_name{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR: DW_AT_name{{.*}}"C"
+// CHECK-NOODR: DW_AT_type{{.*}}"U::C"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR: DW_AT_name{{.*}}"S"
+// CHECK-NOODR: DW_AT_type{{.*}}"U::S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_subprogram
+// CHECK-NOODR: DW_AT_low_pc
+// CHECK-NOODR: DW_AT_high_pc
+// CHECK-NOODR: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK-NOODR: DW_AT_name{{.*}}"foo"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"s"
+// CHECK-NOODR: DW_AT_type{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"n"
+// CHECK-NOODR: DW_AT_type{{.*}}"S::Nested"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"nc"
+// CHECK-NOODR: DW_AT_type{{.*}} "N::C"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"ac"
+// CHECK-NOODR: DW_AT_type{{.*}}"(anonymous namespace)::AnonC"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"u"
+// CHECK-NOODR: DW_AT_type{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_typedef
+// CHECK-NOODR: DW_AT_type{{.*}}"S"
+// CHECK-NOODR: DW_AT_name{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_namespace
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"AnonC"
+
+// CHECK-NOODR:.debug_aranges contents
+
+// CHECK-NOODR:debug_line[0x[[LINE_TABLE_OFF1]]]
+
+// CHECK-NOODR:debug_line[0x[[LINE_TABLE_OFF2]]]
+
+// CHECK-NOODR:.debug_str contents:
+// CHECK-NOODR:0x00000000: ""
+// CHECK-NOODR:0x00000001: "clang version 3.8.0 (trunk 244290) (llvm/trunk 244270)"
+// CHECK-NOODR:0x00000038: "odr-uniquing.cpp"
+// CHECK-NOODR:0x00000049: "/tmp"
+// CHECK-NOODR:0x0000004e: "S"
+// CHECK-NOODR:0x00000050: "Nested"
+// CHECK-NOODR:0x00000057: "N"
+// CHECK-NOODR:0x00000059: "C"
+// CHECK-NOODR:0x0000005b: "U"
+// CHECK-NOODR:0x0000005d: "_Z3foov"
+// CHECK-NOODR:0x00000065: "foo"
+// CHECK-NOODR:0x00000069: "s"
+// CHECK-NOODR:0x0000006b: "n"
+// CHECK-NOODR:0x0000006d: "nc"
+// CHECK-NOODR:0x00000070: "ac"
+// CHECK-NOODR:0x00000073: "u"
+// CHECK-NOODR:0x00000075: "AliasForS"
+// CHECK-NOODR:0x0000007f: "AnonC"
+// CHECK-NOODR:0x00000085: "(anonymous namespace)"
+
+// CHECK-NOODR: .apple_names
+// CHECK-NOODR: Bucket count: 2
+// CHECK-NOODR: String: {{.*}} "foo"
+// CHECK-NOODR: String: {{.*}} "_Z3foov"
+
+// CHECK-NOODR: .apple_types
+// CHECK-NOODR: Bucket count: 6
+// CHECK-NOODR: String: {{.*}} "AnonC"
+// CHECK-NOODR: String: {{.*}} "Nested"
+// CHECK-NOODR: String: {{.*}} "S"
+// CHECK-NOODR: String: {{.*}} "C"
+// CHECK-NOODR: String: {{.*}} "U"
+// CHECK-NOODR: String: {{.*}} "AliasForS"
+
+// CHECK-NOODR: .apple_namespaces
+// CHECK-NOODR: Bucket count: 2
+// CHECK-NOODR: String: {{.*}} "(anonymous namespace)"
+// CHECK-NOODR: String: {{.*}} "N"
+
+// CHECK-NOODR: .apple_objc
+// CHECK-NOODR:Bucket count: 1
diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o
new file mode 100644
index 000000000000000..a837de81a4f295d
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o
diff er
diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o
new file mode 100644
index 000000000000000..a0d093389d42409
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o
diff er
diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o
new file mode 100644
index 000000000000000..9b3a9acd4a6cd0a
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o
diff er
diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/main.o b/llvm/test/tools/dsymutil/X86/Inputs/String/main.o
new file mode 100644
index 000000000000000..29716a88f5c0754
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/main.o
diff er
diff --git a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp
index 8a72aee6fb38fb8..6ea5ef22a65acbf 100644
--- a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp
+++ b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp
@@ -1,10 +1,5 @@
// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
-// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \
-// RUN: %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
-// RUN: FileCheck %s --implicit-check-not \
-// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
-
// The test was compiled with:
// clang++ -O2 -g -c dead-strip.cpp -o 1.o
diff --git a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map
index 95b1f726d4ff9e7..ec5d8e4f1503155 100644
--- a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map
+++ b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map
@@ -16,8 +16,8 @@ objects:
- { sym: __Z3foov, objAddr: 0x0, binAddr: 0x20000, size: 0x10 }
- filename: 3.o
symbols:
- - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x10 }
- - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30010, size: 0x10 }
+ - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x20 }
+ - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30020, size: 0x10 }
- filename: 4.o
symbols:
- { sym: __Z3foov, objAddr: 0x0, binAddr: 0x40000, size: 0x10 }
diff --git a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
index b6d2f4391c70e3c..651a874ff3ec4c9 100644
--- a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
+++ b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
@@ -57,8 +57,8 @@
#DWARF-CHECK: 0x00000000: range list header: length = 0x00000011, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
#DWARF-CHECK: ranges:
#DWARF-CHECK: 0x0000000c: [DW_RLE_base_addressx]: 0x0000000000000003
-#DWARF-CHECK: 0x0000000e: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x000000000000001d => [0x0000000100000f79, 0x0000000100000f96)
-#DWARF-CHECK: 0x00000011: [DW_RLE_offset_pair ]: 0x0000000000000034, 0x000000000000003b => [0x0000000100000fad, 0x0000000100000fb4)
+#DWARF-CHECK: 0x0000000e: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x000000000000001d
+#DWARF-CHECK: 0x00000011: [DW_RLE_offset_pair ]: 0x0000000000000034, 0x000000000000003b
#DWARF-CHECK: 0x00000014: [DW_RLE_end_of_list ]
#
#UPD-DWARF-CHECK: DW_TAG_compile_unit
diff --git a/llvm/test/tools/dsymutil/X86/empty-CU.test b/llvm/test/tools/dsymutil/X86/empty-CU.test
index db9f70874971b3a..7b06607a74cbc0b 100644
--- a/llvm/test/tools/dsymutil/X86/empty-CU.test
+++ b/llvm/test/tools/dsymutil/X86/empty-CU.test
@@ -1,8 +1,6 @@
RUN: llvm-mc %p/../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o
RUN: dsymutil --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
-RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
-
CHECK: .debug_info contents:
CHECK: 0x00000000: Compile Unit: length = 0x00000008, format = DWARF32, version = 0x0003, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x0000000c)
diff --git a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
index e933be8fd9bdb09..928b14b62bc672e 100644
--- a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
+++ b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
@@ -1,9 +1,15 @@
-// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
-
-// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \
-// RUN: %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | \
-// RUN: FileCheck %s --implicit-check-not \
-// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
+// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path \
+// RUN: %p/../Inputs/inlined-static-variable -o - -keep-function-for-static \
+// RUN: | llvm-dwarfdump - | FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN: --check-prefixes=CHECK
+//
+// RUN: dsymutil --linker llvm --no-odr -f -y %p/dummy-debug-map.map \
+// RUN: -oso-prepend-path %p/../Inputs/inlined-static-variable -o - \
+// RUN: -keep-function-for-static | llvm-dwarfdump - | FileCheck %s \
+// RUN: --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN: --check-prefixes=CHECK
// clang -g -c inlined-static-variable.cpp -o 4.o
diff --git a/llvm/test/tools/dsymutil/X86/keep-func.test b/llvm/test/tools/dsymutil/X86/keep-func.test
index f307f5ad89900dc..021c7212bd8319b 100644
--- a/llvm/test/tools/dsymutil/X86/keep-func.test
+++ b/llvm/test/tools/dsymutil/X86/keep-func.test
@@ -25,11 +25,6 @@ RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/
RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
-RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM
-RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static
-RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
-RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
-
KEEP: DW_AT_name ("MyDummyVar")
KEEP: DW_AT_name ("FOO_VAR_TYPE")
KEEP: DW_AT_name ("x1")
diff --git a/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test b/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test
new file mode 100644
index 000000000000000..627df30344d8b7c
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test
@@ -0,0 +1,65 @@
+Test binaries created with the following commands:
+
+$ cat container.cpp
+#include "container.h"
+#include <stdlib.h>
+
+struct Container_ivars {
+ // real definition here
+};
+
+ContainerPtr allocateContainer() {
+ Container *c = (Container *)malloc(sizeof(Container));
+ c->ivars = (Container_ivars *)malloc(sizeof(Container_ivars));
+ return c;
+}
+
+extern void doSomething(ContainerPtr);
+
+int main() {
+ ContainerPtr c = allocateContainer();
+ doSomething(c);
+ return 0;
+}
+
+$ cat container.h
+struct Container_ivars;
+
+struct Container {
+ union {
+ struct Container_ivars *ivars;
+ };
+};
+
+typedef Container *ContainerPtr;
+
+$ cat use.cpp
+#include "container.h"
+
+void doSomething(ContainerPtr c) {}
+
+
+$ clang++ -O0 -g container.cpp -c -o container.o
+$ clang++ -O0 -g use.cpp -c -o use.o
+$ clang++ use.o container.o -o a.out
+
+Note that the link order in the last command matters for this test.
+
+RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM
+RUN: llvm-dwarfdump --debug-info %t.dSYM | FileCheck %s
+
+CHECK: DW_TAG_compile_unit
+CHECK-NEXT: DW_AT_producer ("llvm DWARFLinkerParallel library
+CHECK-NEXT: DW_AT_language (DW_LANG_C_plus_plus_14)
+CHECK-NEXT: DW_AT_name ("__artificial_type_unit")
+CHECK-NEXT: DW_AT_stmt_list (0x00000000)
+
+CHECK: DW_TAG_structure_type
+CHECK: DW_AT_calling_convention (DW_CC_pass_by_value)
+CHECK: DW_AT_name ("Container_ivars")
+CHECK-NEXT: DW_AT_byte_size (0x01)
+CHECK-NEXT: DW_AT_decl_line (4)
+CHECK-NEXT: DW_AT_decl_file ("{{.*}}container.cpp")
+
+CHECK: DW_TAG_compile_unit
+CHECK-NOT: DW_AT_declaration
diff --git a/llvm/test/tools/dsymutil/X86/location-expression.test b/llvm/test/tools/dsymutil/X86/location-expression.test
index 5414dff3745b285..3bffc9aeacca77a 100644
--- a/llvm/test/tools/dsymutil/X86/location-expression.test
+++ b/llvm/test/tools/dsymutil/X86/location-expression.test
@@ -18,15 +18,15 @@
# CHECK: Compile Unit:
# CHECK: DW_TAG_compile_unit
# CHECK: DW_AT_name{{.*}}"CU1"
-# CHECK: 0x0000001b: DW_TAG_variable
+# CHECK: DW_TAG_variable
# CHECK: DW_AT_name {{.*}}"var1"
# CHECK: DW_AT_type {{.*}}"class1"
# CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
-# CHECK: 0x000000ab: DW_TAG_variable
+# CHECK: DW_TAG_variable
# CHECK: DW_AT_name {{.*}}"var2"
# CHECK: DW_AT_type {{.*}}"class1"
# CHECK: DW_AT_location [DW_FORM_block] (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
-# CHECK: 0x00000146: DW_TAG_variable
+# CHECK: DW_TAG_variable
# CHECK: DW_AT_name {{.*}}"var3"
# CHECK: DW_AT_type {{.*}}"class1"
#
diff --git a/llvm/test/tools/dsymutil/X86/modules-empty.m b/llvm/test/tools/dsymutil/X86/modules-empty.m
index fc415acc59f6d60..eb70f51230de91b 100644
--- a/llvm/test/tools/dsymutil/X86/modules-empty.m
+++ b/llvm/test/tools/dsymutil/X86/modules-empty.m
@@ -29,6 +29,6 @@ int main() {
}
// The empty CU from the pcm should not get copied into the dSYM.
-// CHECK: DW_TAG_compile_unit
-// CHECK-NOT: DW_TAG_compile_unit
-
+// Check that module name occured only once.
+// CHECK: "Empty"
+// CHECK-NOT: "Empty"
diff --git a/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp b/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
index 0e3b974ba005937..d87bb5b73c240e2 100644
--- a/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
+++ b/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
@@ -14,6 +14,8 @@
// RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=ODR,CHECK %s
// RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=NOODR,CHECK %s
+// RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=NOODR,CHECK %s
+
// The first compile unit contains all the types:
// CHECK: TAG_compile_unit
// CHECK-NOT: DW_TAG
diff --git a/llvm/test/tools/dsymutil/X86/op-convert.test b/llvm/test/tools/dsymutil/X86/op-convert.test
index 15725a0435d4884..9960d1996496d65 100644
--- a/llvm/test/tools/dsymutil/X86/op-convert.test
+++ b/llvm/test/tools/dsymutil/X86/op-convert.test
@@ -12,21 +12,23 @@ objects:
- { sym: _foo, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
...
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name ("dbg.c")
-CHECK: DW_TAG_base_type
+CHECK:0x[[ADDR1:[0-9a-f]+]]: DW_TAG_base_type
CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8")
CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
CHECK-NEXT: DW_AT_byte_size (0x01)
-CHECK: DW_TAG_base_type
+CHECK:0x[[ADDR2:[0-9a-f]+]]: DW_TAG_base_type
CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32")
CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
CHECK-NEXT: DW_AT_byte_size (0x04)
CHECK: DW_TAG_variable
CHECK-NEXT: DW_AT_location (
-CHECK-NEXT: [0x0000000000001000, 0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value
-CHECK-NEXT: [0x0000000000001002, 0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value)
+CHECK-NEXT: [0x0000000000001000, 0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x[[ADDR1]]) "DW_ATE_signed_8", DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value
+CHECK-NEXT: [0x0000000000001002, 0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x[[ADDR1]]) "DW_ATE_signed_8", DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value)
CHECK-NEXT: DW_AT_name ("y")
CHECK: DW_TAG_variable
@@ -34,6 +36,6 @@ CHECK-NEXT: DW_AT_location (DW_OP_constu 0x33, DW_OP_convert 0x0, DW_OP_stac
CHECK-NEXT: DW_AT_name ("d")
CHECK: DW_TAG_variable
-CHECK-NEXT: DW_AT_location (DW_OP_constu 0x2a, DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value)
+CHECK-NEXT: DW_AT_location (DW_OP_constu 0x2a, DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value)
CHECK-NEXT: DW_AT_name ("c")
diff --git a/llvm/test/tools/dsymutil/X86/union-fwd-decl.test b/llvm/test/tools/dsymutil/X86/union-fwd-decl.test
index c5c8c9e93e0a06a..c73db0e3f5532e5 100644
--- a/llvm/test/tools/dsymutil/X86/union-fwd-decl.test
+++ b/llvm/test/tools/dsymutil/X86/union-fwd-decl.test
@@ -48,9 +48,6 @@ Note that the link order in the last command matters for this test.
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM
RUN: llvm-dwarfdump %t.dSYM | FileCheck %s
-RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM
-RUN: llvm-dwarfdump %t.dSYM | FileCheck %s
-
CHECK: DW_TAG_compile_unit
CHECK: DW_AT_name ("Container_ivars")
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
index 90c40fd1e4ab62e..b63668c39c90187 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
@@ -39,7 +39,7 @@
#DWARF-CHECK: DW_AT_name [DW_FORM_strx] {{.*}} "CU1"
#DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130)
#DWARF-CHECK: DW_AT_high_pc [DW_FORM_data8] (0x0000000000000060)
-#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
+#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset]
#DWARF-CHECK: DW_TAG_subprogram
#DWARF-CHECK: DW_AT_name [DW_FORM_strx] {{.*}} "foo1"
#DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130)
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
index 78b53897346c48c..a1bb3ec7d846d8c 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
@@ -35,7 +35,7 @@
#DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130)
#DWARF-CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[CURANGE_OFF:[0-9a-f]*]]
#DWARF-CHECK: [0x0000000000001130, 0x0000000000001170))
-#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008)
+#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset]
#DWARF-CHECK: DW_TAG_subprogram
#DWARF-CHECK: DW_AT_name [DW_FORM_strx] {{.*}} "foo1"
#DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130)
@@ -65,7 +65,7 @@
#DWARF-CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[F4RANGE_OFF:[0-9a-f]*]]
#DWARF-CHECK: [0x0000000000001160, 0x0000000000001170))
#DWARF-CHECK: .debug_aranges contents:
-#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
+#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x000000{{00|21}}, addr_size = 0x08, seg_size = 0x00
#DWARF-CHECK: [0x0000000000001130, 0x0000000000001170)
#DWARF-CHECK: .debug_addr contents:
#DWARF-CHECK: 0x00000000: Address table header: length = 0x00000024, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
@@ -79,19 +79,19 @@
#DWARF-CHECK: 0x00000000: range list header: length = 0x00000026, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
#DWARF-CHECK: ranges:
#DWARF-CHECK: 0x[[F1RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000000
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010
#DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ]
#DWARF-CHECK: 0x[[F2RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000001
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010
#DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ]
#DWARF-CHECK: 0x[[F3RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000002
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010
#DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ]
#DWARF-CHECK: 0x[[F4RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000003
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010
#DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ]
#DWARF-CHECK 0x[[CURANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000000
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000040
#DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ]
#UPD-DWARF-CHECK: DW_TAG_compile_unit
@@ -145,15 +145,15 @@
#UPD-DWARF-CHECK: 0x00000032 => 0x0000003e
#UPD-DWARF-CHECK: ]
#UPD-DWARF-CHECK: ranges:
-#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140)
+#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000010
#UPD-DWARF-CHECK: 0x00000023: [DW_RLE_end_of_list ]
-#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]: 0x0000000000000001, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150)
+#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]: 0x0000000000000001, 0x0000000000000010
#UPD-DWARF-CHECK: 0x00000027: [DW_RLE_end_of_list ]
-#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]: 0x0000000000001150, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160)
+#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]: 0x0000000000001150, 0x0000000000000010
#UPD-DWARF-CHECK: 0x00000032: [DW_RLE_end_of_list ]
-#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]: 0x0000000000001160, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170)
+#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]: 0x0000000000001160, 0x0000000000000010
#UPD-DWARF-CHECK: 0x0000003d: [DW_RLE_end_of_list ]
-#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170)
+#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000040
#UPD-DWARF-CHECK: 0x00000041: [DW_RLE_end_of_list ]
## Following yaml description has Content of the .debug_rnglists exactly like above data ^^^^^^
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
index 90cb99858c9efc9..2c4caa158258d28 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
@@ -3,23 +3,23 @@
# RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
-# RUN: llvm-dwarfutil --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
-# RUN: llvm-dwarfutil --linker llvm %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --linker llvm %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
-# RUN: llvm-dwarfutil --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
-# RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
-# RUN: llvm-dwarfutil --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
+# RUN: llvm-dwarfutil --no-odr --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
-# RUN: llvm-dwarfutil --linker llvm --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
+# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
-# RUN: llvm-dwarfutil %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
-# RUN: llvm-dwarfutil --linker llvm %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --linker llvm %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
# CHECK: DW_TAG_compile_unit
# CHECK: DW_AT_name{{.*}}"CU1"
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
index 232f6a5553e5717..46ebcf24fe64dc0 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
@@ -2,10 +2,10 @@
## are combined during --garbage-collection optimisation.
# RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o %t1
# RUN: llvm-dwarfdump -a %t1 | FileCheck %s
-# RUN: llvm-dwarfutil --linker llvm --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection %t.o %t1
# RUN: llvm-dwarfdump -a %t1 | FileCheck %s
# CHECK: DW_TAG_compile_unit
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
index cb3b435ea9aa4cc..7f0533a882dd8bc 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
@@ -3,11 +3,11 @@
## RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
-# RUN: llvm-dwarfutil --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
-# RUN: llvm-dwarfutil --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
-# RUN: llvm-dwarfutil --linker llvm --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
# CHECK: DW_TAG_compile_unit
# CHECK: DW_AT_name{{.*}}"CU1"
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
index 1f5ddd78adaa24c..1a3f29d127cefc6 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
@@ -2,9 +2,9 @@
## does not affect files which do not have dead debug info.
# RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
-# RUN: llvm-dwarfutil --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
# CHECK: DW_TAG_compile_unit
# CHECK: DW_AT_name{{.*}}"CU1"
diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
index 2ee1d73b6f92f04..1a8010e364d25a6 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
@@ -3,10 +3,10 @@
## optimisation.
# RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o %t1
# RUN: llvm-dwarfdump -a %t1 | FileCheck %s
-# RUN: llvm-dwarfutil --linker llvm --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection %t.o %t1
# RUN: llvm-dwarfdump -a %t1 | FileCheck %s
# CHECK: DW_TAG_compile_unit
diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index a1f18e6f169db9e..d00ef1a8c228b08 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -1059,7 +1059,6 @@ DwarfLinkerForBinary::AddressManager<AddressesMapBase>::hasValidRelocationAt(
uint64_t EndOffset) {
std::vector<ValidReloc> Relocs =
getRelocations(AllRelocs, StartOffset, EndOffset);
-
if (Relocs.size() == 0)
return std::nullopt;
More information about the llvm-commits
mailing list