[llvm] [DWARFLinkerParallel] Add support for -odr mode. (PR #68721)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 22 15:17:26 PST 2023
https://github.com/avl-llvm updated https://github.com/llvm/llvm-project/pull/68721
>From 66b03b27346d02c747ea481cf0825c61b7aca525 Mon Sep 17 00:00:00 2001
From: Alexey Lapshin <a.v.lapshin at mail.ru>
Date: Mon, 9 Oct 2023 16:25:14 +0200
Subject: [PATCH] [DWARFLinkerParallel] Add support for -odr mode.
This patch is extracted from D96035, it adds support for the type
deduplication mode. With this patch DWARFLinkerParallel handles
--odr option. It also processes clang modules.
---
.../AcceleratorRecordsSaver.cpp | 295 ++++++
.../AcceleratorRecordsSaver.h | 70 ++
llvm/lib/DWARFLinkerParallel/ArrayList.h | 26 +-
llvm/lib/DWARFLinkerParallel/CMakeLists.txt | 3 +
.../DIEAttributeCloner.cpp | 297 +++---
.../DWARFLinkerParallel/DIEAttributeCloner.h | 73 +-
llvm/lib/DWARFLinkerParallel/DIEGenerator.h | 21 +-
llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp | 1 +
.../DWARFLinkerCompileUnit.cpp | 843 +++++++++++-------
.../DWARFLinkerCompileUnit.h | 269 ++++--
.../DWARFLinkerGlobalData.h | 1 +
.../DWARFLinkerParallel/DWARFLinkerImpl.cpp | 440 ++++++---
.../lib/DWARFLinkerParallel/DWARFLinkerImpl.h | 58 +-
.../DWARFLinkerTypeUnit.cpp | 391 ++++++++
.../DWARFLinkerParallel/DWARFLinkerTypeUnit.h | 138 +++
.../DWARFLinkerParallel/DWARFLinkerUnit.cpp | 50 +-
.../lib/DWARFLinkerParallel/DWARFLinkerUnit.h | 108 +--
.../DebugLineSectionEmitter.h | 1 +
.../DWARFLinkerParallel/DependencyTracker.cpp | 830 +++++++++++++----
.../DWARFLinkerParallel/DependencyTracker.h | 235 ++++-
.../DWARFLinkerParallel/OutputSections.cpp | 164 +++-
llvm/lib/DWARFLinkerParallel/OutputSections.h | 93 +-
.../SyntheticTypeNameBuilder.cpp | 767 ++++++++++++++++
.../SyntheticTypeNameBuilder.h | 155 ++++
llvm/lib/DWARFLinkerParallel/TypePool.h | 177 ++++
llvm/lib/DWARFLinkerParallel/Utils.h | 40 +
.../accel-imported-declarations.test | 80 ++
.../ARM/accel-imported-declarations.test | 20 +-
.../tools/dsymutil/ARM/dwarf5-addr-base.test | 43 +-
.../ARM/dwarf5-dwarf4-combination-macho.test | 28 +-
.../test/tools/dsymutil/ARM/dwarf5-macho.test | 20 +-
.../ARM/dwarf5-str-offsets-base-strx.test | 65 +-
.../X86/DWARFLinkerParallel/dead-stripped.cpp | 67 ++
.../X86/DWARFLinkerParallel/empty-CU.test | 5 +
.../inlined-static-variable.cpp | 74 ++
.../X86/DWARFLinkerParallel/keep-func.test | 36 +
.../odr-anon-namespace.cpp | 68 ++
.../odr-fwd-declaration.test | 101 +++
.../odr-fwd-declaration2.test | 131 +++
.../odr-fwd-declaration3.test | 381 ++++++++
.../odr-member-functions.cpp | 192 ++++
.../odr-namespace-extension.test | 157 ++++
.../odr-nested-types1.test | 384 ++++++++
.../odr-nested-types2.test | 374 ++++++++
.../X86/DWARFLinkerParallel/odr-parents.test | 238 +++++
.../odr-predictable-output.test | 117 +++
.../odr-predictable-output2.test | 120 +++
.../odr-recursive-dependence.test | 245 +++++
.../X86/DWARFLinkerParallel/odr-string.test | 180 ++++
.../odr-template-parameters.test | 201 +++++
.../odr-two-units-in-single-file.test | 205 +++++
.../odr-types-in-subprogram1.test | 431 +++++++++
.../X86/DWARFLinkerParallel/odr-uniquing.cpp | 475 ++++++++++
.../tools/dsymutil/X86/Inputs/String/foo1.o | Bin 0 -> 47448 bytes
.../tools/dsymutil/X86/Inputs/String/foo2.o | Bin 0 -> 56860 bytes
.../tools/dsymutil/X86/Inputs/String/foo3.o | Bin 0 -> 61128 bytes
.../tools/dsymutil/X86/Inputs/String/main.o | Bin 0 -> 50140 bytes
.../test/tools/dsymutil/X86/dead-stripped.cpp | 5 -
.../tools/dsymutil/X86/dummy-debug-map.map | 4 +-
.../tools/dsymutil/X86/dwarf5-rnglists.test | 4 +-
llvm/test/tools/dsymutil/X86/empty-CU.test | 2 -
.../dsymutil/X86/inlined-static-variable.cpp | 18 +-
llvm/test/tools/dsymutil/X86/keep-func.test | 5 -
.../X86/linker-llvm-union-fwd-decl.test | 65 ++
.../dsymutil/X86/location-expression.test | 6 +-
llvm/test/tools/dsymutil/X86/modules-empty.m | 6 +-
llvm/test/tools/dsymutil/X86/odr-uniquing.cpp | 2 +
llvm/test/tools/dsymutil/X86/op-convert.test | 12 +-
.../tools/dsymutil/X86/union-fwd-decl.test | 3 -
.../ELF/X86/dwarf5-addresses.test | 2 +-
.../ELF/X86/dwarf5-rnglists.test | 24 +-
.../llvm-dwarfutil/ELF/X86/gc-default.test | 18 +-
.../gc-func-overlapping-address-ranges.test | 4 +-
.../llvm-dwarfutil/ELF/X86/gc-maxpc.test | 8 +-
.../llvm-dwarfutil/ELF/X86/gc-no-garbage.test | 4 +-
.../gc-unit-overlapping-address-ranges.test | 4 +-
llvm/tools/dsymutil/DwarfLinkerForBinary.cpp | 1 -
77 files changed, 9062 insertions(+), 1119 deletions(-)
create mode 100644 llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
create mode 100644 llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
create mode 100644 llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
create mode 100644 llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
create mode 100644 llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
create mode 100644 llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
create mode 100644 llvm/lib/DWARFLinkerParallel/TypePool.h
create mode 100644 llvm/lib/DWARFLinkerParallel/Utils.h
create mode 100644 llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o
create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o
create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o
create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/main.o
create mode 100644 llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test
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 different compilation units can
+ // be compiled on different 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 different 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 different 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
+## different namespaces. The result should contain two variables which
+## reference different 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 differ 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 differ 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 different 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
+## different 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 0000000000000000000000000000000000000000..a837de81a4f295dc6f3d8d625bfc7f508f311b3d
GIT binary patch
literal 47448
zcmcg#34B!5^}aL7z(9~>hJ-~BVgey-lVsQtku3_c$f}6aagt16AjyQ8NdidKx+^HC
zxZr}gW8L?yF0K9Bs at 1yGYOS?eE!Dczy49tv|L;5ZzBg|siQB}^FZZ2uzjN-n=dSO*
z_wIZ7?HBL;x4TlV9EAfyE<(8nhhhZ$1|aMq*vW79ty(aLY4Ee+u&Ee&6T~kRN=7y$
zHLv5#s#h#a#Vzi7!_XeH-FlZ&J&EP26G*IIC{&wB#-mNE4G;>Y+q3NWjr^a+KP$c4
zV(j#Fk(!p(As7`T6q<d+j3o!#S`Qem|8mXbbhAYklV&m$()Jo+wIa{7_q?$aV5Q?X
z at F-0k#}4g<Yii<=R at P^_f372R$_v?$_{}|9Q^&DGd(o!)7<Dr3U9?iCTzH_SuZ1*y
z1?}P0Y=`z5!?j{E)85_-bs|$-6}U{t9mfoN;pXOsNT?~?7)d}W)85~Vy*<WY#kaH<
zt63`zl4)<-PVLE1<Isz{9G+>mbN`ydwVC$rF!ro2|K+!|m)zLgVR?sNtex1nkEXH9
zzsbMaSR?#OhFY51qD^(7(EQoX6uYm}vDXav){RQB>kPVEk6W-A<&CTf)yL5qIzi at m
zJ7JH;D@}X+`X+5pqe|r|wZ`H}?eP(95{sGjcdHq|JIpxy>}H*M8T>O at r1=+wxIco(
z at _VXW1pcT*{Ai?OzkLOCGeG#G79sG*EEt%UbC$6W?%V&C&pG3-Z&7{DSqHM|=bZ6a
z)g!CkCXzn{HBb4{MRU&hQY)SD=Q$_+(tGkF$?ivKB}3}-hn&nbqA#jvs-dn`k8V%d
z-!k3njOX92<~;k>sz>VsR#H1ZZ5bv_{&UXwY}KPZi<ip0S)7P&iWCoPXi+mb(28pt
z!cD7-TO;vAG}csHRTZcVj4dt~bWBxM<ygjpf$@_^sQOr}Dp1?ptSXi#pk7ha5^bnU
zG=y6t72(zf%=3w41rMA{IYHONVht*htV5eushV&iT5BXzYuAM1ql+P$G6k|JQy32=
z<KbvBA+l*sVYmTvX*d~+Yf<qu*mGJ7p~E-Enx-b>EfL68E}XYCITmJvRUPWhonKQ`
zT^+2%iD^wd))s1rG_6jq2}R=ZSiHIww%fzs-Ds>O8H&}1;;7n)!>AKRPKh<Kcrw%&
zPOMXGlo00tWf#|~kW at 9<qEt<+T&N3MHNh5|baNLj4NbPexwX~R)ssv#QoUqpFw|&e
z6;aKxXj3v0hf9VNSK2j`ZOzV~4W~lOnk`dSBc<Ywx=ZtBVz{m at 9!Vssm((i5s(7S6
z5|1?1M!q at GyjoQoYeHYMT-UKQ3%X{~a!u7h<Dz-3rq)$M3?rbWDG^=W6saplRixaX
z+8T at 2Nw4a_T2*CT#IDjswT&tj?W_co8p9hxY;5!ji=}P{)+g3sEX89Rs~6S6u&^pL
zyIDyuNpGo8w6Xa+Hs0uBJznfK)x8g$(&~v*JMDO*i&<lqh0qKRP+f_vyU^@tef=_a
zWxHJ8r+2b_bfdBf>~_ZbPukrHN_Q+C`8AWq=;HctLxR)8BCPZ5PM(@^ibpycxoTXx
z#@t1<)m4=?7Gs}H#pq>SG>O?W+%Q$LaXMn_rRBwWuPK}yUCaT5oM*E60I1O1dW@$v
zktPg=8l1kTN@<HTdf~UK&$Qmj0nZ-#9h=1JqSZ_0!N7M+J$7Ou(h$K)B-X at 6ONMdE
zkArL8sM|2!Qp;L1w!f9`cl4kNv%Eb(WzIvd!n{~Dk at MZ^c(_4(5^hS)t&#IWHQK>S
zp*TYHuxO_~l_xiA1hj at 5TAXuM=jLl$YcTL*&5<}yXvK1dl+ at Pf!wJZm48CO}r~K8k
z`q!4Q5@!J=ee~<gWsMg5WZFrQU{4q6yL)YSt*>tn)A4YY)br-|s2?k7b>}&;UcOfs
zpNt9fTXpiz^Tuk#%KO{d`i at mFwhMf8)K7?Wzh1P2LUGIq7($KBJe5Z<ONXOz$9coK
zOl!BA_->0n&Y1B?vvX>-PhIwMq at 6Dzv`ym=>`-Ou<Py?j8Fd0zacp2fb+MAd&8#aq
zyMoq*lVOPy<1$d$>kqxA3N>tiXvUHyGmZ=`ox8F+wCu=5)gdO~GA$l%!?7(EuS<Yt
zG=LO3)k%WEjy1SItO`1tXl^Z`Do4X`*$6Cc4OLw|UdmTJKU!HmzXn|c at zs%}taCw`
zv$X{O-(@W;kGXZIv{~V%nUU(o=H$ki;RL4T4y(t}Co;Ox=;A7CUbiQ;udBlJx|tuX
zLY-hpr|RTe)yB85Vix)n+Z8D5hFm&6R6V{v8c(ndg*w`>>W9wIuH_#prwNG&muM)P
zX8s3-OJ(_kmu_65E!>P#|D=#2ht*>hLQpj|#}a8*-74CIRcg2a>-%`9A(}|)X;U5N
zoC2J6^S$PVTD`t<+6=WuBW-hQv4F&x&bj(=+!7ESj8&XW>owob!Z)8lcx%93J$*0l
z!%KN89v`xoXa{zI#lvVYd&ib0t0rVNA?D{Uu)GLY)7kr%wT<yLk=4;A^bnyciaQcq
zCG$iV$Jvu{=>z6k&75Pt=PAs}ORlfPcKf_|p($5r=~su}t7nak$P9!dt2!&+jj1eK
zY(m_s0?puplQ#h)sk+Dn9OujqnnVx2tO}NLNw-R-1MOVw%p+&RWj`s5!#ydUJxH={
zJj+<NonS(()qI-C-mzL;N|LONO{}$hm*KKDIlk63gV3zajWajlNU}CILEl71AJI(K
z2A#JFv+XI9aOr`EbIFZx&tmDISx<hi*=z!?_jnVtu@<Aks=_WYn5}0M;ZG#q3fJfv
zxoj=+If5=E9_`kLTN;ufo`#V at hj_Nx*#&Uk3i at 7+R5doS1`lG^g_5yQJsigR*BQ^&
z(ebqnkuV>b2&J{GCjapfUb4ZQ(5%fxH=u#68*N9e%C at j#F54mo!|XM@%bVTk({{2n
z(mX$7sXHp`wJuC{!BP at dvR+EU#t*byo`CHMJW=Y)1Rcq?J=1J9I&ac{uW at ggLtAvE
zt*$C1&KX&DUCzk5=G)K69pKq!XVvEq)T1Uhw<Ol!iFWNe^n07n*6B&jv1V<w70;?P
zo2||9^>IAL!4xf&*0P)NEpu6RhjCJOxNJlfX6=+^EK8pzgcE$6Y)umq$+r3}n_Y1~
z!LlXOSXWFry0~34<=D2ms>ZUPa;*CLf#v|**uh#As{?&n(Xp&cpJucR8ribfC9Ui*
z)@23lf_64;$%7EbU5>dZGoE#Jm8Tt>|DoOgfjaMa+^0+6f~!#plWiRta~)UF4{Chr
z<gD-0;_9urAzaJa&_mh8v-LaEZuX<uVX-U5bGo at MEN=FL!gj6WE`?UtO_k*-|C_VH
zGn%Xy<licnF01}dYwUl~Dqk~QWwq`c$1O<MRfjP|j+K>_y$Oky8f?$w1gN=etKWL0
zrym<-<=c4KbIY4F@`gjUMIFa|3$R9#b-h)M#cly>x0P(ZO^au3e_TB_(CHO;BOYsa
z!EJ4Ak<+D&<E&aHWvhz{sxS7l@@ahBS!EK*+BsvhYbwoQtg9UBf at -T8%WA_tR_vg_
zwr^*bv%#$0&CH~0Dzqc3UG8dERB=$MxFOuWh7Fdz*XdbwQT?_z+SQJBMeR;>bl|2~
zC!JUevUk6O%(|$uJF)zOxZD-hJ|WeqJE(Q(*j-iW?X&8lI`7zU_Ep~AZWq+}M0q(b
zju&8Lmyd~M?W}Fqy6Vezot0^@3)UO9Nwj-c7P#xpWxuwn!oJgJQ)@UL#m at c&)~n7a
z3!lxS>Z(cDfyqaop)gMR`jM(+kqKs9%h<RbO~?jfT?EZ%>p%8$%9dBLDO}c$I!$I-
zxf8et5U&u*t8sddfouzOLRtG;g<N>8;mC!3Bpu4Oo~y70m_?EO@@XZpk?aeiw;4O~
zu*#8^M^@b(@6bq#$bJv2EzGW&tPGEH)DJeM$c75L!T at AnJIH};Ds{me(kjQ~kW~>d
z71$n|H@*0}UVAj_&V-!oqF6bl6~}<tS6XK|={<QS8?zaguL^v_i+A>Gxmi^-roz<d
z%q+hi#$8qco#mC~%!YT8S%ggIyUgwO_Oo*sb0l_($7Ilu$+`>6J}NA^8o7T0Cwc6u
zGO=t;!&TXmWtOxO=}MbjWh?u;rtF)1YrSS8Za4DB)0PIZb&|U(j44^!q at H9jA6e#g
zB+oY6DooPy+=$!Mte)Wnvd#c?CNG`pNAhOzV{ZAkm;8X)@oxIpy?L75c&+NZoSkRP
z7yGg<F=n2|SZgF??Rmia4&RicGr|8hf4**+b&jZNM~SU2CGUB(7yNL!bzaLqY$-d>
zw=4QnP^NRdN*Tpt2K1_i2K$|a)U{kk!fY!#i0c?$HX7U33n&S^){0l-IMsG4#cPLH
z3N2HPcPGv3RjI4Zj2A1dEhS58m+)&ANN!#Nx2J)O1i{Gq>e^ZrS??%krb<JSDh<vp
zrWq>E`v6PFrah3%(6n~7n=5>?e#=lwJ;vbs^__b*j^hPuW1gZF`L9tm&*wz-8><h`
z at toT-GTfWU`)3i{laDIH;WfDAH&k?05T_!$L6FoL?cDFGD(G3(u~)<q`?^Gt^{GVB
zD4N%fcAjc1i-fJxF at 7yVzAT~iXE@{~rsib44&UGiCFK(%=+3K~!1F4oxGvUG(-2XO
zk;Ym)`2>-sz|%`cL7EK32X}N7l*;(N2$eKxvZApDe&8p*p+3%gHuEP?b4`4CcygpE
zjBG;D`nfCgXB8H;M$zmd7EK!KM6)(3S*?i+Ni;Vx!9*lzu8FVf&^9|2m8oDUe}j37
znZ%f%KsMR2=azNInIaim$AaLpPw|ned^d==&EORf_OVH*a`QzQb|pf%?Ep;P_C{=M
z5HZjR<E+M!76PJLaA0~;No2nqu2U12<Th at l$}pBDhYr4WgsF_C?TFa7W0q4|QLHhu
zRJv45J7x>DKXz1-GFI=%ki4BABX)L-q;j*;NM?2-JC at 4IPKKP&>rpPgS|7)U&p3!Q
z!ep8Q!*4<8devNAv=#C7EwLnC7im-tI^JL?MpL~qLk4^ld-w54D<1G>zx0JV-6inG
zltk-wv|iOW#PkS)uF;X9B1uKH#l%}+3*U)?k{oOG9l82=1fx{*as81Y6|UiT0&q&)
z5KSsMgsREnsxs1qdjW}!i6qKkNKFE_C~McK^$DiJ5E>h<No;_Tgldq39EqdM8#X8$
zrT9t;uNpCan{Z6V+G<sso(w^gvBnyp3Bn1)!62p%o;x3ls!&2x+_}M9oA^ROeM5LP
zK2T5}#gr4O!CVze)U<%$-Ch9ty`hGhdd<|vV(X%SYa3#eqSUO_NMxO=$E(cFrj5zm
z#<Q{RGk8A~=V}#dsZk+(Y%-3m3EGtvz~D)XWZERh2I$l at tkYS-5XW)7&a%F~0Xwnr
zl6aDuAg!eJ&3K0<37V)4Hvw)k at q|S+-fHQE at DT`ky*iW(uU4y@@jzH-Vskk8#nC_7
zLgDyogh&`&4<De!chq#O)nwJ0FsAK1Tdhp%(dM;^#{?W~0UsjKkpz1Lx02(~f)9{U
zQ`cs_t|*H@#Fxb39xE9ImRK^v9vR`s1NEytnAuc4Pc`^D7e11v at bwy!P(5C+X~I|G
zc*G|HBRXm*MiWo+cxR8F4oo&SOD6zDT>RslDE?c8l<GB=O5dp<Wok8GXywFcBHYl_
z(il~SLBAHPc}-YjU^G^P&)TgcCXB{vo09PcV!~*wF1i|T#RC&YWB4#o^BQ8pXbkNY
zi4zk>W8xPvVGP#Ngs&PABcrhd-oJ|w6Gme#c#TBt2?K0WG_k>UMsw7}grRdbjK)mr
zWK5?<TVYL;n)^%~!xeK%+R#Zs;P8#Ev{WgCbEeF);#Zqp>6+8tf;ZK!IfL32-)7Z3
zO4epqz2=OrUEVgU_Ni-Ezvhgt-2iP?3sBc?0?ip+se4v<o7D=`wVOe6M%QkLHmfBj
zLpRkFhBew!MbWi1Ei9)*{i(A_m=f)#O8E%XZY+}n=T2!DCT0W4gvv`DM-y_6wV)38
zNh)N}`50XI!%T at 4XJe=_+C;J at hKY~Sy6{G!F at ZPYoWN+Cfj1h8?w?3fu(}bayn1q*
zV)#I3y{=Xa{WdfGSwO2TYBjBZxzQ*=W({h?aHhg}M2McG7{lmpL#!=Y7vWR at h=`fA
zK;`sOr%AmgIGGCCV2GhOnF`F4DHtwdL1Zz at C{D!^)s(AOqCATWtmF17ma<OPrfqGK
z5^G1UNuk*3nzU`vJkhn+q)_g3O{&exniO^?Kov`b4wt%?S;(~uU$f+HYim?(X3fnq
zajgr=^Ez|TF)n9CiIqTQRvoC!-eh=!3_-s>8O20yGuFZ&8I$z at Z@;1&$MvECi)3j&
zP`z9bK-LQa$r(x(6{^+r5JRK`aOQ8dI+{fn at ie?tKX;mJN0!XX>RE2JTB^TQiu&Xy
zOOtD&{OGX$^)S?>%r~1Yfl|eW9g$M8*eN!&bh=?@q#(oD#QGHNk+w>^ypA!VXy+=;
zMzpbWmF-4kJ|~QC-L}hUw^1=)2&Rg~UT+(=95w(xn(K27>)pqb)4QPGz}~MPKfvem
z<D0tfp(>~Mw7figZZ~JLD+gZ#&m}p-H9#qk+chCCr*~f7l)MA*b?$D1)Z9LkpxAvM
zq?y}?=s^Rf4j7b=FZcF^ET^|t?2(dFy=R{^GkN<!m5P-0>Ia#X!9J;Uv>VK$<=z3f
zL-nZx4jKTrgGiO{fr)YOu%Ml=7O0P6rThU`Q*WJiZXZYLJ}KOR7N$^JTdATHYIK$A
zTOnmts$V4-`q;k$6 at pK(_W_v-2lk~Pr#D3dQ)QZzN8bl!xUAHEMjIcF9;~aFdPCgC
zSh1t}fbVa6lxKTXV%I(tN>d7sf(#8PQyF;<beLD6YV-P|w#xFQ(uS7_DK8K*q72<<
zq|3$X9JN27iO66yyG&l*G_Yf4idw*w$!WR*g;$m7zM%P(s$zMh$zdR9S5F?h!`J{!
z(<6tE<1FKLamQO)204wLbwUyHo0y?1l1WA4|73n;dWu#1jtma4Dp;wh+8w%bpxrYO
znHIq4 at pqfvf71Y~7Ns*Pb&yB7`&m9KHGPgczR!>Ged-xjin>0V1{{Lwo2eCbznw+3
z6X~`(6yI;p1;rSW&syiIN{J~o*-#RWYxglcxN`V8?p#hXp4>(p`@8;B(CyMfaNUoG
zg=<SO)c@{wc?(b>TLHMPc6T3-Z*7a<9k;8;3`Eu<Yga*z>gidD;`MiR%gH+j7F^yO
z)yvZ#q{lJ9A0gB;NA)-nk^eH1hsa%s%%|aA{2qBvPn}r!v%AMSFe|9_x?A;#TamxG
zy*)M|@*yQ}xC at l`GdSB5pZIp|arg9`DyjeJ&hydaM{eZr0+IB=p at 2Stu}h&eo$^nS
zOsq|&=rgxVd2c|0Ps3NiU01-`ePYd()8k<<^Qn^qC--?3ol(l)C&%@b^>g)p1F)+o
z$Cdw6XsQB<_BT=AEyTQA`m&y(cBNaZ53%I;QLeFKC#Dl>!B9)^Xi9ms6LTt0vjk6~
zL_SueF+aVXz;{~8-b_o%6h795NjAq4&{MIe5013++N(IEwU+dPl+lP2Gj4P*K>e&S
z0_874w2jcZoVVD@`M;*K-hzQjolE#~xBqvbgM8o{bDn}wH-JxS)L#Z%WGzmaRG`1n
zl5KFx#6AD7EZHWf>^bJ`-v|F?LTn!El(9!C|6<5?BDl8ZT!_A6I)k?e?p{v#9=HEz
zmdduA`$a{UXkVy!FtlCwy8QvrB>8ilR{R?*_<Uzd|HFX27zM7KIeEDtx&wNLz+gV%
z``!M<prUeVPC!(2o<pH>2~{3&``-qw#3*-N?zG|`4 at lrEohki42K*~(Uz_I2(}4P-
zle?}@g9ietCwya?ktRU*5WXc1eh`qSAK=?_WCGAl?(Yd`8R0wA;G+PYz<RtZ4ZaTW
zN7TOC3HSLopo9AZzTfJ4($S^y`YeDzgbz4{s?P<$Ut^*N)A6@}&EVYkP&$4DFwy_H
z!Bw9t0DVZ+M{P*$i~k#d;QBuc at -Ia6LPEdF8HwIxI=lZeKz||pcn<%uiH7x<_P&BH
z`4k7nb#DKAmfjON1F#x117QU$DevphJBNDLy8TsX_BI69Z`#@OZ?a at hwX@-W7_#nz
zknXq6j;{xrAGpZ=;FReBv%-?S?3C#NbEzeJ#VON+ at KeZU?T7qcbINpnhXNPb-!o;Y
z$w~QlT3R1Fwdj?uKL1}Wg-<dSl)rMY$>LL|jMeGW{bdsro=0$fp4R^Ux2=Q&a~%_s
zl&R00AxiB)a1G8i?W1k&0`@lXVuLIHhloxo2DE=}syUT^Iv{~da#OuQ`Og6S47E$s
zv|q5`p=sLt?T^zof~&&mqORKYmMrL$={fU3OE$qNV>)NG_bM^g4{~Zbs(po}Fg;U2
z`LD8MGn}$iwfo<*6b^SP=q at uKCzp#6Tq~V2NvsQZg{9Ecp at Op%|Fl$N?Nl8_nTE1U
zj?EovDgT+4!uoa!jzYa)X~lC>Ck`J^5W2JZ#|<<2B-<%C%<QnV&S<BlE2sw+;Y$!)
zXLaa}@~^NIwq;sS{<|#MIhiu?6ld$<N<|P{J36#(PRfmz)~?RAoDK1?rGH(=`i|D<
zU2YuM)48hhA8lz}-?5gXLa(<}Z*ZzgyU0QJs)7+F+j~0Ja(LKksovMQs`CHQ(t4m{
zEr*8(;Zz}Y{#eJVy4~-ER?aB2%oDjxYtA8iGX|~~8cV75o7 at 9ZT9O$Ls?SOYpXEaL
zx7PH<8BY1H2L2uszLd+dT4%10039$I at t4!!>4459{Ce&#S4w*~p!W#B>GaW_TreYA
z3hz4=?8-HB`m`~|%m*E6VXCwg{^?ZUJZvmH2ZiDQ9QoL(;Bcf2LQ(jyQz6rlgr%iC
zjykusl>cE%!R1tNIMSm+sbdgaxlRR#BTbe<Z>NHtg(=T3Ev<qMwUmEArOC(dRB$-b
z0EJ&5xQd(#4o7}#DGYHcWI8gm%9z=|LoMasU at 4S36&#K{0fk{fI8x?Ra5yp%LQ$x6
zDr7oxj-?gsP)qs$ZYhj&DmWaOF&1lQ1lL5Tg2Ry;Erl6Qg-l00<BXYE9cn56Dodf-
zso-$r4k)<C!;v|jR(t4~nYJfzk*#vd?D1^0j<U3V)VY>(KEBz~U*ptg$&~*~OBQv?
zQaNg^Lnj!&)^@IC`tHS0eFwpHs>iV=?(-R-g%bgv?lBiU{xG696WZd`EW8(xdlKNC
zo_FA)zB(%G2}ICKJ-jy8*BC|1fnHDDJ3XSOeJH#iQ2u1VKa(~v%EdquL?262J_*o^
zgdcY*{|(6aDL{YYR4$qh=v>0jIN`!80DVmOd8dsW%*iVeTrV2s4>>0nHUfH- at XH<o
zrhvb<&_8*K{Z;|J%lj(zup7G9y9*npA{~P3HD|gPE%XgXy26SBag~MO+UwLk+d|)V
z=oY;Obi_31zNg((g_VdMPvi?Jj;__BEkIr(n%hlRcE;E!`m?3bEmJ`ijXKCA_8Qp=
z6kRWsidrCh48b+XDHDYb4yx!G=vGaK{@`z;?~^WEbO;jcWTH|>B2}~pP|gg%Wd`Pq
zpo;nd5_psY_TAf`vh9{^wo~RCKv|EON*#;fnrmb{-TJib3`;iODbqH;glzdNq&wUp
zQ$<lg0{_SX8#i9JWD%!KXLaOkT&W|tqFSbko<ppv8pv9s&6-txdB<o0;J)F3XoEw*
z at SfMxV3fymAC4~9I(MHJz!c$h>pIfy&c75%RG*QEt|he6g8IpD$1TAN2)qC0DST8I
zjN2aFc-PPOU!?T$&ZP1lhg^6U(EYB*zRTu*+v9bkhI!x8{h_BYoJ%|4du1f|O%)qe
z(7h5m?tgfSZu4N7oCDt1O=lw+N?wH at L&iG}?rGf!`0|IsgTi1prOrlh&+3+Iqy9UA
z^z9DxddV{<<+Eg}tKNSBG(_vBj<uu_{PVp^-GJbJQS!}^#5#BX-InZSBV!UHE9!wu
ze+2iR#j~_ at _gS(xj4YK-TJ8|khj$s;l9Pt}JrA1056<Pz&6T#EgNP{JfeP_H*ALx<
zHPbB@%{^ZfKknB1Xr}dacjez+ikkA*BYFm*yzY;n*<ATQ1MK?^SmnJ3thD3j-Mo*1
z=Pe8Om)-oASZVg@{&6aeLVn82JDlR)7u~!sfamQH_rJUO{{$-SU10KI_P&>S*u{i>
zM&+1B?q_`S(I3&kc^5)y<pJH9M0=_FoB{X-1osMO8r|_(8Q#56mLB)7Zm5HSP<6Q<
zbN3h7XOM}fPvCjX&mijQ`K>5?n$x~Eb^rI$C8^WTM88lv@%CK1b^7L@`yBz)=$~k{
z!MV9Gf0w9N=k{gAevF8nPSllm13JB!pF{P}Mg7T~!UFX10}<SR%=r;Cd_9MzwGM6$
zoeimN)ytCYqW*Jy48VWq>&m^~wJ(S8nTV*qYhh&vlW>N(2#nlnXU@=5-d{qzKSn|B
zXxw)n1;&+I=<Yrj%mCz^+t=+XJPeVIRN2 at 4PiW^47MGX<Z`kMdbN40BdX{X at 1qj3Y
zVH|u$`4||^!6?ZztO`qj8pDS|JHPy!4Rba-xF?=<xUckf>%K4Y?Y50a|Bd^gh`mt{
zd%d#&xbiQcG5;Vy0>9&p2z-garvd(u+8=m->Cpb%f<N)@O=<Uu<m+oM_ZMDm*LMxA
z^gRxT-$N!%`!X1`z;oi<a__*!c}h{i-R4y}gMNjW`zUYz3MMRk6|p6~fW*aFje1u>
zCd2LsZ{Z3^MI$MG=Ql8&w+2TUWGlRqIqQ5su05ZHx~~1-lY<|7L0#@+y at PogupBti
zoBv}PD%>BnCFXZZ`8Dc25i)V$$KJwvOXCu$iu|oi=jCGsao{+w6gtfT-RtOpOAXmo
zfQO%Zu>KiR*awGVoHmBsjzdq+7_NNWKF2iH at epx&IpN3<>65F9J<F<*&hxAN>p^)3
z&GU@!1GwY+gr1eKcb^4`=kd}DLGB^@Ec>PJ1WclGP^I?+eVLNyGbMil%JsVEMOLTp
zEBnA%MU{3xSl<Ho{DE;1tJ2W`dDZOsW4gNbsB{^`n-Dy&<PJj`If$Y*c|1hCFW`B#
zL-92bODW$-i6w6qN0mMa at jqyM@5zH;oCj4x*Z)QEiBfe4p7<ho-jd>rymTUfV+j6T
z5@|~f04^Z-uGC4&+|Vn5{(_SC3EC?RHLP1z50q$Fw;&xF)@@=TW8T>k^H!Hh?BJO~
z4p}8+PD04svxOXbwUBua3z`42kOdzIS(sNwV~6c8WYJV1i;ohrq(#WmEkc%EBV_r*
zLJogH$cldmS?L*0D at PRzIeI)vuZs>AvU7!yi`NRdq(#VOrwQ40u8_;G7P9+pAy at ud
z$W_k^x%yQh*Ssy{x{rnI`AW$3J<FNVPm6 at ySS;kGQ9^E>Amo-ALT;Nc<n|+k+)*Rs
z&PE}3ZxC|N*+TByDdhgEN%pOkO5V5b7Kue(60+Kbn^wd2jgAzucBYVZONBJn35m4`
zY2G1Z{ar%hPYOxy71HWL2N<^RhCxDpJW<GTGld*~n2-}9LVgk#a^gusPTeWw%-uq^
z+#_V`FNK`VAvkQ`ZGRE6<6lC~uR^yUw(kWCgj`r7WM at LiB_|8HbeE7_cM944gpey<
z6LMvDjJaX^UbUZ)t0$2ZH?9)W^b~F&4J(dGEfudH8DK0vT}WcFkYufpmXn0EUM!^T
zHX$3H7P9fLLN@(d$g%Tr6K7cQ<~2foe6o<^t`TzlBSKDiR>)7 at 6>_2*w`7JDpEO9w
z$zz0^GE2y*M+!M at qma`t6LQAALe6|%$d-?UY|Z5jm*TU0Le3s6WLt%h?bC&vw?N2_
z)k4lcRmcSw3c2tmAs5{%<kH85?E0OM-G3Ew#lM7H(>utFt}PaFU6qhMGf7HUuMo1P
zQAqSeA!{!bvhGG94L=vs_<JEu?+A%0+=Cfb+T2&j`q4t-Gle8p2uU`P44Zbckb^E3
zGW}K|GoBSPbFYwDUkaIBfcq`OhE)#}a_|%(ha4tkPMwgs8-*Ntwvc&O37LPdkOfZ(
zS@<_0hkYhw(LR{-hYed?B4o)VlF==5g|td18r`--VjINI(Ho_ojowr;fttro7P5Jf
zkRLY)Iqoze$6qJpgolLu<PSnl{8-3Io{3C;a<Pz8CI~rozL3*ugq)rba>f}#&b(a6
zmivWleMZPxdxdOsO`@@L1_?QDqLA~K2)SU5kPA-|a?ws9JMR>7 at e@KWc}>WrUkbUb
z?_?U=RVn21Lxt?F6LQ6ILaw|_$W?a;x%!tvu6bF=wVw#Nu3!qS>=`BG`h$i1G%VzX
zZ9;C`E##)#gxvfaA-B9M<knsXF!^o6h1@=0$X)A&+`U=IJ?9E};A$a1yGzJ}PlA*n
zs9wu)k^Gz*@<Bc#Wmn)dHJp2EhOa=>JqxR*Zmu#ejLNudDEm3(jFwCE8Ai#KlXG5I
zl<>)vI|nE3fV&4scW>E$fQ%^Tg{OOAF3y$S@*DaiWg$+*!-)>Zl&8u{8Rb&DYz#TB
zjooMG!MJNAZzztc2HH=JzJgHqk at Qla9970OZaLSH<*S*JT-kbZ6u6)2g)DQ+xCAbj
z0<b7$=TJ_pj2nc?b~8$@T%xR>@;iy~5kUDv<cN*op^VXT;a;SG-j$OpCs!s>Nyf!P
z`4?0nS4OUkTnVp={%{DYsI+7V&ggG|?Ox#i2S{!~;7gDmb7lbd$$?idK8`b05pd6e
zY;H%gKu?Me<1*1FhbNgL;3K*`9o5DH11Or8E>eMFqD#|Jlc1cULuBnIKBXKBR8X`)
zM9kNxGoL_oSvqQLO`~XGx<~~MCVCXhnks`%P`MDI^$0y{Ql*#VQZtnsAi9|11u54l
zR)H&k_E;n~Q?6BB5A<p3FH7l*)0Mvm`Z*;>r6k&tYc4FU$h71IIvSy8G^MYLKbHC{
zGtntT5ACQBr86L!NAY4wq;p+HV2PcpDp@>SsiOeq4R+UnbaR!|0%-!f&tP{eh{r9f
z+|6Kn4=y<Y!jr+~4|Z>*&|4Bjy<7~oU`WYj5MBw^H^hAdNOyP1EkN!E>mTBNlt^yL
z&w)Gxw$BjvABcEMxJLW{Y~g+-TqpjA?BEiv74r at SJEVl`#Q|iCOSonnPImtit{cab
zEh*vJaW>h~60RSYk{v2`Ysi+1-6pal#O|?VM~dCk$&M1c=aU^RcCREmM(o~7HXwE%
zB3n^%Qn^yU0o%7&M&1ixi>hRv`Wx7Og9ZI3*#5<WegSqsamoEimOBp{TMw`Dcn2;G
z_5{y18MsUZ^DTaPt}1y0ihZbfRF$V-;0jUX5FdD?Ruq1vSC#Y{fh$ldhN<`?QDplJ
z3~5E-kMXKN36)Mg0P1=uxrYPD^#%gOPoooNh>az1Ix{f9Bm!G#NCTzQ031y48rz(2
z8w{&5cCyk15G|+p+MBK1wAg(#(A?ZW4TaZpni7Lr7+6d6Iy+xMeY(T0r|3r81E**s
zMYr$-k+Nk{{e+_1+1D~fW6z}MN*W)xjqKGvc2X5MACW;LWF*P(;6aVMl;}vAIx+Ye
zDYsQrU=M*&snI8C#@`Bb;7NhINlua4y=^3G=x!V*Oni{=Ioi*OzhLAs<Mgi?IZp<w
z4EfUE0(g<&Lyk6jmB3k&XZpM;Q=4zlC}y=kj*}#jt)s^6Wy;<9G+-A|C#ZZEvQH59
zYnH0!K?Oc%f*sN<JgC5b30#!YsLY*@Spi|c7G4nfQj&ll=)m)Nwd8Xc=tp#CrtW at 3
zFSW~PCiPOHy9E7ml+}<@!)0nT&cq`j_v8kGRC`p^r0OVBfyqQKlTv0R4$P$J7b21b
zOOZflS+)Y~a2hCCgTuV}*jRp9v1bwJMT3tEt^lpU)z0AKRq!bA%yaMw-r$cc{wKYH
zVep(l2cK9FTx0Pk`GZa1S2OL&{e!1i`lpl!&j!!79DI6Z at B;9BUO)JZNx{p&?<9Zb
z^x#$C?;yWrPVjN??~~uUDEJI`vAJzU at OR+7xOf`8eNFI9 at Z#G!&B3?8`-$&J2Hyui
znEd%|!H>a9+KV;>KeO~NIX&oFfZI*9f9ZBr#;Lv76Nk89 at X^7Ipi=x*DtNq=<VRjr
zb~f~NXJbiJ*{-y>KKIfeRdz2WG_O0Ma3U#r3E=fGI(Tu(8(?n*JLC{K+dK at mC{Xqh
zlTueFm6NYFx(|vp;E&K6Nq@~MF2%c4pvMB-aor|~4}h{N<0VC)fatj?bX-3IxBI9f
zPOHFRB6rv-siK%JT1NRLDLK8GtO5bTS7gFd#uHxX5?p$o^g)wm8ijYJWClK%@Ld8+
zkqx|nu$~pfU6J*}wXiB1gyR98!=ccBY8{R;yG?B}T<+8j;Mh*ysb?ClKux&_?EZ&o
z*D?%F*-hCJEwg>_NoG^_P`0?EB58%d?NoRqy;w%{07d7CNLnTEa{}i}&B(za`V~cb
zhDf2MPXYZMC6@^(&S_IG6TLR28u&AT8w7BmZxVel6Mcv1E@>Q at W`&c37%%-N<eyXL
z8UgKvtDb<h18O1UJM64{ci;|#Dr1Kacqx(-knU<SJyKHzdQ)^&D%IPP>U|uCOVYlS
zUo8nFn{k5(+$wg|xKc*W){($yMz-6gRG^B$IVoV=Bm&o)^ZG%E986#*4eOI8>r<7^
z2fCb+%hM$$pH&pyEM`SNP)Fbv8_ at R0t|NLkEd&x|e`Ytc8oP<WbxaXBk?fw7EN~iu
z+iYu-)s(Y{EOK;5>4||Ign#N#3|vCwMnQN`fvX7IWUJuxP2gc0(EYOXR-ivaDEVC~
zZRsxoJVWqh2lx_zHwnJx0N(}h8Ns~{P#uOVWQ3CU9AF`UVuBwzz;XcN2!8GWrvjKm
z at T(M9xCp?}1U<SkC{l%WK$?l>InfP3PA2MeqFaINB--DJUJ2x8qC=hN-9Uapbfg0<
z*@pW>PXHZSEEfsSf-Pz;xd!O#V25k;9k691N*)0EU$EuHC69saz6j_jxk4BKwrEW0
zP>?Ew5o4v4y#1p}rvNyF;A9852*4_YkwFJo4<JF!gB;*y0A~=K=K#+Ia5=%n4sZ{E
zy9gfP03QPIB*9e<@OJ=SCs^wM{|?|^1fvd6EyiUO!ibmy><eHh!4?M?05FwcwGH}s
zXHEsGiC#wD4AuDnjwE<2YsjaosRlrd;7?LuU;}`W8*RYHJAN2rM2{t}4VEm!?Y1)k
zjw&t*f!zVNXmQC}u-B12>_E>6Me~DqfIl5r(E=5G2t3z%Md;@vZ@@GmXWbL9Sok$0
zlg7*oJ_*W_jG3>3&sqF}+~6N9exWz`y2T&XEBLm>FDeLrVDXC!gP&RalKw%p#MoRq
zDCo8LWyL`sc+QDqmX`+yg6H%x=I}}tC`BZ&S}IiLF0S-&dLB)9O*?oT;e^1lWR%I>
zBsq|>*7PLiG<FC at 8#+j4<cld!ik!xL#^RBL^?YUfW>VBpq$e&rg%Pczs76|psZ=0N
zpjP~qgYBXUY^118bh)H8^YsZtBPn;ZnbU~Y+lkEu$yr3Bj at -^8us+k|PNFS>I&`lf
zx?Qdkr4)DJ)~PC^lYu=H-6B_rDN*1SqPNMVp#!~#=y`I=vr*&TLloU9*BqIm$0#~q
zE)6q9Pg8WaTpDJIUZm)RRAo}G0<RK1Egd!Mzr7S~P8X at bdqhu3M@@oHC^{}x`#Ohz
z6Foi?&0Pxg)O6IC=|$1m(m^E~DF~ygvJj#P2o+mX4#*`@<$*wJC^;`Bk^C#y0zHe8
zi&GMv=6s;{QF28}qSHJA^i4|kq$JYK#Erna5Cwi>4<YIGD)2GUlWkN5z9g{K28^0}
z8PIc5cBOdIe*!%yy0F7a at lkY9Mk?*i0E%{YC at P^SqujcdOGiR9j^Y!=K}nu+^^_^>
z&u8K|oX;x)2U0UE1Ay+Sz$^m#s)MKs%q7qyzW+iJ|B8wE=p(S0qIF_iR<XkUO_W5w
zg7Sux8yQN0V<<mX<g$2 at mXP#;H5AF?IiHl^5Zr2(0{XOlnhM~<ekyQgDt$wS5?f&G
zW-6^^Spuh!)vG>f9K8lRi>O|u6U9`!gGgK|MLJaAG6I`Y?WYr7OH^M+>4eizU-HBK
zZRI-rUdV4osLa9kMO^hSCp!*%FQ at mx)`lLUiNlOy!}0Eg>+q3~{W2GC5OZMkL7Hhy
zaTw6vMsL<n5Seuc4r&I at -SW%F(RFw|uzwdIZ3Ciq+P?x#<#vqd<6fwwxCpY7d`Pja
z^Ayb{1=Nto6G(A5Q{3KpitQ#vPf77_q__}|6=uF*Qp`e$X656cX6(j+Kl<l7ybRc3
z`$F?GMCtz=DwR*harl|24|(b!&ne{D2INa;%)#>psTx*KF9iOGxl}jd at f1hpAn-+C
z)T>bP9`MwllT1g9zkR^J_TFWiZ$EX<`)AE-&fj!)bNO#B|MTu)??3d)ojo60xP8mq
z!_R(Y`*B-WwtaEcNAL6=lYDPP at tep0v}(|wzW6oLzJ%}=0?WXcy!#`RBTPb|vnvqR
zAZ$Q59pNGbd7BdY>=^v<4NJgwoLiF^XH)XW?MlwL?0p6<odT3Qttn@>;g8#d7?(;1
z<rZkh*^~H_UD=?PzHE<1+>$TJNY8G~^nb#L<Bwh48Rvd%#w~xWb|S`KW;?OoEgiNM
zLq|GH%l1qzJw31ahST$&xcXfGY{ZehszZn(Fb_OEm0tu$#;bHxaZ4ZLH}unhl_%U)
z?B<0Umi*a&a+F8qsyyi%6frIHxB3qKX4hpOV!z>_@*@->FpEJ5gAu4#3|fLP6oEq>
zHyIV~ttzZ76t1x4Ljd%Xv+g(q`h;du90HtKW+Jexv{h~B!JvmA%r)@^pobyg1SNH{
z0`zEvRS02(T7-H8*3&wKCWIKmjL`3&KCx=imN!0G<G$qeWuEi4Y&jwKK-aXEaeWWE
z=Jt~}-*oH?U;e6~@9S&+GOWH}(cPCU`uV5-nOyhpts{<|dd0qf>37iDi>^Io<lA#D
z|FV33{&^ohGcd7s^+O;3xn<<lm)tt;g<D=7xoYc0!Kcofdi#UtKl#yvo5z1S_=BY@
zU!A=A?OP7|bYlL&drtZJMK8 at b=Z#-)Svh^kuuZF88(CX?{^mc{oO;&M51QZI9BBD$
z)muw_|Jn5Z|6TCvS0hhbJRt9$(M1PUo^X0zLFrjL7v28iOFbTcV5|Fr<-Wg{gf<U+
z>iOJ%-*Vod8 at FF`%GM?KT~#=%=(_jzf4BFw8;?|n7Y2L_53QbFHsaX_`tAACNbk~$
z0UwO;R}}PWy|ehJ13$0&d7gXm+9!wqeO~b1y4Rnc`RVI}j=B7`CBETn%lF*+_?wHT
zPhPymyK&96dydV!ZEeZBz0bY(mZN4p{!`Z_udmO)Vbkp7QHiauT)O(QjW3-4#-InU
zoHXLEdzWk(v*(=qr=5R)|G~H9PXGPu$8Eaycizjo_kSQzaL at yNiwC~D?X3^yUcURf
zCqI97<yZThbH|R&U#z-m#O<M)arf_desyBZxtk7{v*wgOiyGg3WykhQe{;lVm%s4A
z%7U|Y&AWX3SIz&bAM{8;_Xl at vK0OzA9}yl!coX4Y2tCnB_d}>en1ygSLKI;$!Zw5}
z5$;0xHNqbe-bZj at LM%iWjxYsb0m3l|34~J-b|Tz}@G!!22!BQR3?Z*O`Z+=s!fb>i
z5Y{667-2iYRS0(@JdW at R!aoq)UW^lja)bjA79xZZk_e|ET#RrN!V3uhK`6jLD at B-q
zFc)Dx!pR61BK#ELL4;=z-az;ip$7)#AcP8pnFvQC#1KwII3HmT!UG6TBfO6AF+%q|
zJe)!pgD at RoDMCHMMue>hmm}Pc at P7y|A-sd|Uj!c}tDy)J5e`L&Bb<V85yA}!4<T^x
z<(mlqLg<OfVn2jRgjopOkBlah?`dG_=dN`S?i2>$?q(4F_?VG%5Vx2ah<j@}T}}rM
zh&yjVxKGw7$PQyD<U`U26hA(HqZvNZFj}%{98eA7MvD(8sm0A|MvD&@2=P|5f%rU>
z5U)*!g5q~BmLP=Q!c=Lr_(+owx4IdKkNOGm+Q}s3y>vpnZD_Rk%#slIx*13|h5{Oa
zWtMT34^OGZ4RuC~k3b1=%bbDue3%d)*cyn>HVJW`oPoG+gAmu12I7NWLfqhIAl?%q
z#9JH&;<i#k+}>ayKC>mnJ$(k^16xAe*k>R<WG2L$-lit5L~kI(7axokH<A$I^`X&{
z4g7$(rGuv>{A7bT=(JR8%XcjRT?hll79R at J7B><aNVZ-B;+_*ztK1_>E!oxyiXU&A
z36v@}A4U`6hDBqGJ7);-CW~>E51a|{IkeH at BN{?{qGNL8tvEuwLua)3Af6B(mmBCl
zL<w=Ljwv?p%Ms%3I-|v>(S-Ok&p_ji6WoPqAnuHz78m!%RX&9v#Ag!5FL?<7(5)De
z2I8}FYH{18vBez%g!nk$K=OSLK>Y59fw*shTHHZkAZ|k<#5Jyg_%NRkH+~w3FDAf@
z;@e_?_@)^CxcM1>d|?8FKW@#Y9=}Ndi0^ISkGtJLxQ!izKYl%jS at 7#Vrck^QMu^vj
z25Ll<5LbGpvbke`5I3G0TYM#id47lhh%e)SJc58fzMufYANMmbDfhY>h&v+)afhsd
zxHE$gH%=Ic`!)#i#>r4n{J0;05bxF)NcMgM;>%6Of4*BlExtEnZ1G+pA>KkXkh~B9
z=#<p3k(V3*aXXf=b)|8FyEsfjel3XA!p%;AxRuLD`1%2J;btmRaoie0h+Bh=7H?q^
z;svvT-Z(@<+%9dPm8PkVgQoFCUR*(R8yeo2m%aRi(8flK8yIMwx2;Sa at zEq9KCv|B
zxu1*>x0e|$-u@=UyW&R61Dk~STD^g4Ooebij!DQpFVy0`XQRbu-h_BDZM69M10n8C
zGp=&S2_bG^HVGG*gnX`Tw0LuuTD<3Lw783m5I36}NWPf^h~LsN5O>{Ci#O$r6Wkp{
zh`V--7B|}w;zL=ZC2zL at dLDh+IB^W3)EbFkwD`6|E~5P62W{!$$ahH)+nXA6++xI}
z+;wD<@}UDE-rP2B at H1J2{)=Gp<l_cHd<tQ-_$e+zkEFEZ?IT2AOHEX};1RX>B9TeR
z9a4n&%-=Y{?NNldZOLfeYHFWPxec^`cdf;D7!AZ1FEG(4zTk&HzF`K!*ZM&C#vTZ_
zI)d;uH4x_y2!G5u?N at AK@CHIxJ2@&te)*cTlOLmTxgZ1EPTp+fK26)nw;MUSDSz$c
zy9L(wEjp5;ugK4}X^C=eC~y_@>h9eRE39o^6drQ~FXO)Y%9I~x&)x;6x at Yafn&gjq
zvk_JpJ=TN#EWMd0q29G#1E^)s)JKQ*c0g~AvG;X)KZ9PS(KGeap}jYuS8nu7J$0zp
z3*{~_dOeUvepWe5bUO;3tK2xcT&^#B??b{$M{rflXl`zZ)`pYOSW}{6MQyAu5(qap
zSImkv;S1}@M8)h#Yor06xsF#Xi^Ur7h3crKH#<@vZfQscHsA~CMpDs|h*#7^n<@f<
zifB`9LrYzxqIT4%iq<Oi17y??t*NNRH?LP$R8<8k17oc$ze`?=8p6r?SiCV&u^?P~
z*wPh&W&=11zI66HTb!s{CxtYn`yXaifsfo*$ba!j{4aC;-{%+|J88oIvV`Ve4t$3W
znq{Y9OX9L$e|{H(5MLaQ#W!*|CX#h^k@~<IE;{t5%Jn}wfe4 at Xw-exB5KxaP2$K)-
ze><3ed!o}rNxttZX2}7 at w5Cz;OpMP9;~!%nl8f^d3?Xje{GSzCKrMb4Jr(1BtuQfu
zHC>y)nJ~ndNoYk)N-JuTBC4~4891do8F<W5_J6T(<RJgc!o-n<{2vQMEu)S&OM!X8
zR3<p6F$3Mmh~OlvRlu_f=tj&avC0$Ry{0x|#*D2XA3oR0wfZCIG@(B|516%RK8{Y@
zGROSQXV0bH=(bkNh-%APq<QO$=T?2gJiinT>-;per4J~bg}go%s|wUM%egojOVqd3
zF_p@#R6Wd!7I&jO!+Xy2<aAq+>++~>Ik$B8)_Z(Cw|mBRTjB8~Jwp!lj7?JThnx>R
z1A89o84kQ6;OQA4IBlw at FR&6|AOKoZz{shdo>Oz(L~rQk^?L%yM&+D-{QaIWJ(F%X
zPCysH7u3U;7WxDlF?6}1vp`XAydA;8Fovr^_&)|KAU5HcUK%fg4gSUy;7%^&-S#2@
z>79n2Xy_tC3k`ks0IfF|iK+jHp}P$|!O&w2oo;Bcp&*jZ$FnNZzk)+=1j_k)1A%dC
zEp?iaA44I2RVHq&l at JwuYi-0UL#E#i%HJ4NLOzwuZy4f^D0-CR|8L`edhy?U$0LbE
zqz?bdD;l56e_s~F{~(Fhnt5byEuoBm9aRl%vit`Y{KJ>{+*<tKIQ+L={8z+k{GYe#
z@%2&s#~}O<CP!XD{M+e_yh4$NNMqI+&W~1B&#%G%R at 49PH$B(yR}}mQJLmtFUb%2y
nR{x*1<A11}t<?_yyK$CA$MIjkum<H{NAQ2rtn9+i$*cbdMgbzU
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..a0d093389d424092c62a7871992d286cfa68e8cd
GIT binary patch
literal 56860
zcmcg#349bq_O6*^hJ<j04B-%j5I`f4W5O|jC}%VrDgq*cIOLeXK#~cWNdkD`eJd)s
zC?0s<>xK8R9=oot>v~_i-uiddbzK&9*K76veXpu}dL|QAGjZoP)vxM%uU@@6ySlo%
z`?+ub{zEsVTp0=nxJ<Zp9vlkb at EZvCHNg&kmp!i;TNwvGD-4~At~Wvag27m5T}=CR
zcu~cYMe(rZTTdhKqdq1(@l~bz5y(^<NvvNmxU!}u7+O~oYKjG8Rn@^@qP}B{o?H{5
zFN|?pkyFrMuqGO74mYkeykvc68+}%OMlf at ZU$X9Cur^fPvN8yzA{7kII(+(q1MC>v
zjJ}U*H8eI!AJ7DqmcIH(O-g+y)M-6Onpgwtb=YxCsjsTKx;fO!`bo6!tyMZ^iK+XR
zMu#TtO{p*3SQjBXSzk_rj+A|%rdR7?Q6Hmzdub at 8zJ{tAQJJi-?+zWw6r;N3ejRok
zlk`<JHPwfLja3byD1?&r<r{s!HL-5}iTWbdtEEDc^}TVAwq%4cXzfD|%e1#+`<kk1
zlJ)(^=(D=emY=9Ew!SH4e%IcsjTmDJKl|bTW?xOD0d~cLEsbsA#@b+T-YjQ~?Z4BZ
z?WRH|KBE-JlqIj(V?a`VL#u*y&8Q6>FS)->`@P01O{~}dsP#P$eM}-pDbqr&_`1K<
zhZ{v>a`~P9w3f>^{jA_Q9e&;DLny(%asUJ1Bs;ykt4uilC`9~S#On)M at P<;~qmRHI
zH6M<@p2jgQi`NVHbAN|bp7DPRD^L1tK;;=fRGzc^-O4lG`ItIv>cr03??|LodB&6e
zM-zok`t5*a%b%z`<B7_1j(s<Q)jOxIr1#L1#jM^#rzxgadCvGg(6js#qE0qynta3P
zJ=BCn;hAcLYxxtKQt>O#_<H#hy at zh3I`WMHzi*#_Nk2(`;rz-ozO$^ZJn6StCqEkN
zwoJ!1q|VAiT>n|qa*aJY>N)FN?GsFyAF&s<{`jM-2P=6%);v`(L#ffDRri90a&{;f
z8CBCckQCI^S2eCIXbm+-!;!`UzrUocWNbl^pv8WF*;t0lOU6&yN7Y3l<s~&uO{(;;
zD8x&vTf+6V(fX>^P-#_bJ<f~KSSb%YSMUT>9f{PdXsi}vlwVa>MZ-0QGo at x#Rr8nv
zuqICiZ}Mb at gR$nSa4agk{hiFJdYmh&Vv%OeD%c<ToZ5ou&<&BsDY5335O_-up1UwM
z7HZ4=DdlF*tM*q^l$YT|zN$IW7OW37u8ge;hMJor%@wWC-5&n=N+T_?V5BbCjG_%W
zlsaLg6kQc*js+X4qH9z%ydf0i7^m#)S_Kj>CYu#6iKPeY%=#zTOcQVR!3%?vY;bl>
zMMcF#6AV=>SXdrxu#yU?rbxIk7HWn`#wVt<t0r5Uojxm01s640s;o+ihaF{?U`?Q^
zwzfGGjaDqEQO2v9Lv^9%P-9K#zek!|qiQ0JXls_~I+UP6mrO#c at e*j5KeyGCx~h+$
z2edRs!z&v at wFM}OxcO6BBjH+URVlRj%W6Y*k<PDaQ1M_#Ihfc`wJylYMys&Alue;M
zP>a6Q99ds6zXpoMtAewdl(dq>nhJ&+nto>GjVaLm#jaD``p_t?mN=!uhBu~wC1z;|
zPG<+zg~+lC&I;GnEn-u)^VONw$@<Zi$||ty8S`7IcPA*#v0&7028}TVbyf9I4iED&
zkF^_le8edj<)~!;xI~HB^J^;nWi}RJn~jHPWo<Zy(X*<4iX`JS#Fk4)i{oBnRcuTF
zI}lQy!RiB`g0t(;pH_t$(HW{SJ((i8El6sGKdC$uS|>X^Tj<ZM603<;ESL)gKQs2&
zKr~bz!b~gD$V!V<VM@~sU(<SBhs`ZDEH$J1C&~Uy3;Y=6?G7qq9$FQ~MSp<f-OA>w
zdTmKnV{CS{oEIuk4^|At9-_NNJMk$zxmi7+wW_|wIc9aNzNWPr9Y4|(YUT;8K+cd7
z+v<Hd0a=5=Ppss)y?RvNZ4S$D7Esbgcb_k-x7a7s4zdJ&I!iy_YP)IezCKLD!&y>~
zo1G{hD{4i at DY0BS)x;-Z!2C&#yyLVn8?n;<X}W%95sd8u8y)2n<k+t#Ex}+j#sqYs
zh9;iMLl~v2!p)BJhI5+MZZ`4rCVd<+n?p^`q18Th+0&7Bwggc(4ZpBKW$}|sQ1 at k&
z2~5SYo({#uLaJ(FS;^TIw6-c%C1GNm1}c00q32Y=`gLGUU$9{M5y6GCmsSK99WlQm
z$S9nqHCMIa*cNH7je;gsfMhz}NXpAoOK^hdFLzea>>5ITN5yd32rOX^RZ%fs@>el0
zTvjo!8chS?m7$o-b3vK1H3k3QB`q_L*|jLNnN^K5LKO{7vGp^mq8OG_7LTJ%BsHTk
z1%7K>w+FS|6=7o8%nSQbCg{@fGWkiR at e{O|iGHA6hSILch2w)2<LkoBQP!bQM;-cq
z=>+Xk{-siy5DjsPhP-Ld{~&YmB!BVTjf=KbHR04hF{tRn?9mTbt{R&n(S)mR6>h{V
zwW=QT`{rPMI2zN#COSxUXl1xD*p6??$v+`EB1VOA<{E}%cXH!JH;P{9?j*;Cq>6A<
z!HOnzoO57u)>x-TtQtM*bLtGXhC^+$YcQ?F`PVrob1YPd3<?OR_&V)xr{TY!)?~qg
z<2 at CzxZ3Gp_N?CBj+uH;uBckbNyFHnJ(=9kSxAAOs>ZG#xy}fNu?oPMX{U6V8boHy
z at bCZ0W=yED+KKjbD*bUax(ShVO2LF?%L?r=*PpnrfaR`Gyl|2MbCJgLrn!#%*#$5T
z>mD4TNIGSEpvE at d_&TL#e2p<gXs1+ILqn(9fnJS6L1<5>3~;WobjFDBAx<7(gV0Wy
z5MEc&VE4>r%R8l`yebAITodR-hZ<kkj4N*BL1?E`jH|AySpy9uom0R;4+`|y_w$E1
z|JdeGL!>nn#MMQelxRYjHvQaD(^eU6sY_6)!<|uSoqsVDcc!AoaXkb}d<_j4ZJO41
zO2>p~OEuO9E1*OBI;ABbH^!Pn6+EjLe|m}<8mOu>rDEG6Dv+<Vl+4F!aasx*uv**|
zDms^sadlV-WUVw{a^A_)gVv!J0Du0;Nen;{bh09J;*8&^Y8c-fF97kTqa{5XI$s7R
z6P+#u|5z46P_E8!Ybo9wY^YPElB~9q#gnY2^W~IEQ|EG4E(KO!g_}eP<z<krP}<qj
zN;EBv!fLOmbJ+?w8dqZ^slarb({Pum?`+Yfur!VG>p)xQaycR1;M$d;G`e((u)Xrm
zmSB5LX%t{;Wmts6wa_BvSV^=N8|*n-(lX<OswnTj;?~*%oN9Hz#814Hm=v!(w6>zA
zMupb0&dhW$S)@Kjk$Ra)rxvm28z>4n(RQe8g1JJ0V8<!OPk6lPv>Q22Z!!5}1t|J=
zBWmV}BHFQarW7%s+>LnwHpCDH#jr9yto>m3;cg4sUmlADb%jC>QJuk#?e_a2XKAmf
zVJs`OyGWt6wpc|tjOw+69mg8WEa9px!ds|vyVW7vsbwR*$THqpgPqlL2o_npz?_A#
zl*@5lpgFNYcQ%{OR at W&V_JUM=DJt03jGHG6%OH}p#FAbrxQP;1&W#0fM?P^kK&Mh@
zzZjOL8Z&TpN{eG*>%XpL#dm!ql#O27;#y{WHKL1caom$hNZMH~+JJP*!dhudHy>T4
zC%*KVwnb+BGhIE7rNneq*~^LPDoU}a*tyncFEFNSQ3tDxow8~o?ha#rxGXwa-gJlb
z3AiPXyA2hX2xwoIDNI*U0QQ8MG4W}jW%Q-1ky|}=Ch at dFT~$kc4AX@$mrqmT=_Y4q
zz`0weQx)$Y8(oFHvTK5v7S+LE+ at f@b(=~K_O?{|}yIO@(o3-}SDQoS8 at pKi*VlI at V
zGmcw2(#nxuV^7nPE>Y4nkN5L1N3=GFjg}jF>68#ucEO|$TGF1>LB}sNah-stVR+|E
zmz at rz+iMbZ>Lt%~s=-p1bmi8m9_Y~3Rk=*KQ0$aZ9DQ}kw;z2|;9X_-FVvzYHMK-n
z;Q<5O`@$|?%b%{%6PqGUT4^h`4r_0^I_-OW=?=$EMd`G3>yBZ%_BiyUV~)L~B;#tD
zgS at 4zE3V@$T{38O#Q>w1&bnrRv2~@}Jgr=&KfqX;exV+Z{Y{vKVz#JHB07|I?h}-D
zK_y%Ix}=sJ%DOD0T~N=)EZK$XSOS=hJY%DIS6P}`{V#3)FVuL)W5ZSymr at N%Jn5E^
zQJ1=ieo^HMC#AhUitDnb`l=e1hVIHHoUYx;deiUC4vk&WpA*$}VRqB+6t-!pn-pqY
zS5=y)=l`AzHpt5MgLGyTKPi<iEB+2k?0-=!yBV(1y5e^1cS?7f=-Bp at X6v!`aOqn#
zY2|OcJmkzJ7kOnyx_KOD_RyuP$3GTNW>`<Q$%D=bVYb<{vaRoU>IrQZDdWJHuwkfE
z7pL)Cv0Y?V;%)a%*<|(tbx~<Kb{3^yTn=SvmzUAi1qGJ8DX5D|E?I5Yw767S(=N+o
zrCm{|iJOPIs!S8Lc2SYGSDJo_ChF{p0!^`-sH;jfh3YOU+72|QU%n|6cSRw$-*MDc
zW!zqK7Zq`8#p#!Dd%ayy!1h)sDb}=&wAESHWa-W{k`;Er9KlwJ`tHgMcfGpwPw;*`
zk{fPpt!fVAr3X>WQ=LI(KAr0$|3o~T%3F at XD(qF(w=yM(WH9Yg#xw2Vs61P(v!MOy
z+K)$F<!NBiDZaD~b*fCWa3}CVM7&)|-WsIu?aQ-?PAF}A{YZtE298wNMiQZP%h`{o
zqnQ<Xl|VvHY$W}R=qIopX;}G4NF%N0j at OGwjmSO=t1iqFv1utD=O`a+2$78pc7Xv%
zzjTlS>r~2uDI^q*Ng=H)U?{LHHZQ^9n~d6{X*VXMWM{=nDIq%sOux`NN=ZLFYmzZf
z1nZ|kck{lAc5fNz+{+mJ7z*RPGdcgd8+Ta&bd*+_BO6}V#w;Wo-(_aE*Pouj7$flz
zeMCA9J!v;#*}sHm?i#q40VjFvW-_64Rl`)-3T39U66i{uU8O7iHBGinzR<6FJ=XvE
z<7rC+=^Du$4n~#CY~uGBn2t>IQt{JG){jA2?&@%RnAI|zK-vkQ%;bGs`mq5s`7sm!
z_MBfZIj(i@?xkGm^;eFO9ptm)g!#^+v~!G+M;>9eo^HVoum6^!Gs6EieZGk*?G#be
zjvQM}N}hgb&-mq1>$sGE*<5y<ZdbIYav9F?mZ>oA3xrs>_FF09*K(<t=@xW3u48!F
zXmnc-XGHPFFT6E~Lv4p#rC$&!uN7&EHP_<pkinR|{1Vz$Hp0(IXhChHrMf<(8bS><
zcnlsyo`=F??F at o68j4rJ>L4hE@#aekY0_u~BlUdsZ1cLhW?nMSn?T7`&4*P at 3N=<C
znP9kX_7eTVzxl0UJbNW<k)*N?Bx}Nw)T(A7(WXX52p~dJb at Q5(y7^=mg(+YO{}=US
zGm23^f!<hZ%PsBTGe#`3h8e-ETk+nLywR4p?ZMu6KIk<OMQ+}8%1J6AT=fBy_mCkp
zwj3eQ3FEBFks1P`T5w=|Qi){0woJz+F41k=ij|}+fe#tHhZil0s_lU2w?mduT2Qnx
zv3R_ANE>D|wLNxFqB2zHNRWOzJqGOL7>K84#gWA9NOmZmlpPHzq17W_eCb;=UOA4Q
zVh~2tJb3t)LS3%fR~v3ccx_80hF$Uvs$Pfd4MlINQ>M$nAI5t^@Umqd at Xk4D3$?mQ
z;B7Jztkc0dRaYO;JqWT!M!Jeb710(GZh<bm!5BhvtkDZ1b<H94QtfZnufJ7Q)qH~;
zMx=G&n36-Vf?iDOLyfo;i>{BxkOxDmqgWxTS*6xS84F!#Y*lr19h5{>y&U979C=>1
zPT?roSCV<vfd1QvV=U5EquTTniJ-AaLp9JS;V8oJAfyhMJrC!!U{q6FIOE+$cz0f1
zebq|5I<GE_AtzXk2L^-D>J|{ZHwl2erYTroU8g-Yk;s}b;F|gfxyUt3H56K->hO{+
zXVpezY~x_4+YFvA!%(S$E!7I&c)%O3EmM{NgC#AJXrmnKAyZwyMkfhH?8kLF$-26F
zY(&ND%VLxSX(g>|!lMH*&}dCnBj838j#^aXt(II6uP2ljf8je5E7i&-JQlALv3+;~
zwHfWBEm+mO5-wDQriV{I;0 at n8)M}DyjT+T<nypr%b*S?i#bXo(w!j}G(Sayi1b5Zq
z(1KTEQ&N{^oh~SgfW_CB!8{f+GAyB3h%GY2*Y at it8Zfe{IzI1-_eSIO-3sqjB?;DH
z6MZAzSI#3|&L7f2L-k8!pogDOP_c$4X#}7Mi+vmu#eOT3QoN>6X*&fZPpt+FE)9gE
zRrQT64Pj+GXxD- at t*X)(JQ}OU3)j~W6OYDf8e`4%#Kfbq+VD!euML=ZG=^8!HmxEi
z9*v>CLe0d)qcO3In0O4<(unu%5~D|BQ9O1OA|@V<wO~iR=o1gHiQ(uv+ZgSmBnAwf
zvhirl#EwODY}6GVERK(TCXDWiF(skv#3A_bgmFTwIKnYgMp?0|%`SB9)7HXoie38*
zY8QN)Rr1JLn_cwUXJqaCwppc5S-beP&&b*p&}P*DW$h}^J|in-&jN3=YJswLHE5ra
zwJV~{s)<REjaP;78fht_ at M@|SFNZ|^K=(upiFQ at RZ3JppmPvtQr&J6hvw~zm<xJC2
zg&booD20Eb3L11CIv4&JDe>5ML$D#-NU|z|fseu3s`Wx60<Xt8fx$KduQwFUKN=%r
zWdlxmb at XkB;L{j&x>(Wm+syE10j)Nx)zkvUMk55C)v1k#BNfggLi8ZT5PEkTLT%yN
z5QhRlM9iQCDyNrPP3knk$yCsKLkz{qRA8P=;o&3}L?*Kg;#4d_O*wld%Coq at I&9Bk
z$?ITl+SVp9F?Zyg6oMVjN!#Yn6<K>u3gHgtq*|@aNuhTFL@`B3In}k)g0D^3&6K;X
ztwFV!IXCmfxh^Qr>r6q1IGq(C76OG?bf9uwKo3ulLCDv|!WhVHk2NufMPxp})h{&T
zW<6=ZBw4BtR8JQKkokf at a)y#gg=#e|#1Lr!9Qj+VhGx<EJPjWlYFns3dl6jfAD0L%
zn48vJwF(TMSOCI1f2|c##|sA?udSbl32c(!Y;K&MzbMG}aGBLq>$4KFW}V_`_jd2T
zhl<3P-!Js@{a`=io%hZMxZ`iWx6%Er4?slfI>^{0^M!~=os}VZuZAgbv^ailBwhot
zRbjpsnQvfT$8WaCuZN*7b(rPl_iy-fsYTioKQ<Zf35Ft8oT+_Bw-afnWs?!P#LyI4
zwj0)s9gEy<SPyh8@~B~%j}0M5hgn|py&yo=XMK#UQqLP7KK&!V6z1(TtbfNvEbliq
z)J`!HlV7%>P;7bku%U$o#yczy8I?9EGptFrNV{s7W>~X37Fl6ft2-8HGOV_^h~>4u
z<d&iUU42|5d-*&Wy>j~x>h<371N*r0 at Qoz*2$j)m|C}6rN-2Y%S<9T{%E0H7JS1nh
z2I4zPZr6mIj9xi8lXLdP=i#~yR<nH*A)VC|5oh~|P8~R9;9x|~?gw5*FD=+T&Zl^e
zFF{R at o)D!Vc|H4sXC=@p9*=s<bEvs at 3CyARlz~$R!uE2+%Jo3SI9S-H9kT{#9@$Fy
zN?eV-blllKN9?|F+=1rDQCk|H!i%FuR;m7_l2?4Ms0<$3IIt82qSPKfkSQ==5E&W0
z$Qm5a)5ILwzGsrjN)0j6_>9$1UBr|ta1=g*!)!e{@v<qjOC1u!jp7_frbgK2=h&H|
z@{w+1>0XYy0ls%!-p+1O9J6&OwNHsMg&Wtb)Tk_ls>&IF(jQ%dR+s0UHekcRcrBp*
zlp5nv?*3N2C{-NK8Cyh2QZ|$-?Jd<=wwDlpu8{J*&|=5BT&(DE!vF;kcRX8kPR{=D
zPM9HL0ZW_1^ofZX5}PKm9Hbp0?&K1vVLlv at _O&omE~l}BOv#54`&mgiIs4~}Wm7qH
zPcs4 at hq~!jxhpk8=bw3>Y4-*MX0<Co)Vvs5VHY4QRO*0n%00j`Sg8Xm)$zV#F+NmU
z3Tk~D1|A5(**c!?I&&y?B6Bg<lG9SkbD;hdBs#i`GMTCjx!`Y-CUWF(<6Z%;+m(^Y
zPr!M?ICwMp-N6B_w{p8(#?Q579S^a<7 at WI4b-S|rpuG5DN7ps(tnv81n=t<7c6FbQ
zz#5q1%FR$Yo~6kB0GBtT#|6;f%F0kZJp(|xuK at lSq3#)~`-uqr$UqJPcO!5R75Csb
z at Nzu0qTwBP_cibwL8<rLs(Z5)c;B7XeFFktkn at 2%S7m<#W4q&9bFLfQIi6D`_CMV{
z@~H9)H_~^3Nc<<5m#?7gQV2~a|6hnE+WtV+*KU`}o&w)#`0$<UN@%-Zw7D|6{|277
zD3bvrd%capLGtg*aQ$fgT)jU4?8?t@<?dSy<N8Q&fC=VJBbI%3KNL1Tf#<r)t;L60
z{5j-ntiXxsh?+6NVl0Xak8xs7;r%Vfk+3_D1!>ezYsbhN5Z5=u;xa}aOT$E~v>3Eh
z^yz~m?%ehw4sMOby=1hlG~~pL8JFdvd{!BT^4*MJ&pv?GWPHL}&fP&{v-=EEs)+Cv
zZr=xmN<B$`L&p7J>I%q{67`K9Zg?$Do)n<3+2XBp^29vfA1&SnC+`ua?aLcsbRO;G
zu|+B0V(=Q6gR?WXqOF+5ko_doT at IG(UbpW-OXR$a2Sr5Z=oyIg%!9~%Zr_lRN^PN*
z3!GYfwHCa^8Pj(&;6WH9To-5b$OO?1F#CBZ{1PnJ18(00jJYCmX-27t=rmt}NFifB
z==R+Uk<Ij9;nd>$!Gf=H#`GPqH!P&J*Cm*;3GnNLZ%lw+CrsV9Bq$kPgp(?|uj{r1
zxE}B<=KjtM831&Z`*r~4$mH6Q0RI4ZBg^sb1bEIqN?io!y2lCky#mlDgdeb)o-}l+
zyuLdv=7UbA>N{zaQYXQ=9!|v10`?*CM-uUGE&0a`uKLbGqu&DOdcuaTM(}TherG|x
ze<C;xBdzQA8Bk$0cHd-l!xe;|&e-L#VBM#)pF)#-mL21Ix9 at mM?hhGzcqzw`$jChl
z at A;Iw&h6t!crEq)v7J6&Hspl&Y&#vkgTcE9&h?zL;p>ierNw*0$<rO?uNLpmPM+>C
zqf3m=H=R7)2~Pp<ML5^HPM%Kh4U6|_GA}+jDPK{k(eR~HidN}j at x?5GuaX6n?>83j
zUrwH*y=0duRSoC*CZYa)>wt;fgEAchlH{rHYv2v{BhHXaQ$M=x6$4vGyujefcLIX{
z$7&ju8Lv*|d)k5vGvloRqf$90fjGaoh9^iLVZkF3q^|_LtpL)cP7`&}es1x~ojg5e
zP9AIGO>puU&spqeSW;7+QjTJO#S)m7ETDV^<4h9MoxFIl`&L^5i=6_x$vh2S|MAGz
zQYTL$>&y)SQv at 1Q3OIAoXo*JJi8`|Kpe5CmQcC%{O)x30Z71N!)B;PYIWvCZ$m0nj
zPj{3%EP+@%0f(AC0h8Dn?WA-8oeF{H;9TdVv_|<}u>{Ub)}Val6HVmvlX+sP@?8Ld
z_u*WdQ))LS<xefC%R82GR>YJ^M(g#d<sG$gmL+;a$D+#jh9z}lYAHv7?lsw at eX~<k
z>O~H^Rh?r=-J4p<Vc{2+==~jwD&LZQO|lQBmU3A5kR|$LYEfP9<EJRKsXuDw51EXs
z=TUhtCUxA6kb0R?f6Ro>l9I%DP<@{P`~oMs&soD4M>yrn-%qKd;9Rd~GOuQu=Bov?
zii6Uh6X06_|3K;YGOyr7+??Ti?61^a0}=kvX`?;3DBls5z~@c at yKv2zeyt_7Go_UB
z?X(2`=@ei$Ga4pMRcgl`Fyu?8fWwf}EP)@K0?CHFY)L7Pqs(n740Y2?IxeSx!;sYw
zcpOt*SEf_IVaQ{aKrg3&orK9x|LI0eZb~WTtG5L5oB|F*eglDBgJDR%Q@~+J{tP29
z)G3f`$ZAV!SV}47d&CkL?i6qsk~<UU&mk~mFQ<URkTsS-nNuLykl$HS<te3<Z^$f@
z&N!!l!;lsTtQ-nM0!{&kA<tO?)13mzh7?s8H8WF6Dc?p*pu#EOFyvJT3?2YODm~ro
zu4hKtkp~#wawpI3&qk`%k~*qmDd%|nv?agFDbJiKU%vxQieV=&o}!itSyHPzmNISk
zZisp-k-bwrjyZ8(AD}Sd(>>;b$9D{ZPZK)JDVhHgpgm^;zS#2`Ow?CL`6Gb{dZ~xk
z=6VF`*97#pl-=QROrG;!0W at k3;D at 9RjPSld&L#R}g7D>lb`gHsDeRuB)O<MCADzPe
zmI1nz at bgYM{~<uV=K+4nsbdI`7NV~i;V)3)D*tpqZxjBrhk(i8KP~hv&#*izgV~EQ
z82`o%*&E&YryYcNaISZq at pf702ab68a}LI&49 at kDQ}#v+{lp>L?>nHg4uS07wV5h^
zE<%?O`Bt){YqsBYK)xWF>D7gu)HnKlYYBLh1ysKS=9|b_h9^yo-9q)-1m1gauE9=T
zybUJ$RKLGLcHW_oAM#V=^P~y)t44$!j5OR4N%eaI(2xay_cAa?1l6w`kierIaNhms
zwyNLF7H^i5mp72S5esp71m~J<cs$+aY2Gy!Z=RE<b at p4NR1=(Qv4f}joovBJIbdVP
z_ZBbY<msehhvA9_&K1@?)$i{J&07p)wUK6_s{ULtT2=thzJ*Ht1+G8WyjDR_c|G^z
z=yI)b_k9JPd{mX|2)8 at 87*SN;Q3&$xiEF6^4H!jnED2sj*!@>e{uAQCx at ESPtA2Us
zA!Z&|CRO(FNQJ9_?$12-Dx3QgPj&`MnCq7AU7q|Zu6$6YM^f~>{X|DOWUqpZ`yZZu
zci=jEK?eMNygC_4P}0i(5<IRrxcB!G$lJ~g<d@@$`&>BpOs~gAeLH~k>jv~jNi!pE
zvm~mE-gglsMC#VmQc?-Nd09%`4Cj7L(#?>_I(6SY7Vpo7$0&xEpN&g at IQKhZSwg(~
zE#3!)7mp`3cOc3m+cQEB8t%V)P#t+FLYF%;Q|h`B0TH|l1(N*|rjGZrWW1TE?s+2k
zrMLHyEObvdSME%fl&=oKGYI8$dkod)$~}nn_$<6CyAoch$8WsZhr`b$3-@<k-!>~w
z&u(AE<G7HX%H|3u$29l1-t0Q~xg6sD-s^h{RO&m|q{HO%*6?rzBlaB)Q>Bvo8{6_|
zk4PxraxkTq2X<o=ZKdja2H=~S#U;)-y5X}hvfCgmE$-i5l))f~y4+8?2MX^D at Wj$T
zxK-vuVC8t86M=tav at cEF{<CS4l<C(Z-&Y#(rcAqb`frBP!+{$4ldL+pAQS5E7V(PA
z{w&xp5wPQlxXNCSMlb3sDgKR!Ka-J<`*dnQIQL&Nf{@7DhUkvk!Q#-l;M!WVnX}6&
z{~~V#RKn-Ve84q`UHD7{RR1;5vYAmhLTrUcmfD#z<W%<Wz#fKPkU0kH?xW#xW%hMv
z&4%YD$Y=I*yYde~U_C|laPNY2?rmZcQ{aMqW`B2o`dQAB>;(X!cnJEz*W?#NaRz!x
zvSO8A2-GN^3+deZ|GQ$2W(RafnY*vb>XwBo1=Vd6kG at -aq9^x4Iee5gix&{Ndvo~r
z4F)9e-?Hii9wYE+fOk=PXV&i=(%)F{S6P3JOZN at +*4JL{Z?m-Cyb09O|9Bi;1y8E>
z&+woIUKHaF%Nl%Wj#3nGw`Hk}J%5jods$ZQC(L60+XyY_0i;=s)oAwT;7PYTJS%?*
zxFQh~yL11;c-ddzD4lFcmL$$HAHuok3lP_(|0;d3<0DX)`{=BpJPlX|oS2o{i<al(
z)~Hs0vE*N)**@^ZfMc`r>nw?FQWUv+GF~=sD~JKdWl5$J4A8BP2Dns#XIvlDsQ2+<
zylJxv(Y!A>?%8x-4emOk7@`W<GTD^8Pj+7myn*;~ch>NA2zdYE$~_T)(xJC?DDN~v
zBhG{XZ$Nn8J0D>uOG|%fAP!V{RBN>S-GQqS&oj+jXxa55ulRDg(y9vIf}ghqyw4O`
z<DB=Y5rcv727&i0hwO;MiBk4!CweImuE~49bE0nn;T-|*57T&AXHuI`h$M+V>stcC
z`vG2;%OT;r7!a58y_pH{yMVZq at 9mZV4+q4hd~c46`8LV;f`GY{@9mWUUjv9kuD4GD
z{2^ejihKLI*uyO)djsOCxEFUA_q1SLyoJ_j!21W^8i;T~+dHV8nC}MQTw(PNckq<&
zZ-BUz>fI*+9s`Jr8QxMCYsJ{nw*k<dgmF(>+K9HH at 1wvx7>vF9CgMI|Tte~AuyD2-
z<vSEOS7^KkyWWrIhvT*=G&!?QFW%>TTOiEE8t)PpZ-;4n9J0Q at fXOREZ_vfwX#^;%
zd?SDhFYM&8lC%abwbGJ`bS&je at fJ(I)hW-0t9*aAc*i(- at f5XG8Af2S>%@+wbW!+X
z5an`__Y7x&(QqShpCxd<Q(%f!qRRJ`C9u^gKtr6F8jmqp(%GI;O8H_C;Bt}oMyG(o
zkOwS*JDdUzL%y~I?sEzx8!`!5lXM<UDW!btA;9G#@6%2Jhat~f0xviP9ESAAU?3V^
zaS9|GQe{cKl~PLiZh`=pi at YB>1ssO_XbF7o6mS?)fi55#b~y!-4LR46`ZlGM^1TWH
zE*E(-+>TD=Fl0QKB9P-0a2T at D63BB3BpdQ4OKOjlQpz_7OGR8R@(y<jI1E{535<3M
zI1G8*5-4{HBpcGZz@#%drBsS5G&OP(2JgK*)rjfp_WQkKpxfZOJ)gIY!@+irPI7X*
zis;itw}AYS-WNC==PkuKLk_CwIiUX_=cQ!ME}-nz-CpBJly{ST;CQBr1`pFGgl=yz
zENoRY9U%K%x4$HcYm17)V4nxq?akY$O%5WcRc;20!)dp-Q?efbTXOk9oGocHJF4hi
zuruN7_R&$pp_~U*NYi@|{6kSb$W(eimh20^XdZwTf}ctxt?2{+Hxv9!$|SCCpL>D6
zM$YF1?Mr7h^7;|j=ao4U2hUzOY{UU`>Vr@{?mmvouGCX{S2iz at WJ>SL#I`Q~o3MIR
zRyi{_Dl70;hPuy^Q1^;&By>RE5`qVo3aP9RGJA!PIjutGo-btHEkX`@T*$$12|45o
zA at h5cQp=&mLKYk-WZ`lli`s-7cD|6s*9%$ln2 at Ef30byF$dTR3przMV?9c<bc$AP!
zrU=<~ppeUs5OR5~kSkh+Y(HJdRhJ04`dT5^+%DwW2Zdb!q>vk45OU+2LT>u2kXv>M
zx%EFnex2oK>bLoX+%ZJRo%;y6Yn+fBQ-$0!N65V^gxtSI$OEk;gKMOa2iNjG?x?|`
zn}n=<Nl5s6A*=hAlecE1kcJ6DA_od-suQyIG$GBG35ne&r1d2s>v*en)Zk;Y$C4b^
zSIF_hglr55IboKN6Au$|>KY+uHVZk6_i0BBKKmje=Uy%3yd6R|KP_ZS#yE;xG*rm1
z#tFH&LddqoLN09*a`~x3wqGjb$~%Qz^@fnE{~_d>?&G1Xu%T2);}sJaibyFHuKiv@
z&3OTW(cwa3<At;wCZx4qNZUz5)@>KE{$3#){v_n+Arl$>n8`wpT`c6dHX+CJ=H#ft
zjaLgf;SnJxzAWUV&xM@)qmWbbCsFd$(Lzp}E9CTukTcE{a^|%{&ib8 at vtJc*&Idxy
z-6`Ze*JNthlqclEp+YuK60&89kc+}Xes#Q%t!E0kbeoXNuM at KUULjXLE#%sFg<Q8w
z$n_cfGKCxZl8jtAO313ILc)uLtPTrVbDWU+3xzb?Af)kOA(0n_G<_^&?GHkl`%a<G
z=qMqvX(W5^zgWoBdLh$J6f*s4Av5k1GV at s>v)&g{@oymq^w^Kl4;&_>a)OZAbA`-V
zA!Kfgka=ecIp_)@2j4H`kUt2S|BjGDzZ9~d`~J{b(lSU$t2CmLwmJ!|6FW=ROFJvs
z at TGu9=S*dUV+w^FyT6d*ju3MEdLbJ(2|3|rAtyd5<fPYxoV-iODOuB~<<ucUP8%oW
z^a>$oEE96(S|MkhE#&O0gq(Aqkn>&=a{lK+F3g at zWm`rFxoEPGUmYf7>lz^!pDN^%
zONDH^Q^=*y3c2iKA(y*nP|FpAg>1+6S%j{fFXXC-kgHD-a?M3TuDwObb-x#K{rf_0
z_>Yhq2h3#jo5l*cxk|__%|dQHNyx7+7joMpLT-Os$Q|DZxs$ieMwQ$>Q^-9B3%R#e
z$b+py9y(3P!<T`K-l_BttB_c#{(TLWd*IxMW^!6HW`7rMP}JJt{#5{ZsgJYaKOp9E
zW1*@C_-3IhYc$T(4;=u$ED6doqP0*(eO&%R)G3IOv^dolF=cUzDahg!J=WsXXlv`f
zwsJe-p9z=wf=jI23l_bv!@TT_TUm(4ubu*D?2A~4*x4Hk5uVA#-Ex&;JkJzW%x$e~
zxt{&9N^*gFrsp1kGjbmJd1R>J0?&5|u0{-l5U-~_i^z559tCMNVm1)29C(&6qJ>6*
zaE-uoqyv>%#>GIfIlCOfWxNb8I|4!XOytAsD&;~==@hU^7m&}OUxF->GWz`VIoCN0
zPXyr3!1_*!I~$~1R_VDw%KcmjcORSy8?yYoH1uB!xQu8SCqtz>806Al=_B-Ut<HTe
z$|TD*mUnW-y$ZCy8h<6BZewYsKpCo(Yi|DI0r<aWO!`XQD2y^P+|Twvl9{DklJiRj
zn3d8(@`;sl!*Z#gLHhg>WM%m)h;d7T{}B3!P2i!Fn<z?ah|yQZtJXqR0atpx&y^la
z&VGX+!x_E*YzD>0Ln(uP&IbM0l0jc7eWl`KN`6V?338cnKYf1sN+n2(3c1c3U5r8=
zUbqYFW8uxtb)Nx}nH$&wl2eH}h02oy*JE`H3S3Io?3Ao)$T~!p805f)q5?M)JuDG5
zy6z%tZX!zs9w53f5j7DWC+k3&^NUFiyPhWNAYn0GY4j at aJkdposL}O0SqCSwRN!5r
z%UBnAb{=$ui64`7IOgot@!U&v=~@%>z#2#PL2=W`R)Kwi=FAtJanmNw1iFgyi{kQ9
zViTKyUP#WeI7e&R1~g|$vZkwmK1um-Twa&`vy at +&jJ`~iGfh*w at k|u`1+4!g`%sCb
zQ~jL40y|YzIJ``$uK at NO;{G1Q>na=%Bx?!oG7oX*f_U6=b<+>t+#!Vvz#IZ^pCRtO
z$jmC_meFzW<_#^3fH?(T-%xi2NH=%k2|yOX+jppYIg!l53xTYLH-D%*N+he0^Z7I3
z?YCzk=k&j#cSs at U_1Drnw2*WAyXY+_<oy0IdWRKqj{h9Jg at v5wzfJG(LeBO7PVWfO
z`#rryqBjeJM8ADRZ$7=FL~kLzqeX8iy<<f06ncwA?;LtdMDG%MOA8M}Y1hF!pg=la
z1m6CB8R$-cci<2~&w_W40zo&!JE)-WY(%>p-aQvj@?`C~u=pDIStolgQpGn~{=+g=
z;oT6tm4eGAd2;t$B7*GUdmf<$#lJL56}}C at 9Tcph;87yT`q?w61;xK2O9dXH(5XFf
zMWDNq`!N8SS%IgBpC(Plv at rswGXc}*UL<f96=|U8bpY=Yyw+BiR|UnYl#Q(DuVDRy
z?CUmKscE+RUqCZ61K*Q*BS$GwsF{Jxr9iK@(-kyNH`pAqZm}(JvV3IS#xqP at mx(oq
ztUKA(l39~SkaZQ6m+V9DHF<2LDo~2R5MIdX(NPZ+B@>8_l93agpMfG<L<MFL7%e~?
z-FFVqJx>bECpkq*_as~~snXMNoU-5HgwNM@?sp^uPa31E8Msh7t5io(7{FSBk2vaR
z9f5Nsxx{f(EYAB}lKKM2{Uwquqe?b1=5~D+kP$!*5 at F)0;GG9Iv`LDZ2Nk%G5jIP;
z at Sp-)32co^OuQVx4UE>pi`Tq3CvXczxA4j~&!ONBq8BI2-b?gSJCC~P0}m6uT+nB6
zk*F(@CacmH5qAF;d{1WJj}&`C#H8rRQ-PO=UM3k#iX3>8tjC2V5k}&gQzuzE3f?j*
zD4Y!6|3R?evb{W?f^IE1u6P&dxCy|HSH)k!&om1*W)**J`A_Ik{2lxpKnqUHEp{(6
z{*&^Gv*4e^xF-)N9tyw2J*B9)2!7UO!RckiW$-Vf%o!7l1Msh*|IBH{`@w$-{byAc
z*TDZM{b$cFUJbwKJa0*HBm93RzG+qQaqx@&^P7rKg#Sb0n`6bN!@raMEp5f;!Y^^R
zt}DL4lHYcE at izE*^<8l3CRNIzeJ at WBK)D4+7W+UY`^#1FKr6~oS*mme<aJ|XPE=`A
zLRg=BX^$#BlN_qojZl2TDZB~bOeiflwD4|t=fFGcKsnnS0dN13(%&&EWpz|`5Z!G`
z-vMWj7D$biQxRu|84kZo1+E5j_<0h!XMlF_ at -J``(F@{e$sGjl%%g}HtpfKExyu%b
zXT>zpN6Ft7=hLdGD)1EHE0f`A&k;UYZeD0j(gsbO*U8)=aqJNQs@^4hx4 at ERBmGyx
zk0hp$_le}~a~!98c0yplj3026(QQW7k=mCzBM&~-Q`U?T#+R$6mBTyy5N(>|UlJ3A
z(<YO*K=W)HbYjzHkauXRENOwjJPJITm at UIPjI0aoJgC4j0$U{aa&WM!$kHQ394%T2
zw2_?41Qg?>f&($4*TqEx>j~T}fCD{_=)=kADMT-q%3(q2aaDq%yyz_OFQm-10@@Q-
zEvOB+g#68RQhBFLV!LC54_rl-oPcywli`t)DsTf?SI1*LD6t;Ju}q at gPX09#L6RxC
zhrsQkN0mIxz_~gQc#?rlwkj2PhQRr8pyWjYH_EW8irzrrT>=+Vu^ww#o~r00p#LD}
zibRe{=ig-gTGWbs;0FS?*?`tR*|QwzJ=75BN$*2;HLJ;e30%(@fx-0N5a$Jk5xB$F
zHdRgAo5*}ebCgyZC?R~4LohI&$Ss2KpaT05xYZWH>6^fBY(TfmqB%ep!;N at 39=GTy
z0ILc9*#R~KIF8`E4)9a}7ZCi&0bT;&I)Z<9fWHRt0KqRD;Nt-PMDQC2_$q++3H}%d
z^FIafFM=Lj7-XsZAAoc}3TTcK%>y!oXdfrK7m%?;2RP9wKq`rjaH8{p97%MP11+qY
zqEs!=y$a+aVGX?fn+n^29u4n48a)NxqJ0X_0lF35Q3Zut;k}aRXt_eT3*P?4MUQ|y
z12=lC<dREus_10^?-88j06zurZ at 4k#4p0Sg6$3YVssro?U^v0K4sZ+reDP0>KGXru
z0B{Jw!yVuf03m|Q9bhAXqY2hHz>@)-PcZBNF9C2p!H5IA9l#?5TO8n10A3|nVS{;G
zMOA@!h+am&>8c+A_=4ckETKGIOy2{@UIFlgI2gzSFlN0C<Z*QteT?YQ^lOEMd+m>E
z1z22A=!dri-u{OcPJwqiy@$;7Z0tX;_#pU~0_%T}DqaFV=X(7QMgy9HVL}#PHu6>>
zI1@|f7KcEYlhS#rxZd&~lvy0L{0C<hA8q*$=}~-=<)5Ehe5U0;v~TeRmVd#3;!7<5
z!okH?S^h-@#W%yxF|qWpqT;*Z=kQUwxJ(5eMxbn^6sU|{oay15`Xu31?chHVjtVSO
zMj6~ql-I~>O^jkrWABl*E=4rM{~P%+;mb_ZX#9e(9<OZMOpNcz(gT+r!>~M6U{y<v
zGL{PTAW$Rr%E2~K1$<=HiY%wJX1v~mXee%uRx^xfogLX+knBw~>`1Mcz}jS$V~Ms1
z>X6-+=q9;Jlw6!P4fdAO$iNJ;Zj&p-I4dxl=pAxt=s*u8dZC>1Y}A;ygsdHM&5_Jn
zLDm+zG)!jURd}lG9=SA3X00V_W4tiQSAlgzPfJA2{BI*!$0V{;;54GAB%&t5d1M_I
zFMXZDMMRHJMlUCNY9eaXTu0Wq(m*8{$q0jL;;+Ga9?pMu+yJ>Gn)n*f at 5#9^&XM#d
zW>#ZY6P*8&I7i1R1-g)&E8`p;XDQI*$hjfTk!B`l1WpC3>;$_D<>`!`OY~$LRe>!8
z&b9#~b}7;G<9a1~(tZM0ll7~Vg>o}lTa#jGYwjZJ;*_k1$V$q$F6E-%g7qh|PZR?s
zdfe2*XR<vXiDMb>Ed^eqWR-LPnx_J95ztp1L{;De0*zw(W{G?;Bl9*@;BRED5#=(A
z72o|LB>Y|E*T>CB5(<1v{?Wph$&=KC#1FV at z>-_3d6I*HvoIDo^ix%!2Zhdz$KO9m
zh&3>|AB9#kFM*-->RF#uj-G?<O;pd)iDIZNA<`^`A`L1KAh01`e>&ncqWU^YM?~`a
zhkW7o&*9)#!j)%K5Pqzd-cNBq=K%NlE1qL0^IR;xAE>}Cpagygjz at r9LVlG^#?uGX
zwYWcc8 at zaX3MS<04Jh~$%Elal0AE4kdLu)g<fz<aB6XKYc$uqO-vg13F_FGOq&Y#L
zs`7awnJ1F1z&25GkV~tl<bnNh;Ef{w=G at NP9F^PY#}9XaVAZXN_Mcoty8=O4CDEP&
zYDH6(w^JNHZPGj7Z5 at ahj{{<iA867ppsMmw9Qb2g*Wzq2=I;T?|3i?H83)2ssbC;~
zd&9XFmp~|jEX<BM?Y;==dWjTtFJuCz;GinYOk8dJYG65x`>-=^qVdyA44<TSDPqiI
zjCVVVG3PNR<e!bYox8%s)fwM~;v19UR*G+lale_tn|pH>Lr(es0dE<bLn(V*DQ}|4
z9UZv~1hW at TucWG;a3~LjYLXu at m-31~14sI>{af)hE-XTp02>c$m{>k&f4Bi~+s_==
z`(yVLXOHcF?o(HP at wZ;zocH3Q^BTVY;MzGCHJ$tBrsIzPX3n_p`W{uXpzg{A7hLVG
z8#Hg`x{;qh^5%~2Paf<GZw&ou)6xIj<CL%0-T&YK&xUiGih}2FIp&<XO}!VK^tY=Y
zDx2*8VC|>t{^{xe%m^4c4sI6QBDh*OR at KRHo8hj3+X44mxR>ERg!>XM69v^5ZUo#o
zxLI(E;A-Jwa3{lUhPwuC2b?^wi+r&Q at yFY!P@|+eK=b$0VT;d=;N(lg1C>`nfU-aG
z#~Y*MO9g at Q=`e=bBlweN^FZ0s_~T7fr#x@}GAx}2RGw)AWn<(|o>c>tb_vQ`zm&J^
z<@0|GTl%?qongyfjx7w|HVX&*c&nLVE4^I@>9D1rPtcKXrO!?L470WKCl5A*%GdzP
z4gO9($1{el^!SPlhOP3F=jjl%%7+h2lW*y>+OWg{p4^7nJ}sFH at aa;?09L4O6<c_E
zPSee&=ltQC3-VY5i{Ma%Dh$UoIMw7Y1jleW1Nc1z#SGuVj)0$)=4AL|aD55l$Mo5^
zGL%Q*VG_ZZE^*r04V3+w9F8XJV~k6+gWv|kQEn(`0o-snj#%vPW8hGHssyeK&JV{m
zaGAS-V(~=c?hA at y6#rDvX~sVTl+`vH4$V^d^FbHDVKG-730Dor^jRh=jh|tb&l<RT
zxJI}L+*-J1xG3DW%WvIh)F+i!bQ|zsN$%7K`@MPnq~*74y7rW5lMX#==RSF*HyoXF
z$ES14 at 4Id4zXI-y4(rqW*+)b6c)$PDk9W?#V$icMWuAZ6=3{=J+wZ+0I~Oipz4f|N
zw!OEucmEsS8g=cRCm*x_mInsB`rdIHu6sG_vfLi6JGwo5`7vc1PtUn@<z?&p&dk65
zkB5JK#VfbHJ!(?z_h&~}uYBbD+b$e@@SKWix%2PYmbHG>b$=iBS+7 at iF3nwj_SSOW
z{D#jyEesy>%9alXU-b5mqyDqu^WQCtp8aO+dw-hoe;+M4YvInO&u)ME!$Tj~{L;#r
zf-T1s-*El|s|!EtwYYCdpK~ssd&R at YjQ?)m%2lWIKH!E^{`KDA74ska*MIH|R*!r5
zs)_rY|G`sdMT;-kaN${JZG85^DR<Tlel&N(@^?pN?&sS7n39&S{g36iuXuMsp9^<A
zKj_{u`BO($-}B7UX+uZ8J!$19d+qbWgY)lv?e%T%E%F??`kB2yDV{Vr`{@VI{!8_#
z=j^?@=!WURSO4_zmS?^ga$DxK?bko^%?nF^?795og?(Da^_%+G*4L-sykS=C)}vqf
z?wW14k1H7T*?HHkKSJdWKj-4J7u<jK2Vbpne^)fGch<tvfd$L<`)2%)P5=J#ot9B=
zZr*h1X@?HXS at r(Nx)c5L&zkx4O|A>>yKUJ%M^Cx(_DrSTf!hV=@!+-xTsa(G-lmqo
zt${lZ?tHjw;O>R{1KeA1JK-{LQt1b`58M>EL*T06THsEH+XnY*xX0jLhU<flF#;|C
z7ldnuI|Xhl+|6*0z`X$XA>6;=y5oekCtMlaOt{5xO>if{T?BU{+(U5B!MzXn6<iih
zZiC=T;HJYZf?El<0qz{Q?QnO&Jqh;)+-Gn+A?BgOj)a>CHy7?GxV3O6!~F{GCb);;
zo`?GY?q6`(=-_-O-dwn&;MT&O4EHOzo8W#6_bpsc3|0kjW8n^fI|8mA?s&Kh;I4(c
z5AGSbx8eQ?SAY|GCEPN&Mz|B;Hp5*H_W<0paPPu>0q4bdJP__#3__?D#kb}3!w`k>
z2BZ$t0uVl61;QstK=|WbaSnI9O>H1<yCB4^v<Bi+GSI8|IxRrcFnAdbH~LVR8$~FA
zAMZ31;*Ccm#k<~wxI@)IyuVI}x4#X<O&)~)8c(=ng@(AEW2EHGVvypCV+_Qb?~KSh
z<pz>{Pk at HQE>6wx<2`gyAD7||07ASoZz6Kz03qJOH_!?M35|jq0f%1^rcH$SmNp|L
z4}b#V793L&ywOf6ZlX0(yk|^^D+NXu at 8T2UZd@b9+jN9 at Q^!Dj#*GlS{Fn^!CLST)
z*fY at d6&m8Amx;(d4V2=df=Q8kz0kE3pCiVf53+*r>0uB)7!1N4Odxz37KGDP5dOH`
zi28WJWAt$~ln at t5jT9eg%LK%CIRWDHuK4pQK at dLv2f`m8qhwS*nQ0(yWgwIlFE#E>
zAjDlEMvB`j2yqLvfw=pO5GTq8;`RkX+_7vR?ja(?RT*Rdh!q;*b*Yi!+Yl+mw>6rw
z<<1d8yccRBa(@LO?wK|b`ASDZkHMLU@?JUw`Mx?M#fRM3NFLOUn9r&i4%d(wpG(V@
zEeI0g?lsf0xJir<?+hAS<S|r0r=lcH!rWm(Deee2x_IZ45O0(kDL&dsh#SL<daiU6
z;)<$?$PIIZxHM`~<lSmQybLxFUx`WRcsQfJ0bYp+YSeSL4I%D=G3vRKju6+kj4m#r
z6XMFck>Yk0LfnpSAbETi5I5GD6nWE?QoO%pq_}s75V!Lf_1qdnh`WUh)T2;Cd_uuQ
z<U2Mg^&^~7&;2Qcc+1~NaU&2R-k3DHhM|KI;u{K#6gTD&^2H;{<K=*AAY#<>h6AN|
zAHqbeF3=EPGhn2+Cy7$rGGwH<Cy@}BJPgFmM1=SdfPrK$DWH!rni*ZZ+d(O=X&5Pa
zG#b!USZ}1b!;~kMFW?}>R|J6Yfo=SQI+xs(iV%PDs5j^x7+j17c|03XZd at rJR%X(C
z5Z^@PGpvNTnb5Qs?mQyI2M&xBw<r<f&Lso!U89V^{eytG at zQW)-y%4OLx}G&0O7Oa
zAbe5^gpa+0aIYf>e|$Rvli>Rj48(m;g!ssVfw+T{5O36*s+U(d0D2ikWU|f;V-hi5
z5!~HHh)-r1UGl^>pdkb8h}<ebDefRJQru%ki0i#3#j6T5#4VOaiW^ZW#bstARlPz(
zT-!5t at t!)Rc!%9UzcKYZ3_}!j at f|Ao^D!Iz`6>YrJ`oDSpFEBZ%B`D#_^>+2T;u?R
zn?#Kq_lYqjJ|AKr?s_A{Csi!SNO6tbSj~MCl;U;@BgI>8gm?$ZK=P&lK<~wy8#kOu
z#CVF_J4a|&JVox!BgAKDj4pYM8xVKTnnD?5`WBzDGL2FmQG(Q;hucyJS-)y{T*@`w
z3LnEX at N3dUmR;aAr~yGX8860U{@U at k3#>0GQ}J&%{Ep&3YWSG#^4CuP^BR}S)l~eQ
zhTl<qOXJ=W+0{<JbAc_D{%IzLDff2qR~V$D{52VVNA{sh%Fnf7fpV?Ob>;TxmbD3S
z*w_Zc<xb*7 at Q*+C(PC)Vy>d@=&+Lh5jQl7!3ogsZ89P$S)kALQM6HiY0P;(rZ!;LL
z8 at b)-dkAum8ab1{l<9s5xf_feI<fwxNVf;_z5OTX8wa`5jU4M$ewMx&C!uTT@;ef8
zn~dD<^2?>Ybw<wAbIN?&0=Xt5x4UxTvfvUU*HO8!ZuxU<m_JWyzT37;1aqzW$0#Xn
zVEY7JU+lm9W#t&fR(>mVet8+2sYaq%xLmI9di5lM8EpQp(&<f2_2HVTSQy{rC|yz$
zsSTA>H8qvaj5Ol=ZLw(StWayH9v{(aE?pFf)Z_bCVM}gSsIID|K31|0-(NGF(w1m*
zX?3`<w4|go+*niJQX49*89llb=b&F8q55!jX$`)pwX)RjFDWY-YbE(}(wbji6|0Lh
zH$+Phs;W6;;gXUj12{6iaMoO#9j#p>nKZfkA0}0bPw15f`CX^z|1#D8eTw0+6DRyH
zb7($j_%j-4nvI4vi3Lji=^AvxhEPMKc|E&hG*(+1sw-K=^S1sFT60wxAJ7Af-!cm0
ztEu?rxO~V at i}UL@!Pao7jX`|K(AJ4>AX1eD(;wu=CCztNbrKMg&*w<W^Z~{QsZsc;
z6W=$&mpKu at 5JaU2TR1<OsTq{wm)YVWem2vD_}MnC0#ouJLnfjXG%>B9iHe|34r*YO
zZinz=7_&d4=}197rfI at RLO!I4przCiW-c&vFc;bfF(#nf0Rk8<Z3c^gW<-pT^gsBq
zawnw`F=}i9`SO|;uF+p%qYC})JHRYO^K~}jmO7?yzPl#nMzgh8Qc!EwEbX^Gxn`9&
z)bmqS(9UmTS at M7qz2MhHBIPADO-(#^gd@?qwpzwgndK_m%o}kVz|*_?7oMIcd5`ss
z at Xq&Scu(}WyjebP#`+JB&RD-B)8)Y%9Ny at b74t0XKF6anespEs;t7a%hwA~)Ao%w7
zF7cF>c)FKlx+(mQcZ#Q^`&`JLe*6QT;_fl($oOd8CeI-d4tSSnv9FKIs`Gfdw+Q!F
z8Jj$Px^MDKfT}(*&(JxZ2{G!5?eg?Pq(Z<<(mTU54Rl{h&CzPUIXbHZQRif4B9X6-
zet;_7Zkz#;(K;M@;O at mCptv$Bt^h^B7mqh|I4I8L#e+d{t}gBliux;l8*x$p#jk*(
ztrXt_idI>CEhyt(1d0kRJ{A;ni{dsN&OZ_qtDeP+Krv at 4o^I$QP|Pj(cs}Fh7l9(F
zVlxjY<~%SL;l~dU+<U5_iwqrL=ob~5|FogMGIWKZ6AX13diyLbe>kp$k)HRCQJN0X
z>3cT<B)-DXX@(XUN+$l^ca8j`hHf`>qoFGdon~l(p}73wK<7o?IEP2kXni>V5k6>~
zSBKZ4P<kODX{eC-0FL2JjDX)?Q7OF;$GUDg9)9wl*KFlC;q4|2mhf*kVXpd6{!tS?
z6 at G@9IsRPK5C2XbRBsr*b$w85!qbfWJR`rtgh!dMHQzrL;ogQvmHEh at BdA6uh3`uW
zKZX1_<zIk4XSipQJWdQt51zX)h7Z#F{rH%7O{AfzITVeCYVis0aPw?_x4ax*zYW)z
z6UgiuLVo>yT{#2I#<%2vO_Fc_;#0%T1S-Y{@j=|C3Vh(bVtic~->R;_2Y=&fm6x|m
zD;TN|HKd*3yl`2?ylQ+ at 9R}bNjftstGAokzuF&M4Bt`}0quAD0`?^Fi>JPc?Qk4_6
zN`B+JEA^rX!qFhLc16a=;e+>8Mv-a7oocSL{8S<zXXRI)4{PMtgo6u0(H49|lI=Df
z<r8q#6l$!k;8)+%)zvhwOVrHtS1g!|&grn{zkDY$Zuq<ozPlKg at c*>0MIyp4 at J-C%
p%6034xG0TA8Zo1dtq<ZE)B|VE#D}(PLQVMUa1}ljUdFNY{{dwE)z<(3
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..9b3a9acd4a6cd0a47666d4f21cf647ed8fef2791
GIT binary patch
literal 61128
zcmcg#34Bz={h!@rH{lAqgiAmO5)eZU5+H}7z(SNu2!u-%mmC`s$whXP08+&p1Qook
z_l;LQiuYNywN|UxR;#UNJ!(B#>Q%45{=eVf%zOKGlUU7$zR%A7X1>4Q{N^{un>TOX
zym`-m{qc7xO1Y90{@{|~)_d at m0f%EhxGxEIaUA!$W?alTIIJ*qD!TpzaRh^r(E5n>
z>+q7&6-%OF%h$`TebmQfliyKle?rM>Gl_KsgKMg)f}!<Qq2@?1Qc)QU#_H>9^!QAK
z>tKw5EEO>{7_16MTIw3t7&Knrh&X+_nK{Q1uR9p54pp|U2|}qz1%tDe&sco89V6RB
zsHxS^lX3ch#;COP)i+gjs_)$6w4QcWB#x|RO&$N8>Z_=%Yzeioeq!zG)u>~BYU=*#
zutSsfcB-$gv8IXaczxgMVo-hO>B#4=*YqRQ??CPCR9{0ym8gu at m->i~#5T+0swXsc
z{Kx65Xl||#1sf|GLd;6MzFtP(9#ei-|44mJmB&>v&3JvU{7PGrsfk+ml<`DK*Y-76
zRK at H2Kcmk&g)aD!`XU>eJI(L9$F(7UNz=5~Z=;48Uz~kaO%1Rs5^Qa3uWPIh2ItRm
z#wdG1hgO?d at 4uuJi*ozBN)6JiIDMhoU`-2ZLo?&gw>$o*@nTaSvtQBrCcmfqsXj`X
zGslXr&$s%zM$s5wezb?j$>u!U{HhL5HTn>Wv9AEYP&jE{{d=oqI35%tJ`3 at NgMRjR
zrT*kq3ihZnI35Fxqb%FDNfN#ve=ME7_1*H>r+hSY_SWxapS9}E*<0UupRsM~#LhbO
zBiK26>u>TOixoQM$)QKDdSdq0CuX1Zvo~W{{rlA9_8)bs7}S5%bj9>m{e!`p{-aQ{
z49`Am%1-DtutVJN<K<^8E1$FVi`iShk(B0d{g0L6e4>vZJ>ys%qpS4d^~Hy0KXrt3
z=b)*yboNtHva6oxKT7PC<jz!?u2oO$=rliDzohJD#wFjF_moM;kwIM^v*YB;%dEVi
z7G|IFWa_DpMN*E|u?<1t=`xM#-!|Q6?9u6+wcgb+!OqK{>BH9VzjyUzqZ^t!Uu6W8
znlM52&M23wRYAtsu$sZ1Eu*TwqH#?|Tc{;m*VLGipPxH1cT&c9L38r+Cr)CxAa_d1
zL8_*yX;N-gbF<1 at 8isgYWouo1b-2EwEtFT$R*wsHIFiRdUc7ik3`eTbzvZjSif~<(
z0jE~gR<vYifOYV};2nH0!@)>PMO`E;yu+N#ih5kPDk4oSnw4=F^f|Q!(YZ7<HBODR
zw1&W2xnN#-WD?XC<aa7JXMSaVX=%Yk3 at U0{n%aZ)p~f|l+F+=qrKzQ~4Z1tRKV4~4
zYb4lI6Kp}Lh8#+ru&Qiosz-9++NPFBu%RNnR)y;}hJx&Lm7Qm+RH9{Nv!cbZa)Hiq
zexc1Y@#ZWj50=>AoT}2&(qa<~l`bwX2sT(rg;aA>U1KEF0+WnSOzBWpwl+I`)}9J3
zX|_~ZH5Cmz3NXf+qKfM3mQXlcy0}UiuWAX^gjzz4RiXbLX<n78YHCDVvrN~a7!A5)
zVp5HkKttKQHdE at Vz6obQYh$=>O=GA!14R)ve`;G(U9~i=PPFAutPa^lT2|GdqQS0m
zP~1?lKFG>O)3Cgh?L>P~HO{4$rVXWKRZuKm6`a+qq?N?hRIsk0`6pIhc7{G_>^jx0
z4~^1liBr35c-a{&F-t>m2G3Gmh%CF{th$<-C2Y!ezPi&oSwFf`Sp{}IW56x-?gXVd
zW at P<9&yk%`Q&AsgA5n&ZwcW_0-A+c9qmuI{$4bm8t18W(Xk$%mv(XT(tgefo_pGR&
zD#<tvvE^dYV&~Ub5y{Tr351jbtUdrLIHv~ZQ*EdbCqpI1OH(Dc8F8)fN0nzx>*NW~
z7Wxyb#A>3Yi|0YXPmDdOC>*K}Vd&S?$V!V;V2srQU-JfChb^sDEH$J1N6G#~3-Zy`
z+b5{>d1zJW7xRnQ->qq>sMnTMG)CrB%Eh4+^<c$NJVW$p(LsDFyKw6aXsf7ib at o|Z
ztFLOS#EIY39BScJEkmvY65Bfaa22vTgCAMRQG0c-{)0K3h^v5-Hu}T)vd$L!irPh%
zpigJ%r(10|tskxr)9`SW)cs~R%EyXY+I31Smu at xj5_Fh9s*!h{Hijft+CNU$Pb`8-
zJz%4we1h!z^`IpfY(bxZQ>dYtm+}yL>594*$92OwR_idD_-P|Q_Lwc9W at p!GU%Kq!
zNC#VjsGEj;Y|zB$#U-fEWt0g_#XkpmEG`yOMKjAvuCAcf6_E-F6XP&Y+2apArV7 at t
z2W!US#WRiymd{yP8eDQzS!s|_I81A)XvcqhQ%iLiG_C?9)6qs!P|&#q2Z;Fv&MKNy
zMJV4<F&s7miy1?emQIoUmCmo5SUSHFO#|UIp@<B2L7B2O4*%aJEhCRP)hM)?6^(&V
zX+v{lL!cszZn at LqakPoJW|W<gZ}sbTr}jfd7+W^;>+(@1IHjXy@}o-QM`$qv{h|&T
zO1L7+rvyu<)YP?vS%*R$b(p`e6SPZtU!_zS4snQvylKz>Aal_q_j&FnhubTfap^A(
zD*7;b%!eybjm=Hrm|JgE*N9PSMLov%Ey4P_a71^TI6*2yYw8+<9r&i4@(bf5qF0z~
z?qNuNNN$SgM$rrXA<0Q0sUrNVU}>{D!Pzl6Yph#6R+S$0Idulx>O$>vsxYj at _18Hj
zbIewV3<?OB_!{l+py9t?)@0U#{XG at 2xH{-y_N=qJ1GDo^xwN93gN8{#doX#Zvyh5@
ztQxz1<US)<hgkrQOuMDa)F3iry8rwiZAM|0)lRghTj@`((oKk at TM7zWEGx9f+<)Rh
z2d2A1(ZY!b%uO1vo8~_9Cl|nE%zLnhBI%axMOC)(#@8)1Q>u(1Lc68H>KeM$4)l~9
z3PO9jWq@;zr8`DU332cM8-#Ytgu3;m4fdIN^r~*@D5!`)3Fid5aY9Y0X~7*g@*uQZ
zDkfJ}RIP;ulI|&Brw0YP at B8UpT>hk%P(xE&D2Tg at 8Y$73Fm3v&y{4@)+*%W(Qir>v
z(z^blEACE3P3C+EruZ5f(AzX`=$4McaBC&z2TP$t`?{s2NS at TSgi3i;G5*99H8fCF
zcS^;!MN}YP2`MSVY;i&g8ZcYj6DqowkI6Nd2xP4^U~t~e%Y)XTCjfu?#Yqf65p=U6
zbmENPt!kLk5-kAnCZZ)V8 at gWxCKKH*g#1Y?grMA=;rUXuIoMFQN+n)xH;X4;P4~;G
zGfmygS%DN-eFYv8#gvypdO~S;ODop21PZI8qV8p@$kDhOo8k&gw>b^>nELJ(T_=_%
zP<~x#>s~GkqYbV at 8A_u|qzF4I?`{cp)RaI0cCHMQaJUy*q8u}c)?|Y{W{aC<EUXCg
z`70i+Eykr*2Tc6fM~QLq3PS5jtEyCJ9qY^t2jfNRBNVBZk#y%G_ILwDAs5;%l@*#h
z6bN>mV)TN?hfY5r$Kfpof2;sS{||_oaiWNJZJjAaj3<A<ydpNl5IV&=Wqg?X!E(qS
zEa?1#NK;T(DC7{;8SL8b{Cvn++Doe#%L at Haq|iEBthBBU)oTa4jx~u{!d+VvAEC<Q
zR)=i2rj7I@%M at n~c300rOtSWXIpvW~r{j7+b8Lg|ZZ at 5*u3I|n390B*RIt4T4^J4D
zP9$!MC9zcS5GAUd3k&3leC%p~Zl%z1GAuzgrsL|C7RSWaf1S&UuKI{68$Gwhxy<Nn
zL=W5IcqS8*w6j{Y0g04_HPe=8K6*+|bm}u<i_H9IqIw)tiHWMRrxO!Z)XAh`_gbGl
z!I-E;UCc6e%c^2L9maxnnRK+giFWCQcqEUf4W$?eXkU*hOjJ=3><P7C;L||M=u1>1
z*L&(r;`ND|iq`rFh6{C^KJ64wG&ws1&eb~Is`&g#;aaSfT^q!(s0Ie(5v4PnsG(D;
z>O&P=+A5UVtht|VS!+*>C#py$bD<=We%#WLP>%E*dxDnqh?3^{e4d9fqO~||f;`Ym
zq=cZd2L^S}lJKAoI`+}PwGgl8 at X47jI~_>$tclU7r#us>21{Msom;ogK!>iL%4N)r
zVz-Q9 at 2g9`WAEDu-cyF}qZU=t+#0UMTLyUcg;l<mKT)HLo12=o(l#s|*4{*Q+RykB
z?T(#_5^3qy6T?L9ap+0J9D7Ph`qczGc}rPO+{atGq|@q&4n|L%^-Kq2>q at kFTDeTT
zgRwO2qca}sn=lH+Xi;B8bSUB6$0+TAO1AX%NG&^*^;kxGpq`CcvI^BP1uzGB#zOO+
zvb1yc``Y|{)Oe?0!B!ZzQVmKxiI$O3*Le}`Q|09)3D1w>zO1>vqKc)VPh}HM)b4n_
ziJ#35jXiNb$ExeW>?VFv*rs*fq)_X+suH|B|Mz6DKvtF?Br>A-QK|G;@poBb|BG7r
zf$l1yJ8s8%r$mQ|j%7~?wjOH at mwrT(Q2wUKo6ekakv%*T&EsUVhAvS(`IGQwhV^Ef
zyzLwlW}8hY+xm&89?<rXGIoqH3x>LNa~gdV+e2o>K6dYxO=c}n50#c<Wl`eA<xrMz
zc^O?jP+;+kf_kXr;??#{i|b5l!etq+v?mHRcJWY8m1(Tj9xBp~N)s>9Se-plpq;EH
z>ZwxgM0F1pZ5NsoFW*iS_e3FgTyfM>W!zD74;69eiW4v4j(U5bfbFGFQmhFZX{)pD
z$r2rD#4GH9F at miU_1%*h?s;{IU*PlcN^V_aTSZG9Ha!SqoaziR^NHLa<rm}SR6cSH
zR$#5Nev~Om#DfW!GTv#g3(LFJIt$vLsQq}=Ro(^`o#IQ_P^ZcS3%8IjB4T$X*)>Q%
z+n09}olwH|<|7r}8aPs68;OMyE$4i^9nGxBRsu0Ov5~|xqTj%Fq+#VFCXIxeJGK{*
z8j*DtR$Z7kViQt4*-<`N5F!g1>;eOjc<CSo)~S>QQ-~=XlR`pSKv!T}Y&OB+PDUNk
zgc}o5va at 2P6q6kTCSGV=rKDe;HOZJag7w>=Kd at g#hg}A`w;4k|y29w$8J~ZB8uwTM
zbd^?uJsb9HV;16#?=iDG>QBsI^pSXpzDZ6RdJ=BJvVIBg+%<4511|Dd&16D}s)nhu
z6v_-`CD4;PdrDX0bDC_M+|{pg1LpsE at Uo?WM2+MM2ct?xHqqw{Oh<-!o$(V*HXog|
zJk{ayFso%afrJx4naO@!`n3Tw_%Q?jj+}j%9Ot@!Xj87l&R6!4UF5Utgt_NY!Z}9I
zBd;)9Z?|BD*MCdV8R37MK6j!@I7Jk-Bga;glD8i^GWK0+U6=B{&1Ki=_C$LsknSA2
zOx5AJK!}BF?@AH9m+Op~Xh9d?K8ClAMz{5HMi at JOVb>sbwOw+R-XK!86|pzDlI at y;
z4cK-@#+t|pUjD+>FJd-+(3`SiQ^_^hI#xDlReIBQY#6A5ZOxIEOh-7_7OAWc0 at Uv?
zo#0@}bBz)knA~2AZ57%S35{-$UAgM(DzUFEF1j^l>srSo1;%{wY~H at KhC^XSsA_7J
zeHP*nM|pRmK)+WsF{n=HsGKpaM=_m5wVy9VEybg{d`CfP<<RZGjM5l6t0+#;OX5u_
zqY$gHe`hcv+mlMQz|Y%+jOwP=%KDIM2sKn;qXH0lV-0pN2-0XMcI?$bPzqyjQVMC(
zXa$?<>j|%~Y2l>C{6b3Bwk)kE2{l$AnP6SboE3UY#<I3Lyd5WOk)*ONB&+HqsoEAH
z;bydzmGg at bp}DeUZKt~V?j40GU<v;h^<*=OQC~=Jq;tzH?cg&;q-iZPg8L%Hr-Qm(
zJ3XihzKU0jA~(Cy at -~7H?#qG6PH_lLDnJOdaI#f7QbRygEB+XtR3h2uoQ_RgqSF%>
z-xdW+UJ1lpPFS=7z;?+9h)O$T*`ax&jcRq!vceHD%Ct>zL}knxM}qX*=`mm@$3QeS
zD~@QlBiW&7Qg$??B)tW?fa;1CY)p^t%OH%VdGK)SNL`fLS6$bJ at VeHf2wq)iQ1v=o
zZz#IB8fDHB`0KEF3-)>DA2tG%>aW(V09*V>uto=KR84)8K4~CpWaR9Ss3O{G!mZGS
zy`>=}|5bXHs-`7`6I1(J^q$13qLSMR;xe(mE`rVzf5B4z<4!Boi2LL4hHwOVFr+e!
zX}hXgwJyw9IBO<VREF0>Nm$j(pZpU?p4YEe_?PS}$-HX7DcgwuNK<>2YS*ucf<~Ge
zDuIRxhY^McA$9ni`50&f!<u3?0~=0ZL&KW-iZ$5Ju%-^ZOt2DfaR$SctsvOU3V`gL
z6|AqU(VnWNrnPl|tLmG`MXp(@q0m}YgPqS%OLo;ZNq5F8lx{P4<qy{{6>P0k_!0>A
z9=A+c0SuP3N}`SOUk{ne`n5VqDB`JGqm!(usmJPI>?s$aBuE=+O*7u-h=7KxDjESd
znsC^n8gH}Yg4i=sc4NcWNY<z|&Dg6zCt~~XT5t>6M|-fMWer at Y0!<Ge2*I}NI at D&8
zY6~0HcA9NgqBW at VD#iaW3~YrzNTLH_wg at hD#$PKoEvKX|%^F=$76FTU%E3GqGBPZo
zNQf;m#E(1Z*G$l>sT#h7i_N^TvAV)$w<N(DyxGu*P2~BHPdJ2h&``az5A^Uu8!FP!
zER6sZVX=?hpxAF^Qi|6UDs88L<f+Yo!IedI;fngk)`mJ|JZRT~HP=>X3?7YDVi)|i
z#Kfbqs>Vo5Ju&fUth#OuHqiqn9*toi;pSRm;?WrDE7U?vJQ@?bh>6Ewt&P|OnHW79
z3*%j|5Hay+tQD_0h(7TEE3ON#w~f(0N}|KiDI1T*OzcRLj*Ys)+uqR=#DsCWqECrA
zb)pb_c<nnTRuo~MDZQ-N)ovHM_GxS3H^r`f2DJ;m-70zHtlchp?K84=e%r0mr>tH4
z+Gk|#3TU@#fU<TKXrGalvS)#}TeU!0yBf65$l4XrZq-ByWTRDKyhd7zsO~tb7B9O*
z{g!<(x<tFGqBa7xE6b$7zEdiOky$~~p>p`|s6zI!7SxHqSOpC_A14=n=qd3oegj9~
zB(+WG_!z9N*dP?6Yy>ypnn2oa;0=bN`G+H9tZBd{uZF&jP56LHjV at N4`t7Fsvw$|6
z)n;k|eWMWq&pN4%hdmXpBSLg1#SqT!c7)pNszdAw01+{r7N}fasx_(61Q%05>kTm!
z7gK?GF@=ZYRuCD#GKfpD1U2P=l_;;`0_(6na3!yc;b?oi#Kdrs!%zrzISg$tn<ujN
zFciXF4nwtC8HPe{Aw)4m=yY^zsRdt~@B^dl_VxzVZid;+6Nk5;ysk3^9pVU9gjfg^
zX3>GltpGi|Kn5XS6RAT-ZhNeOL8M8>1DujXGj7p?28 at fP`atz?K>!&q2qaf18C0k?
z(?Sf92Ed-b&1z^CE#qZ)L8!f4fA0jj&z};9apYees;cK1Ild8X0mHt7Vs_`8YS3WB
z`E`J9t@)anKWA2BX-~Y6H?ttBX;y1P1NMxI-{M$4h?3pms{#9HCtqZZH)?I%Mm72X
zd0!<~&`DxHv_EtAo~qyuACtV%Ev{!4$Yej}VX^hL^`OGB at 28`E%*QPYCu|*pbNK#3
z*^(f)!!r*xtgpMsqoYnXo#^lh3aE(v21R*3x9R%{pPq2;qY(W7g^eC&eTSu~ri+Y~
zm=Coy)mRyl?QQfartFhVMQZD~Ejf2UH=k?6*NFP^^GP^dYN_Sr2eEj#REID6S)ZZX
zs3jQ7_-xWqq=S~tMtG;8ooLzCL8OD0tBlCaU2D0+upW+zSl&O`P`UBh#ESKREwaS&
zn$M0Q-^beG#`C739~jz6ruG`v*IkQ1vmCt*?L^B&!z$@oWV&I^?OLSFu$D(fEbmb^
zRAvmd$!f!@vqd`8|7OEFBPwEfx7tt##XAh^5?f at c<-OU4%I`4VJEM?on(;hlSWnv`
z9W2~qSg&*~ve&S_?pnn9z+8&?&>U*Y@>*ZLblKmKv#oUbU1QVIJxOW4A;Z(&I&nY0
zYXCks=Pq$2;mdtVBwJnhNN2L!RoEvftxunW`y7H#XL?4cIqAjtD4n;TN=loPPITIS
zQ}-Kz?{TIK1}`a13#LZ-6z`QDqo#L1h*FTeK10B>66hO^N4*7osJUM*%%S+y{if{)
zTMG~?%>xyaVPXFc%qpNhvX%1Zx*F4T+&Srv*aM=t15J;jwlqGq7e$RMK0TNxc~xp~
zvTIJdW&DuwC=?nzlx%$DbRr1D!}7quhyBt)roy at rWN6X-^H3!tqq#2b!`zLE%al?X
zCQ3i0M(awT+yRd2L2!(%r%$x>GVOYS#8{)ak0aaT><sp?vrXj(x{bNx9kmDips2iE
zAX!n&)`2g|<tkJBQO!zaN3CT2=X5ZM6_}f<P~&}uq8RgX(O3s~rw`q at U$ipO43wJa
zQSKpD^(vJgr%9;-w`>1&y8$DyNtVd`K1U9<%V2+`GTE7f4%{i)=HfnVa)te+dW*&h
zDb7SO9flUHREbZJgU6vx4{@PoC^dC7pd#=NrC6UnhrxSTK*Xj|4co=^K at y&UmZAcd
zfsSIF=`?LB&j5TVl64{t4+=|jp_|3!h;+DxnOvU1)A<N~Gjq0;gp)I8keEA{*W7tV
zz~fLi-)aL&9ch(?QVZ;J7gj9nP)}%uVr-dRPq0v_MU$0#sAaHHi)X77(|?8zuKW;W
zL#ZW}p6Ybg_z{S)R4dSD{4&a)%<L?8N>Xlx1#H}p!J`lj3F&Amb)NqAuTrVfn<lG?
z$SjW%P2`__rh7HKN!9pEPOioOP}gfd&vOIe^PY&P4Y?STeBgGa1W=sY0l2Pnd#B(-
zp2GOh?Mj`2z-2Jd<x5h%JS$N+LtWma-e*FCD>X^=@eBn?T at CzxLcNnz>d6TFhk-r_
z+>Jmf75C+LN_%;#MZ+8J)V1&|qSRY%mD*wj{^m|i-H5=4<h<?nsgx{O)*Cr-?Q-|>
zoDSAd*T3Dpc`<i=>PGr55Q+a4^YS^AT?U~N^1nbd(WcNfxxRF}R7wkk&cH`8T~|Zf
z{i4m4l=>(<>6A%=k$qoB>y`YcC%L}24p+ao0lNkzxzg4_QuUYMP!sgE5leY^FfJ^~
z5WB{$#Yb8E&E#t=!-?sLnvrQS&Ws9YJ29v5VHV?D<jBW at H0q~!VE7h9^#v?0WB6Da
zCfaO^K}$uS{&U2g*HOg5t+KeS*|yS<6EkL9?nC+18iw-Uf?z*CptVV82+EcA0gX*L
z2A_@{Pxwl=|Lp^m`VIXJN&f;<SAb7S)IVX2;k7z>Qh@#zi?`m%6Z8DfTD*-;-e*kP
zKOocSJl at G;i&Fk&;59G at +mm*nt(eA;;s<;Moa<h<|3ORSoTOihh|bYq!2R&yTi1PV
z|H!dQT|h18I<@$#E%*XwO#dx_aluutOOle4L39I584iV?f#rI@?Jq<>Eh3jC9Vj9?
z%?yYfz?cuZ{r5uTeEP3+YVm((!Phur`VT)47Sh at qVoccq_+`R3#lSBUrtVu~l#CgV
zPm`msaorvR*8`r#+~1YNR%oi+zZ>x7l-?Z!e+PIo%kl0Qc<w<;T?ps8#|aO(63{;g
zKVUUICgGFH8?e`6KImks0VP>VodV~2I2PXq>>c8d#NuCD^1m{;8Zc`D$_vi*gbiJb
z;D>~MZ9)EjBRCrUnd_;f8unJYvHK6k8MB)3(@7tAELfk at Dc_+<{+=hsjc)&mmfY`>
zIK(w40yC&mk|rv(lX5q>{ZByddg^<&gFb(+9K-v42Oa(e;9UskdfwUa^@(=1#e2oc
z(<jW|E#6<8Jbl7o;G}iF>g4H@@HFuLz;bxg$<yh*V(~tR=S4dw<sXmI5e=U?rD&Bd
zK7Yg#_&i=f`5(1-UpRS=_R<SwS_$X+DyIJZ>w!tC!;>8ylH_T?pTQfGk2oWfP5tP$
zmji4)@eG42|49hG%W4{(9IZ~}f7*f%NRGA!^hyO7$Kv|p8WSUZlm%zTNM8;3(hNxF
zIZf0>`%jBk;N<B(^WaG)UZIo6c+O(qYDrCVN;!)CMN43Mynym&Og2f(aPk(R5$n^`
zf1D+-%qgIo%+ufvnSy++bn+y!&fG{aMWC@$0cS26Ezzb9qK>RQXh}79Dy94>g(k&y
z9RwViT5L(RBu6hCK3*V9uJ5!2A{_)AYWzhev8^4XbOD_Xf#=~|XLV|g^1o;aoD;7>
z`3s6o<el+6u~hlbg}~q7T<3SH-CUGEu%xc&TFO}wQ!#24tv7Zq at 2HJ!mgugoMV0>*
zOX{Z1r5pu1?qHMlElyFX7x~kz>MTp at -p-{Q7Jh1p-ru#T@~=3=B>Q0JQVt6rvP6H=
zxu~x9DN~i&F$6X9yJW`Imlj_tdLw5^Z-&&LDD`YIP9#f8662p5 at C*cA=nu~GR`<mo
zPWcBNs?@P?u9uUUSL at 1E4XBo#(qCfWTLFJZ>9>+E;y~P7=lUL|)Gzl#_#LN>cITq}
zM_B^@bPCvoD>+gA>n*9hok}VHUQ6KLP677AMnlOorFIX4A)h$~9EO}>34G at ih&SX<
zmXz{1%G{PhS2x|H<8lf(3^@)0k7KCoN_Gl34EdEMkmeMylQ8)iGQ+6xbt<L&^_IW@
zr+~wdM<MXZ2pBTRDc~?<P{0U`atg#7a-1bKx>G6Tf5Z|P;}mch;+u)<=SUbb&MDw9
zWUVDI(J2sb$geG_f=;EBf8;Ea&Sa;6!;n at 8tQiGEikt!tL!P$;W;g}n4H;i*)XeNu
zO8GZi0;Ns?haoRPV8l=uGTU>ged?K>cI at GXx5~-0&u1gmW=S2}wUo1$c-oS$b;>hm
z%0KuBlVY8d7fn%1g)FJ#x|T9+_il)KXCr&3dmLlp0qKD12ygM28y^2A1fM3f%_*7w
zM?m|}0ep$4AG$kzca%OBh at h8wcyF$Ipn=UmpQP+=kH~2o(q9CWH5c$hQU^x(5Flq0
z{Y{MU6 at We={IpZpJx{4JIM=gI;ekg3x{dH2C!GEep#Jj#|Iw*qB#>63e>TD&qQq7D
z7C^5P{)>lz$>6^&^fk|Z1FQ_DoPo~xQ8#37a;KkhB;vuj-gL(M#6sV8#7m#M0E03(
z*LzOcn=JGn4%va<0G+iEvL9<RRr)-Heoo|T$&N17fj0p8lxVV77k1paG4N|kz#A{1
z1|D8!BBvUjG%=nQYTyp=-hy+DaPp#UFxICAehAt509_-0jJ!{p at W4t$*v&{|9Ff$(
zCjgCH40xP@*(0cd1%L#e;DCJ};Ivf(Z?Sl at oV=O15UPQh<+we9bImb4UT%Gwcb&zX
z at 8oHngO@1P4Ch+r;HiP9TJW(B*qHIH#S1xkI;qG~+|j_f>NHOc{1~D6%YYnbq>*nt
zE#QpN(HZcZet=Scg&V{<uUZHW9xxG;jIMvWhipb at h!y_QGvrK!eX8H!5VYkdxrW||
zGhR1{bD<59JiGDla;<d_*aMFbb?iFI?M^#}+yP?|3=vvsLHkKRfw{yB3A_L9Nq<5-
znC<N4<#eI%*NExkl%`6#1Lkr1(EX9eo}P36!;>- at Rl^BS_a~n8ie&16zi(W0U!&-#
zg6uVrasSIR at J<h=d6VGxdv!9Bprn=l8F-wka3AI+;CqP~NH4&x`q^;qnchMh_3s8U
zI0fiUl4erWW=T}nng2pah}3PJOG)kd=cg)l3!MAUl5Ubj)~WmNv3P$mJVr6RLA@|%
z0Ox)~EQ^VEzr}mo at S^dg%8x*Kq?Bdq-p2j02h}kEMd)%TCrcxljerPp6rGZc61<ls
z<4s0&&lkbZy#0=0p?gwXX&YEl{u%_g66%xk398MNb_(n9J9t&f3Ghlie&tO$3x3XZ
zxWDoGFSX+IOBu(3t&URwuS#L_VrS_7+M9A2{G3N|f9v(X1}gRKGwCpS-_`uv!-xYW
zz*MQ^A;vZz?GXv(Uj?Sr at _s3dqEl1@wgSF|SzO_aqt6%?M#^mvmKOIPFUnvzL|yLR
zxQ7YvQSijl-?^3hA+UORo)>{Hk~)^AZvSGsl<AiuKTsO+j%2%b2K^37mjgBOyOA}K
zKQ|fb?-udW<UuUh&k(TViMUF+*{ZVH6#q)ZpGiu`<4AQVocpgyJ0RhE0nr_`^ZTUX
zXM<~NO<~Tip!^^B{9rbGuH*+?BX|m*iGUh(8MK_wDC}A;hDYY;X(;4W$`@dd##xY@
zjS2e+ at VJr(y1jGYc at y%<gWaz5g$Qh*$T0U9H14!_!B8nofiwNdL)?StXE{r<=K_S{
zg%JIc{2VAw!dVipSfw8T)F|FW#sB*6ilNVQcyBzUa9 at +^DaS2_^8A(m{#*OuOin{N
zyq9_o?>y30 at w(w30Z8BvQ|}bGQs6THe?sZKsXpEw80oJp`18~Pfkk>isK35xbAO$x
zC4KeOGN>JYFM%gj`xkinJspD1`%`uKKaPNFf2|sI^9M0|Y3j&DeUxHUcYCTz8ub)H
z?xR!FMp0$@>j*9G3#3J|q0y8~@Z^MCo|?V_T#<-Kj?yMEUdloEm(y=Ws+h&v$l!4H
z1&Hf<d5J#Q at gAtleSGR@URf*yPEJjmMMdeOQI4Yi5-Aytrpy6P4ER}UdW|J<sT5LL
zIpd}9Nrf12LaG!;i~+hlXn;!{;F;`4yY at alhR=bnKs4_Qj>kZ$$AS9`qUgLb*=E_u
zyuV3Z2mD&%tK6w$*CXKlt1In307{2m*CF4-gvOl-f!|Q*t)~!nvb6L&24WZHqgtco
zV+XFr?STe9jqrZ5Kkwbro~2;sc=-9G!TU_6)dPBeJ8lFJK6CJX?vNd~oG4|#bfT95
z;WWSZ8z=f25I$t^ez(n$+DQi}dB))Vy?+Ime8k{&xf~MyO91idfHye?eiIO%4tP^y
z;4y&sbimuk#eADg`GbJ at bikVy178P-ow3&+1HS{96YbuCE}r|Ak^=#8qTM^xRldIk
z>*CF{E)d?|`PV{(^XJ~-9mM>*fOFE;JI29N{tp3hcGi1P44e&!^CR9o7i-1XF`xm^
zU4$pOOnpif4|oii2i>$6kKCp0Xxj#)1LLfWH(=pxHOjvTI46C)3tTz8XO;%wV~;Ko
zP0p+fkN0{11rX-^k9UQOPuNTZCaz`ue+82_o8F*H-)yo;`6#RWnZSit=j7Rujno=T
zs;O%!hjsp2E%`R5JR7d^e{AtKIeF0(wbVrP&0^QdT}zqlMIg!<DDPHhfiZhV;66)W
zr&FNCDpBSC+!DChDL_M<nVN#WT++F!Qz_+-K!7t)-kY2P4nrQW1nzVSI1KsH61dMP
z5N}8cvL@*~)~S^8Z-4-2puA5z1ssO#u>@Xl3OEcIf`%;`UUUk?8&Y9Oz1FFe^4|;r
z&OmwJa|$>N`Q8%vr&GXTNGVQf(eQ~=Al{I(Evc_Nl~VqfAix<YZ<5<_QaKEn0;UM`
zaSAvL*=z|6a0<j5@|-0#tWzoFACB24&Omv`I0YPrthWRvI0YPrJZ=dTI0fPj>7QZJ
zIk;0PJu*8QLiSCcI<N$t_jpewKv&9B2Sq?Hg-hAvdx8DMOYEKG;&=_wr?YMad6wQ6
z*d6<>$2CL#RMzuA|3%Ip<2j!I<!PPrXZA$CH|;<6XDVyNXnjFQd4*wNtE?FSdETY`
zHC9|(lvM}zIdCbjzDsTLCxTk#`Czd-O?kaj_5)x`F5ix_C2eL$WxWY at GJGlT-82Tu
z`KK~zdS8OS%NhhSjo$Yq`@+wf51^Ic2NFqZ;wAMKf*(nlMAc2W7wDhK`6og9Zd at IB
zV<xUY$z$>78Hc~k_`_)XNK}v8 at 3<lBe6a75TPL|UNKaM=B&RONx|v=FXS+bzSb9xW
zS;OH!60X-_v?=Y7iO5|J1$#|*rIjM&qof)u&<q33rPR1pkm6XUS70H+PS)5{s9>gs
z)VPZf;zNdBrPSrpiKxuUQ1S>^z5kHgC;w+qk=v($<(}K8XbVIAW=W`D>CYu}_}xN|
z*dt{2dqU>8 at +moYh>&>&LgpVS<j5)^3r-NS at O&X<w+mVHoRG!u3n~9j$daK2RJOE0
z$g<f&R#XaExn9W8=LtDx7m5Gk`-NQcjF6wdCgjrhg<Sr%kSjcsD0$@&Ay*wB<eJGs
zuAL_2y17EGUn=Cr)k1cy6>?LXkeg2ua_e>>w_POU7uN{6{Wc+Y-Y4X)Cxra+IU&1W
z5pvHvLhk)q$o(Fae6IfiAIYdHDdbVr!zC1&C1g#5kh%+n9QO+$YabQTut!MKTSA)E
z6lz&FT1ZQgkjP>oZ4E-!ZxQmdYlWQf3n3 at +`D^Z|%`XT!>2)C||4Yc}o<j1@>?>s3
z7$Msy3OV~wA?GX*a(<PN3oaLO;r&7`dQQkCZwR?`uaL`n7g6UG8A7fq6ms=^A=iY3
zT)S1sb=Q%MZFpKpV at U}^O;So@*Ig)~mRp5{9~KgMUP$Y|gtU1NW`y?rg{(hV$c9Bi
zHr5I`{yrg_{v_mQdxf0fKZNm4%oeiwP$4Jrd1CI^lN*JcvPH<Lmk2rSb|I(#TF4pi
z3fY2l8WFZ;3ORF{kZnOB+na@)^)n%7pDE;=ONH#XRmgew3pxLfLN543$c0HbcXP*H
zw4acRGlg6>MaUJ?g<Q2r$kkOsuHPu+hV4Rbyj;kxUyzJn^Q4g4SA^94Q^;{ihmp5-
zsF3;`Aq at c`jmw2J)eC7pS;)GJg|z%aNcc%1k-v~+9mdCmxmnY^(@3U|5HjOXA%Vq0
zX08!3Ym<=Dok9-3LC6sg3Yon}$eeeD%>7!(y#CXvbAG0fBTIxVC>OG at T1eRjA&bry
zviLfZ{MNgLv`Hh%Z&x!2t`|G=H%L3n-*~ow$6qgG(?ddj_Og%@J{59edVujZX9+o}
zRLIGzg`BcZ$f?_foOX?n)9({<#&bfpydh-k=R(fxGn2};jT5qcs*tl53puAj$j&W7
z&bwB~1&;{1 at J~W6`j?Q4J+r9gk_;g~FBEd=d?A;u5pwy-Law+>$d&g9xoVG)t3MEO
zO|MdFxptJ0>m~}h{%|2TR0z3olaO5(3AyPmAvgbC$SvOpxwY@%)N<SYLVi&!<n|Rp
z?pQD6&hv!ab)S&CUlVfA`$F#hPRN74BdFz}(Lx?B0?FI#QgUGG6ch6c)?ghsoO at 9+
zFJ}{va^vb&YljD21dy{3xKOu2%;m=H+IjGp*|mR8z%}(zJZIALm@@Zi&8|@&=j;&m
z2}X^bQTrM(Wk!uD$c!32){I)7Vw#K#=UR3kEb_x8zu*!pXCz_GlMeHaIBF#(M)vlH
zNuGnVQ+#?{;F+qjxpJ4y)pKZSz7M!(M%p<XTTz*h3^i8ZGMC_L+-L~#{@$~MTvyup
zkXGa70O3rAX9Xi#Xc!3REIh|JP#N`H0#p^aAe(&QGNjb&{Lw3Nn4ug7dtK~GYo7 at C
zDEui6U1A_=Qj=0vK<ZK#78tuy5Kp8nh1ZJ01*555xnvZyDih-6sX1izTIxz$5>+nH
zG6RY7u>!3yP!&xW_v__m40Kcj!cNwtH^Az3w3xyyh;B9cBcR_hwN;XJx6kboZVT0!
zoZk+9YHG!l`$6%B28vpcYFAn|Lz7-1KO~x&7mZGS2PieC*4Ubbn=hJGVFg5sxJ0~o
zBigguRkR4Yif5wLcwL2 at lPhe2MBx^SF<2r&HnAf5O6YS=c4yuPz>Q{=lv~^jBqg=*
zNgxN8 at M%c#0yJY!YRPLD=$HHza1qfWjxh^AV36~_g`d&K3ESec(cDs9hwwSz)V^pr
zL)4*H6G}ORRtl7)3OVsw(hi^`7cxck6&BM+M)B`4&*w=l<h*Q&WPn*ITtPmuLN0eN
zT*DxJB@)CKMwJ{-j0;*yPNR?5Vf-uP5}d+Ih|yQX35ra%Zcg`mpD+9+Ia`K9hBt2|
zk25Gf{uMG<!hwIuU&)}akiJ6kF{Kho<STNS at e=w<=qr>UEh-M9MpKdtN1_s^9f-fD
z5uVPwk3v>%VIiO*@lB_X?YWSDB at C8Gkj<;)SaLrmqn19w_*ckaAy1VVnS8D=2<K1I
zn9TElj)J$ZuXqATvM*2sk~Vu2aG(5f{$KY4fy2m}(<$q4vKGq3mHe?~s=$#%m&T$-
z*HW_P#j;f37^3B|sEJTb))8_iDJD7WT1(cE!eYAmMkdfgbV)2~bZsPSK`cuJP9}OZ
zt6k5)i7x2 at XPybxZE*c7qq&#pn!OvWm&iUcYC72}@EXvxGSL||ZRWc`dmjb)B~f`P
zv6%yaP9f*$C`W5L6lmItculi_)>6JMDleJ>O_X05kG2t=+gT>Eeg at VVWG|9PI at KKn
z7Tc++%qMZPa}hw_$l at zNyspfbfZPo4fRV*_fq2|<&wL-e=_4~g1 at kd@2aYWMEt#pA
ze9Pk{cn6Kj^x-b$b$ADlD*ii2iaV2!pud23$f(R5Fu#X)=&0h<mF#pfc at H)U-u?E^
z<b7B+y(2SuFLp4!qcV9vHk;mzOx}|%qjz*B at 5`#`Js^|!W?_2AWb*#(WO_42?@oHh
zi{8uWJxKK4OmCLxy_enzqW4L9vqkR<^yY}(H|Wh3y&uz?m-#Ow at eRDgGvtg*J{oV|
z<x6Ke7~T;h1<inW{|rG7f_G#_<~Vc~li<x*Hp`QmQJ!4_KPw|+iON3A at -IzRnF}Ep
zpy1K7Jid$-BFIxa<0vgC{*|dJb3Fv-P_Tl6$BG~;CL^c?#lJdL1r|~0^cx|r&!OUF
z0FqM!tB9XLBh0x~Nni^TFu)oD+o(tbSq%VM30`lj^L+!ws*tTKYZF+fl6}K4+zCn?
z%`V;sG&wo2lgyjgJvo?xONicRrz=r>x}{!4)~&V$PS!56Zs%1js>{T>gRHyQ*5X;E
z_mg!EmFGV~?{z-5P8E0(fzb!aDJ16w|5W}nM6;yJRDnGVjJHKp;LijmL{B at 3bNCxT
zGfoM-OLCf&?*4@=p#$)L#O#j<@6>kA{x<`^F-HG~f%D`nm2*AoI{@Be06yZVqkaU=
zk~CvGOz8xDTO_Ho at IOZ)*)l4B5My4YyMH^2I>OB1;AO%c&@4sGKNT3y2<J<+ at J|JD
z2wWVMm^lf+p^Vnb2?t-46PQ8K3pg9$b0|2R=q2&8^NC(&=h5`$i-}$#=$ay{BBg{2
z>k%$K3Vcs;pn_sgh?o=|c`8s#^m55%T;#wyvK|+fM0k|SwcaP;Euw<VKjCj91jk%H
z-g6 at 8#bZv$J_Gc*Vqhn#>@(qKnqxMnW}jvGPwJb!1Ag|LV@~#EUu5}D8IXNB{C{NJ
zQ-@~nw&YJ6pZzfWtjjT5CT9N{{?941wK)4(_&p`?pE*7I5Actof7|TrFX3NF|Ms%%
z at 8K7n=d8$1TBTHk_>S7_boj-#oz2-p;6H)*`H}4X;Xjl93)-{Cz%OwxUY~uSC4cFb
z?1}Jm#$?Q8J5(Y2^zojnk&JK5G1<F7CHt#X_AlU<B#up0g<r#F-Po8DRoENxqhWo~
zrLZc at B!}vCBNU%-GG_sN8A``2%3KKV8}McxA(xqd!aFRtFvzHs)lucDtCem5XLxVe
zeF*I}L(Qn)r2 at rZjyp#p-w0t<$XoWnG@|E5(fq>++~uQ)7>$7rkzd*((X5yzx|IA&
zqkLL5R|QrPzB(SBS50_<JPXsBqz#%l4P@??ICc*JRjq{Y7Fe=uq&E at Py@Hr4yi*Ql
z-nQU>zUMRu3_bEZ{7dh4<mJYfeB_Prv7S<oyx;hIYTi at uj$5cri&Hr7dGZ!(o^69q
z5}WsD@)mWLB`pwmivo|uX3MZXAnQE4lvH3ZfeR$}^5<ZEL6+_zqG;B)K$DII=W+qX
zIH}-3FQPX at MFVLBZV|wNrW1WQ9vw#X3aK3FX2mCeqC6`D{PC2zUO;=qsykq9Kpy$$
z+e!IGO=aD%!3T=Sk_(V-YSKMYQUwkr>)L3nr4nl;{);4PDf!n)1W6`;9)UYVkIG-n
zz}Y$wIGTYSwkj1^O<-pf$X`R?Cb>SUtVRS{30y+O`l8A5R9VLZJ(Zj*V>u?B?PUEz
z)QWuIJOa1dfYx97bE5Z9L*N>EAF``imEJ_)M#c!-N$;*GFK`cmJ8f-q)x3v at lsTHC
zw8X#@gl~2T27X86Rzdiu0)HTIn=OLNH-SfOK)1`RH-LT!ci^9*akD-J at IAr5IKY%3
z2E%X%zUcsm6QFy~0p<ZXgy6>xa3+9-1V43v%K=mo{K^5Y1<+3L`zV-xB7kiKJ-RT+
zQt9UbxsqrfCwe20UlR2@(FcM2mgrC?`T~&Gh-Ny`cY*wyXqE%b{N^yFz5;qshTI*f
z)#$66GyT)hgy7BA=rDLE9F%z=&>VPkGBOL`EhIWYZVhI`J1i%w9Aq_I?j*@2r&m>0
z9e_51B at XaJ0Ndg63LM}C0Is3rGzWMKfcpr}bAZ1B at EpNK4)D(a-XXZ$0e%eNYl5pB
zU{VFL2bWvr0QUnhj$oYw%mXl$V3PwZ1yD|~)d8*ou$Ew{4f;6qtpX9Em(y=f)#Cwd
zA$UAX$ft{GCx9ymo)iTGHv-7pU;{qRsN)<XdOZDFVdi7gu}J{Hi5Z#C!21Ne!xm+}
z1n*1qE?nT*JZygU-{AiY*svp2_Q&vZtT$`{nsp1h3AyTS#$e$;;1n0k%l;aaIVqU0
zvR#$Ne`IoYs^wphn(edv3;Sjdwftqi>`|6~(ZK8jE&t-7*?E?~d_;DU<zJGKJsp1b
zi3Ll?XU~P7-ABQ)i7K!dfk|tmK&9{ENDtT4qY2k`fU5|H1(qSB?%Z`0Y{IH0wZ%p;
zm$5do)^`%k at Hdkm5x$HxjS*W2>;B5N&BWMAmhQOh7>4z8vMQxU8A}DOCQv2z%Aakb
z3hW}QT4Xt-HU0JNL_<+?w3>T}*4UBF4aq}9>l~>)PGDWU%HI-g71SZShv*KuOO#xU
zo(X#kX=LEfWZf=zh*4JHb)t95t)T;bkLY=F$+J;o-p6F^mV1tP*5_nhAh(9`tp6kH
z9=SD)XL+l at +8ixR@>QT8(KBLEGyWSy)}~mN3XC9nS}bZJWRi74wDfff6NsJ|k4_?b
zdMs+x975LF(m*8{$q0jL=1j1#v8I~5J!*j563wg!x|5vqq8v$o<|RNMBIoB(j*jyr
z(D%u?I?B;;{slC>8k}8Gjx;kdBQPASNhjH-kWXiH4AE0<R0XmKY_|a;mQQqNRIg-D
z+E1XEtcyA=l<8z$92ZMlGn=eSI%O>)D=y!<l(UWktBUNC#XyN3HTB<kXr&6jz<&{+
z2L`awr<znDCjiY;fffS#u7juwtS8VYw&&tml`5Qs|DwC6gSDBgwW3@`vEnNiA>p4v
zetp!8IHABf<R34589Yf%Nc_M>WXa=ipXA_|&?*`9Y5i0cxSB#|M&rL6C&U^ky at f)@
zF)xAL^y*QcRE{2lJw#NG(utz0eS%1f6pA#cz_SE4M(a;Ue37WWkJ1qrqIl%M$%=<z
zAA|oI+?1p;qO<WFY)TRhU*z7odLcu}oEu+!>k+u?k$4FF3xNzPkU1N}5ff15$sz0k
z)NF!SUX3K4f^;t6-2<@~5a&>ig4&Pqm~Y}y2%L;(8F)vANiJIeRr0QkTD}=99)38y
z at dHMS7tuE%Xh**i0g3)flDxpQ{3-xEbh?Ki(mFi&So%01M&c`M%WeRwmfS%x95mdu
zjBnkow=8 at Yke$SESB!;=UxVZTM#Qmr at ElyHwcj#(HRO3v#<lEWNN=G9h3=>Yi-*As
zK8fV9?7|87U-BmXIJDtkBHG_!PBD}(T?CCZ=RY*Q1S!gje!Y-gt=OyMnTSba at J3$5
zn4Izo*Lh+0MPriIy#yMT)EM1-jAH9<iPOD=Zzb{AAI`PxEU<rth-+cgQLd$o_AN|O
z%O at JK{vvh<#6I`I?gxx+7W(36fc64kj^)!$3~kZhz<YW>#CXlbaLq$bKL at Ioml;XM
zbuH@)RhP0%_&k>ecp<5l?=V6Kicmg;)}Z*8p5rX at OQ0?dd>+e|L1ft${Hf)SnYh~c
z24G2y`?51`tnqtHjC4eIExQsi4q=RMx{9&vNhVa1hnBWtuZi1R;=YWkpExo}DQ+0$
zel>|tzL!m9i!8+4o+{*XF#TkX&+z2&oIKLQSz110HdV2e;pB8|zX_WZ&J!Hu)5oIY
zj!sBJC`$qLqi8=)NQGyQ3Z*X%c?9T4xD2=h;C7E3Hu(B&XAL^>tGSb}KjY;U->AP|
zG4`L2yn5A{llyNxyLtSu)4p8))CW0zuAh5hbJ39ZADlGg?BAZ#@a@}Y&1>%e_PP(&
zpZxJP)8BVLu|4<n#g~6G at Yvkly??Xd!_lW7GkpHc^$Ulry85p*kACpnj^qD*?WZ56
z{o6C-nRBmo*PQ+8juV1AFW7YVITxP!(8PoD7uQ_9`2GindcHd64@<TnQy0VSg1Zmy
zw{Wk*eFXO{Twhee2)Jyxsc`e*@Xms&huZ|V9qux?Tj3spdlv3hxR2nzh2w@@8E_Nf
zro)xNt%hrc+YGk@?kc!D;2wixuZCn5J4YVuNEx1E!dzv*uv982Uo2smry37=HwBcv
z3QuhweC3xiY_UAJI*?&@vpo3v48v at dJos`e!_uBXWj`TMc1}EQTA=ytb$D<QDdjCb
zw>e<g($Ccq3|lr2j!W;-IDNc;P~OTj*K#l{%^s8;8N<vY53UhmSUNsXzC6RQobaIR
zV;Hu|i0eZbw)C;{V%RD#zGI21lRDt_g9q23P{vAwZ_hAnrBQA2EY||y^2#u%Rfh7)
zHNsXM$bJt9Tk^bCP at k0^cM4*d*F_%k>M|%h8XkOcnS3iOI}Rai$y?_$Wq80`IT+^o
z%=6chL9<hIoyjl~%OX;~rBCxMTl)O&x^oB2LU;)rs!1Gm^18rdH5|iPa6I at L9>cE<
zk)Ykrpt#gVIQADjm_F at FQXZA8*t6(#iKoD&!u5uu-Do~?5ocTuAlTPf{mf|i4}i;r
z8w*D}vf*goM7RPtJnX_S5WOrM?cjKiH`~+UsDGxRrG_33%4Wc#N3n|x<;vh+3|DTj
zWuSNnBwO&V2CaargsXz9g<A{P2)7Q7 at gtzE#=imdu3+Wl1CJZO>-K416g_bMAJ_DH
z`oZnbF8}h%y-%O<{PdDV+j4g8d?4fKL%(|a^IG at Eqd!V(`RKioV=M1@=CU=HZ#eGa
z8%}%5H~6jN4)`c-)2_X%W{m#T!z1^WuZ--x^w at XbTfFVI<6r#7H|DHMhX4ML$%~GA
z=D_fAYaTf{zigYYZ`<xWo_=T1OK+X9vH#(_PWyV*Z3q1$r{v&6X4jr}>yGPBoB8z3
zuEQ>PVCbst7Z?2M;+JRq{=BJo9d!KEs~^7LnNPnNKfk|k+Jl3uGA`J3)s4 at 5HS+f4
z>E(NyKYC&1_x)0aKA3yU##xb-(?^XRchCzD=KrdXJDhXw#**r9x4&Mp<{vNaUFn<h
zee-|*T6y|e9~=<e<SV=9(o5f3*Z=*!bFQ2beCfGm19Sba-dM8g-1}}n`m8JFUHN|-
z|M~0fi|@a7Q*P^*spWb5J$y~^K{sqTN=@9nrO(b^p1&#UAG5El8S$8J)%)fCvb+BL
z@^zQqF?rFzr=~8LTRQ#Hx0ZNXCl8*s^X=bmJ374m)%3E4kG{SAyb&+n{(4sOp{~Qu
zShQas_k~OSH~cB}@>kE_aoLq`F7|)+Mr+ovzYUpI{nm4VjNu=hGjQgh8(+NO?GYPS
zy_t31wr!g)eEs{ZFWwrlI(0+s4d;EbXZXF at gQo3x<;$iayI#xMd(eQqhc`|6CgtHP
zHr4)ZY|XCY``r1#yn_46e)YxwU4Pf9n?6cL{lo3&LED6z2Dcb41h*b;8yw&E<Xh6O
zz<mVwJskJ98VgqpHxKSuxOH%+!d(P+Gu*>)d*I%N`vR^PPM#5Pd2j)^rEs-y$HUzW
z_b}WZxVPcHfa`@5Z3J8%TmWt<TrJ%3a2LSsf_o6|Ik>mrK7&i?g=;-r4%{(tO>if}
zT>!TW?m at Wc;NF7!3@!yH at -Vm@xGK0dxUF!P!QBq`INZPClF<zefy;tB6s`=e3a$-q
zD;&3|ydCawxEJBxhx-OD4ISBNxXExwz^#O9fZGgr9^4IZ_rpC4_XgZ2aGrkXOW-EJ
zmBTf_ZH7A!?gqH~;hu$i1MU+z4?3Zta1-DTgF7DXY`Cl8cEddd$MqEK`?$n{{SglC
zYsv1E!{osjfnlfw!b3Jb1m%FhK)%&FK4<?7#FYwE$wlQ>M6?V-eAU=Me0_irS0pht
z99*42h^ya?6d%bF;=P_Rk4p^*aU#e-^7bzvE|Nk-z8eg(NfR!|GTOKeD5I9*FC7$z
ztf~a<m2E?^MibC;6KrVMY8{dD&_)-RaZneR)f-5*u>|xM@?#)wqe`iEIFlmR3=-mE
zE0b~FJrd%635S5<m=6{qE?YBFT=GYVi at OZOMJ$B)qJT+}YhVa*KFSmiAKek+gFIsd
zSLP7nQW+DGuSgT(>;DGgA{s(`Il(|&Ohbq-Dj10CbqI0Z%%sQ{qX}_EoiUZqyb19+
zxG{puUkLG)1fz>D?xL-z5AX+wZ})@ng=vO#P4b0KBhD9ise#MutRh*hAwCf>Qe1pP
zDZU6{AbIr|5SIZOYxq_)rFhq2ATHn`#1|<{M0tN45Z5RgDK5yP6rYQl{LA||fW{(h
zq`0jFrMS_A(Z$6(g!rO`fewH)Gs3++0rBNp!{M?_3b&y4O)6X>Nr+FW4aB8Eg!m?h
ziO8qzg!pjY*dp6$0P?^V196!jrTEs3iOA>Vg!uT}KzuSoi1RN7;&Nry*oSa{xJd>G
zcTvEP8wY at Jg)<0`$_%Z6yNZ~kxz#U~{s+!LTn$BtZ>gAwvM&LkW~ek$Tt!AHE{`zz
z=VN|CeEM%9ayb<tuCg+aY^Dl`o2(j$iyA4#*<z!M3ycVHTG>EctVW1y$xK99`3Z=t
zQUP&05D;#`0K(S_L9RvxfpE1b2#;DgDnd0`4VP=K32|X5n*a{kIs)`p&}Ja6k)srs
zuo+#u5hTQwyhe&UOt4b8Ul63YR}g;Vv{Bso0wKPp3?j#Bt$`2U48%2YRLXac48&!8
zgt)TLlm{Qq5aN8LsT8icCBzvyBgNIlgt*q%KwJk%i0ku=dhY!|h}+&6h%5XEaXFrW
zWU~xFe?ulriq~XlDXyY5Qd|?uh+HI#V&%c5bcFcElaZ30F#yeoHYqOpqZD7VGE#i0
zj}YI(GY}Ud6XLpLlOgVQP3V3&V;A3KBgBbB6Oro#3GqEG1Ib=0fX+wQMC4jMN^z}|
zk>UbJLR^h#AU;YX^vrY{8knr10nrR`*(9a7xY0z+S*;;H0W=U7I8y4QsFZBr0qEYS
zF0SCF6rY`#Y;!9Hpfc=(F7DuhANRcg;f59<Jh)2%L>2dl0knU#?Qy*%mEIOjnoAG~
zaaEUzU$|OBeB^5&*&+l|TsNK$ii6J_8S(DvwiK76i+X(uQi^Ll3Gsb8ql>Q+5aP0D
znu&v}I|=d4IwQr^sD!v?)IeP3PKXbNOp);Q3p8cL{fO}6hBzSHg$RTj41sVFJP3Ey
z0pTPW2#=j6Rle3|Ag;P*5_|*FKu=U?=&|WG#HCJ@;;IfK#nonnxHic^2t|)dcwNdh
z!$SI+oHrW)*Fzpu5p!%dA<j|b=)k{9V0|mx8UGH$N3PXqymnxMHhI(dx=MfVf8kpe
zbrs)dQp7NVM~Cz$8pL!Q9r)7?(v|))!^d4jr}|eLK2C{F`J4Ys{2hjWAY!BbOh_x^
z|6>N}%KkluZ%&#H@%I{}tNdAKNLTs8Wk?R!#>L9D-skf5O-ZHAJU?*WtE;j(vGD!(
zMnC%BG~em&nf-7lC<o<c!EG^erk!;vR}Z<(KSJO6kgGLvY<F^4>CQYQ`D~oDO!pzU
z<{zQ&9muWt5psQz at 9956ZZhP?8#&W1JI(JgkjpS~rhYq>I~8)NKO)^*A-8vet`Ae6
zo$C7&<X$#%rrmZb$LZ)jKSEz7`kMQU9NV!RR(%9cL2c;z;BC-jM(&658-d&|BWK!m
zr}l9g{3;{&L+$TL$ZaulU6l*lG7s0rviZ`|Q!Y(L&}X%GwllV==?CfZt%RRP>LEt4
zmETgG-xF}vNLJHu8n|4pZ_ at gapg3`kD_7o(=H~jks)`7{6(7!9QPor(%B^T_&YRiP
zh%X;U!g;eoZJ~O6ezqlVNmEljz8qU;$;}GYRJ7Jda at XU_#fFpD8g9v}tZU56&CRQ8
ztg3IV4&_x%n2^_&ul7Mg_|$w}6~0BgCNDofcVg}&E6JadR#|;Tq^7B*A)I$)Mb*Oc
z6}im at aAdrE);yaXu3jsdG`ag9CY6VePv-^s{l)PAGS&ZmiglBU3;&lnG at k<h2 at N#C
zM#GxKYe4d`O`e4K5@=J)2KvI0>grHUZY{5btZDP%L$df4(7KBHx{aY0`2 at BW$A>%D
z1l#ID?F`}*;I_`t`l?VfPimu9hec6SxTd|DK73)E$yrh95AxIPNM%i9Frv+X5EIdA
z=mU&iRHN`SU3@(h->*ji-4vA~Y~lPQy=G8~-#w0o_)&Tj;zyCS3fx@=88Q*ApowV(
zO;iMRa!>=KbX$cVU7h`rdPfTKsd^Je67rdP1TCeGFmr+KMdzA6h%o`(RuDj!szu;u
z5zve#BP8c2{Foh<(r7YjYytVMu@<h<-#DfU{bgyuEJgF}W8#)Nrf<G#EagVCwOCwG
zYt}67w?1fWl{eJ$L$J`!FV9-?fMUJi*EBUv%B^bFL-*t<%KC~P9$tC+_x{w=?-cLP
zJY&6Oo+R(d9+x*Y-J7)Go#T@>tVniwu>aAW-qeU^Z11 at qm9)$CfahrOeeX)W)l($i
zS2jK1@$~+!Cw-+S#d~tHn{iI>le)q)y7%1V6vVo!`2o)q_`ykfv;PC0eiH4P6Cdyd
z;9KBLtuYC0T;UlG<UsEVPhPI4cdpj;hIgtbxA#0m-hwDOy(5%PdT;#>&q4?nc~@w$
zFHcCVfgP>Fy(npi$KQL0rx2?A5znZ(p27(2ihSZ3j7SFn22tLCXFBL1loI>ANnahG
znv1A&larCi=f^W^t!}rBq`yE}V!WC22B;78MNo_ra(->-FF`R5$>F#u4fN-r7$4*`
zf?~!!Cj{CT^l(tj2;@uwWqdCv+F8yQxSkIKeGe3EGv{Sc%oyeT1{C9#oJT-$R^;3O
ziiVSO7AWrBa?Sun!y42Eigw4>rubMgX9*}~LULvpin~8PYRt(4rTlnMbW%AStH6XD
zGd9op^;`*iw;H<K(BX!DF-P;CHT36(h7CQ~&>@DtK3mJ*Xy`&i#~Ql#2+hCE(7A>l
zia`?W@?JDSQ_Po1csh(Go?$36!SI{-BYn)!s|?+2=xRf!8=7ILGW1QO|1m?aGIX<{
zs|}rQXojJ<U#AIPv<W`WMb&FNxc&v<BNw33kc9UcR9YH5`b5O-xCw7&1RQU}k$)8f
zI37d1H0ZGIy*C^AJ2YFJ2p;8E!|^CYr84}cgs>FE at R>M|>kQv#!uf_j(S%7Df4T`b
zm~fd1pAJes at 7H+b(mwb%oA4{33_oVVIVQZvgf|%Zy(YZegjskz1|!_x at ECpyjk&+;
zF}0Tg9QPvZV5`cw at W*lCL2+R|UUbI4J&wOJE{u!u$_4YvBa?!`{QQ0NdFLrLbuHnD
zd~4ZGYu|s}8DD$G2jyc^?dEr*t2kik2~GJWVpK3(+td=VzBt_ at icx>aZI7xf)++0p
zFmy8?xb6v4Q3Q42Ahq^{w#n5MkqV<|-?n0WqCNUW^nL$Hbm#Zi?bP=DS!2G5zH)&n
z%!0~_aGkV&45{Z-EhtAf!7-T`@z23G(1Ddy)YmuR=DeweK<O-eIG#hzmikbmbTEl1
z!-v;-Pf=Pnuc|=>n=!PH)IjOdMvOzNgNsAq)`pNXkvQ`TVZ)k8Eu%Z7x|Od&%s7M^
zt9wLO^ZXuBgH}1K5#OQjf!xi^cdE*tQpTdTKLB44o5XzF_XHzN!Ip}4t8=ivA74Hx
z=qTy=U3_4k*B#R=CY#>HYEww5G=HKEHkB?e&!@`Zn)U00nBfUGHR9GUvLV<uQ5`XJ
SW>DWV1|t=f^`VKlhW<Za!fU+%
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..29716a88f5c07540cb99b4188776e6b24326a6c8
GIT binary patch
literal 50140
zcmcg#34B!5^}aL7B!NJfA#5s3SP}`4giI0^#bJ%?YXA|&agt16Ae)&<0*H!OQ4|zZ
zR77!CT<X3rRcotNYpb>{b!oM>*8NXy>r%D;zwg}p-n>kL+XVB=opbJY&OP_s_1*X0
zeeeDLzaRZCT`5<J!Vf|!!def0auD!$5W?pK_w#qmeOhoa)8NmF!=_^BK at fkzU@W{g
zrg<G-T)u2^JZ^E_=>-00kJ<kFVWqMOq^gZ1)?YBVvZ^W=URxDzj0Iz%%3!dqJ+HCT
z&m`EJrj*-C+yM;+tD>={Nc~D9OSCuK*n=7Qd(>h~JkfSASRJlxUKxZ@(Fg{o9W{B;
zkw#moLSt|JG7UYEU=L^;la{^OhN=$j?LAuC`MV}+QqVAQ(xJUjWo1*ih3(VUzirEP
z!rM*T=N=z7WVjCPMe1uBC{MH(F#cpu(y3pn)^zJHl*-U-hxY11Rbn#H-onduB2$g(
zy=!#b at ta^T)Yw=X4%Ub2!cizC+FNAo9cv7}|2^$BRIZi=Nwjy%721<w#-SsxGfbT9
z- at nFCRieEYuFwgsA+-8?+Ka7g?6AB?Ua9RJnx*NVztdh-Lmm8z1)J+zBlXq6;GAhX
zrT%TaRns>Om~ppKoKt>__U)pvgz|=01#6nn8d{h*-WJ at Z@nxnx-Zl1mJ)-BSOr=(7
z4J*AKZ?%znv6xtYdvDizccy7N>0V9y8+(Yg at y`!{bBAQ#qpM0q;2)KU4?{X1Xz8O$
z?L|T1k6M7hKW4!|UG{BLesJIaZ^?`;f1kXxV#aA7=FHf(;*}X&{_-vp+jQGWuV~=g
zg-5)OM56cz{THtI(HW=xD(9HV$E|q$12uEY6PC?6TRszckIWu}6!Ty49<!|JF$gVf
z`LpFq(V4TYY!hTw5}25?<<l8keo3p6s-yIY_7dYWo}BJwj-VNu@(7|<JdU4lzH#+Z
zeU<8)u}Tf<je5_hQ4=Pk6NGDP8`NZu?VPIGQ2olBmT*%v(ommMTwFN1uq0==pasRn
zqe~d~7nY6BS9PICePLB&qbgbwg?dqCbELL9S{rH!7lm4Caj1&Miul9no5zG`tQs>$
zv8oJ3BUJ{RP_-)5G%5$8!w!S&u)`P+#+pKrSX5*Ir!WLJt3t7cCN0Vdz at F1u5W}mk
zp?*TFsW}YU at _Dl>VkI!^FYZup=A6pn@^b%Z99CB~HM9n6!}Tj;tAgRCriP~S7T9hN
z|8S!X&9PuZO|S{I8g>|U!m6^Np%&RiS2Z-nf_0(j8WoMK4+lBzD7(y7t;Flf7R9S$
z`8-|X;xV?+q?<XfA~@a#XI7P$mya{iaQUJNf3VKVDy$kCBK5Iw6I?Q!xYDkzY- at J@
zY&{iR+-RAyS}GoQRA3u##)hh^o5Im(`JyUiSk)A+2{(o7tHR%%Xm*vVYN$tFvs~A)
zHWqZvw8=GI19b~#x0qU2wG9{n&Gpg9%KC714yq#V{)Co>NVRmW4y+ZAt`6H(x}d5~
z#iRQx!MM86+8`SnUBhCj+ky45)fh`n4eQDmRKc*YDmblCNiS*JQo%@F;}2}SQ8{|h
z*lntNA3CMg6DRDq<BiH;jae3glQ~LtC9>{<(;_uBi`kX!a{ZXz$@bBW$|kVe8B0!S
zcPA*_F=xcL%p9X~YC^S9&Jhc+w6r^UeA>ww;b`RI(zY5i7gUuOkG8P}_StxhURFn9
zm_0+a6C at j_Beq_fyg2#Qhhn30IDnAz6gD3K6`Wav at w6&jkHJuh6~hE6ZB9Zj{9g6h
zrgw6{vxok`Cb7C``J&k{@B>qqjE#nC!&v+@)U(lIIDCYgz%{PZZP?UY#ac7AznAV0
z^q?41y*)r>&O@)lyjVPz^WDm(P_6bPR3DpJDF=sgw1bsGafIk$(N28=r*LZow1jG#
zopaXy%~!QlV&FG4hMRa)%aP-Nq_##MjzZRC at I4zj?ysKJzqN#;aTHL}N58#X)@ZSh
zsQW1r?CB!?aIfvI_3iCpIv$RadfxmI^<yP1-+xZ5mmk%|$790$UY&gZd1Fap<^BC^
z{lF?H=>#7g^%LaWuNN)BU=!v9457M49?HX*r9+V>$8p2CR%^GK_+cwQ&X`T%M(5OO
zAG+-2NIPGGXq&nN?9k}=!6m52GU^1b;+Km&Ru?NN)X2J$qbq22C>D}9F)jm at z5dW^
zs$lI}h$b&uH2LUY#mwd9!No@}C=W6TmuXF*R{XX$G*w4I6B<AY9q%N5f5#eJAQt<b
zO*FHLP_d(7xNHR0W(`$dUMA%$pA#8fKBp301M!vNm at IZdnX|PH|LL-pmB-9#RNB-~
z{giNdU1MzBlu#7Ya);I9=o1OuXjD$IHLu%~+P76<+q#((DMp=ONXP5sd)3DGuwoYa
zW7`!d>4vN*3znDFM4F;(L!pi~EI!Z~+O>S3avBp2bBTtsY33&=Ts+GIUb at m~Yp4;2
z{&7J?4y(sv1iz|pY>2iw^;VI3tWra at Sl>4VYa`K^o;KCV&MClIH$Q4_sM6~zr_EqX
zB-}c)3JXXa>71({$8`bG!C1w?v_|voEPVF?gx3e`)zgpiK2*U&aaqt_q8-r*7U$Do
z@{U!+ipL~2A?D{!u)F|g)5-gnw2iXL at XAO%dWcXJ!4(Ovl6jzO!qJm)=>z6m%^YKX
z<RQ$;OU|#vcKf_|qA6!+ZO;yWRL?32%M65HR&`Ro8&gTP*qA1(3N(WgPF at 5I$Lk^y
za2zu`Xc9g6k}6o-CEY5C4zzP|e;zp-F8N8J6xXD9^dL#P at hoG>c7icgR`Y2ldB>`B
zDM^wxHnz&{U4~2AWLcGI2BArtD>WD4NRl=-Mqf!rAJI(G2A!7)lkF+vaO#2kfw6UP
z&tmDISx^3`*=!8X_jnPrt_q{Vs=`h&n5<`G;ZL}!1+LLEa>-ic%>-RY+?}ooHP^<1
zJPad)4)J8OvkTz76!fDSskkJ%3O8cb1Y- at s8aRyguQQ&kqh(dK;Slee2&J{8CjYW9
zPuXBjXwv2)YtcZ~g|=f>BwJW9muwOJA@&+x<xOt%X*)?8X`GX=)E$}hS{EieVJQhK
zNiQW~;{Yv}$6!YU50v^eK}V8p&o(yeoEPbT)VR0Ip)ESoR%ewG$BZPqE at xz2^X+Hk
z4)A2Nv+DBz^{DZU&Cyl3tzESS{odx2b$VQ5L!&m at f_qh(P1a^vO%rb8V2Tz>Yst;{
zmboOmL#fmqP8(5$Njqg3OVXz?p(t-BThoL at lC6HrW@lVaux!aR))`ZdE^g;cIkv6N
zs<Gs!9IL(#&>VmZJ6Nk?b)XL`I+k?l+ZgSHMz-vAN-H~zby`6?p`DFeawEiXm18E#
zjC-A(<!Q&}548ISsPmTLI$abeTy;vAWb4S7>$r*zsPT&NNnfYM*;`|6sEW0rhq8$$
z>vy8v<VUl^VrPu!w&psqxXBL++qI6n6k1(3Rg#DN at 6HDIXp&x#f3I9Rt@`&{V?RZ!
ze9Lr|)Vi~jTad7;4r7QMD=R5`W1`KK*q+A;P;<#vzjaGb-!@9hw=&sy%ZoJfP(`vu
zE#<xiSR+Zg-ik}GTfo|FB|C82#FMsPT7wOAdIesG+uEIQSzBA=bSdLFsg{Y`>ZF3|
zll`Q8Dr<69nM9Iy&e-gnN^=<NEXO*b+KNk9ZMepY9TeF6?d)<kn6$fznRHHtc4W2F
zUG0o2_DdDlhT7M#!IJm7Z5EwWzwM27wxgX<yJH<4xV~XOomdN!cfW(oI;pbvWBGu%
z+!@tACf=z#sCDVsomJ`Wv+ATe at 7QqiRo>oiC)D^@c^<C`55UMS9}`R3S=+32)|c!$
zE74#ltT$|vX!p)6aOay#er;8ZeW#K7mQYg!JNu(puR5bFd@{GHi^pLHCU1QPLpbQ`
zTdI;pBA9e7W8-!tDjSG(5j3By|JctdTVBPca7jDrG?`@Oj^Q3aJVGds#_2r<vMtaF
zCGBr9a^bm#BNz6OwotP5T#PNiEQ;)xZ&MN*NxmR at o3SGgs~m0eNUFQz85(I3+3#Vs
zh1oTel;KiG{a|B?Y^bm+3_$X=gB;kVQWwmjP34#zk}3kG0^4Krq!%C8YmX+~nUIrR
z6f37T#W7&=mA1c}^qxGEjoFOLM+Ls)!8`le+ at vZRQ(=5`CYE0h<4&u9{pFS9%!UV(
zS%gIAJI(F(_LFlMb0l_(H^`tNlXMrBeN<R-)p7p>4)WMlWn#&ihO4qA%PeUn(wR0p
z%U1GNP1!g3=z8TkTyEqa4_g{Y)=BQFFs5W>6Tg$ed}Nu|kv!RKi!n*deIssDvwDUT
zNIC=5nLKo=Z^@g*kGbUEUUC4l<JI(Ud-627 at mjq9a_&E4KG>IZi81rkHME3-)}9AE
z at 9<qYIurb~`SWqhq;o`7J4$SIDS6JLz2Ly*w*Oi_u%+C8zMavZ{4$;6QOXEzGoV-1
z*4ob`#LwkA5++;Gew at efw9(kM9zcoWu~s}9$EkL|QapBurO;yKcy`h}UKKyvOn9);
z+ETKpY7yUNf#l{PaC;g^NZ=2jP+nD~!Y4S&nW$15qe`uFi)n(2^EyC9Nt+vz37Xcf
zc5{Yr)^7<)@!J at DzJC9nm2$jbZOlWoBL6L_=Kh?herNUJKAv-1MuK}|dHpPmYw{6g
zI6MZ2cb~O=Jw-yIVm}T=c7q_PGrE7ji;JOWS;t-xN9@}Yg-?hlibT-7c69%#N?0Up
zm2TkMBIL~yO239f9%8Z|C6<R`gLM(Se}Sh{7)scahUHhxJg1;veS=qbti%g?<TW at -
zzZ?#)Wl+JE##qxZM?BaPtE>$I)YW&gLnL=l$J;<@>ndz at Zc!v0HFfgrb8Vy&Zx6z%
zug1I}$Z?enCmo4mo<BE7!%-%vYG{^?hY5(If;un|l85<52i3{#jWeZntE_{h_HEO+
zr??wk?5HSh9JU>pG1^AYs*01HFB?**#A>`HB^Z;Jz(})z=Xq*QbwhJyZCKTX>#A^X
z8bk&Q{9qKM-cY<3Nk>7cj5okgNt1dj+E80dcx_D+ud2-%L(Nr9OG4wr^&w;vjMU6r
zreA!qpe2HVDPqy2vHfUPMI at _LO+uoL=qt<Tj75UR%BD3P+UBsQG8HW4?=Vj>lNj at 3
z$i_PM+_DZiQ^Xq9upl at wSG?)1`?ZrnQ*ag-hblMk{NZ3HgbPE!<avC=O8kg{jw!Vo
zM_LGoYQ_)KlS(3c%<0s`B{`Xd^tLKQG8^GyVpOaFz)PtR5tDYz@<YqS8qMmc<%J_*
zTxh%CNXnEojtt4$`7vT=$4ERkD~(vU6WOtNR(3MvB(nvkfa*{aUVz7$O(RUEIWT-d
zhptM^RYzJ7KcTrHhG%%{RIQHJ8j2~dMww9pK7t1- at HQ>};B^bq{MEV_;4wCd*63)B
zs;O<zg9f at rM@EMv71d at FZ-y<r!3#?ATct0P)-;7NFg4$#-~6OPm3(;v)+uWvF-)HL
z36}F0r~2V~T%d`ri^fm}Ln@=VZd|oWoe*UzjGB^AWppi!L{+W)$S-k}dF@(-Un#zl
z!mBzA*?RoO8d|GVt3E=3#v1A>fkp{O5eI{qI&$V5taO7>O)>xDQChq<qNX;q5^s&D
ziC~rqR^k8>j8-;-;DKuZ`eClx${Nj7H8iY=0IsTSpcJKMt%k#ER1KalM=RM)+aS{!
zmq at zL;GtbCpj5EAQsIrGc*C3J$}(W^q**epm)~0GRMxK1S;7#9ZjH{erluC#<MHHv
zjG7=Vq&1Cruqg%_tqRoxt~c?hMK#`H=>_p-4teGsZ#`Y9RyN`;z0Snuup((f|7Z<{
znpPr&L+E;V5h-47r(-Q9tCpxSZRgoyWm<zauTuPt!og<nK at uH_vPW=#KYp6=YB*}@
z+N{wPWf6$@<UZVEC8NL+i{XuZ at Q5#w)X!UCR#P=R{^ONtczvD1D}_jcHF)N!Ug=-F
zDl)92hGH~v<%I_+`3lKcU88gYP{hSQPJ`mVRY<8`Q>pZw3R0#P0|u9mjYLDW_04q=
zWf=5p!5UYEGzLavm3Y_S8e+m|tg1fNR7*@4ja5fh;#CE}gwYt@*3`I)m at pbcdxe{b
z38OLbi<mG5Yp%zurihWzSQHOMhKUKIv1UBmBld&=HZBrfYdfPkYGT6BIU7b}CUvYq
zr$$?0p&1__CXV5XIi=0ei9_J9GHsJ8j&RPDSyudNwJTk7+FS6Z+BIiTyW(4|nn%f6
z?W)(D(Y4FlYSlh<?dsQ@(X|_()oKCi+D)K2qbqgK3U9Sqfx31xXwK-`4bf_~#CYh&
zo5HY0TdF9snx=*2l&BZ@<1i)KO%?YMsNGm52hN?+Figw_k_naPpN=Nv9BV-x at Z(g_
zpmQ*|@Q;}irvY_bfs?Fiz{JOBb!eSXtg;bZhhqY1tAW=UitZncQLwTOhrAkc>l^T*
z)*4-{82YVd`m=x*ThwA&0du2Kg3KD!hT%+w<A at MFNil}e-HKRiq&m#001y!~X at Sb&
zrCO63O>i(3wAK(qaWEB_2U9Ryw}Qy}l~EjuC8{YGtVDSf7g)#bg)3$IS&p{0N=hsj
zxeSHkewU%G3ucS1y$pr&ewU%ztSm!ecMMdqMCfpJYng>yyYMZm?AF#g)oPa6EEAWv
zpggWK2OZ-IR+Lx?RA$wI%Ir;s2go4wYhn>h<Thh13}Owk9^f@`bmJzyXu!Hynh#Vj
z7X*;?f<SVFl0}7TF+Ic(=>VMhTda;|QN9uuFQ=@k<#-!jkCw)wF2BudXC at dl7)$!?
zEK`eTPOC5PjAu-z`s0?SHP_W)6L8{dqU5ErquRZB at c_LI2}R>+SPNf}6TjqfpfdA!
zklDAr<LXDgV<q7=VN?AmTx?Y&sy6Zs#rQi*6TB~aiQ#Or-Ef!0RV?;C8>+C?4P(8J
z`vF_!xI~pl4e+$B(k}1kjOf+<tGsDM at 9$s5<#Xj`WqVSxynPSJdh3*fe6F5&zqNb3
zD+O;4Pa)aj!iNG<-L5g2DOs7Bhh-j)*Y|t+tC`v3 at M7$=?kXi~W;W4 at 2TeGrKfVc&
z-UqUjEUlOkms7n<b{jKYyF-<Vlx6mX%*vo!JRR-&GikYdA>5(*go7p?1Yi9~mF0nn
zQh3;-ov;e1mtwrmyU<mirPI#LcBJkZ#~o;P9JRHT>J>+gu2Q{=q^wHyNp;Q4ww&)f
z9F;<c`%#P!EsO?X{NN%8lsY6EWCFbFPk~k)P=q!b7%%m>OqOm?LZR^O29u<_QiF9P
zP;ZFaSRCr8VBo`SpEGTrbM5wlLS9_KQPe{Vm8q^w2Rhu*2aq)1b~cmEH^R7TW#rFf
z{f}&iDmAKuJXwf>428zc?1vgFbh`#*+Z_(FBFoO4%(?ySrWyd%(N1gaq{Z6FahdEQ
z{vOgCC3!+hhoQ~_=y6Jwc?B7hhc+1NLQ5(&ZZM#+kd3EWW at Z5FVN*oyaGGH|PUtQ1
zBha!cU^(chu!&CBCa}jUHHi%*9R&s_7s58n>_{}lGGsT{R7=YsXK+AH!;8{Yd4jG;
zj_fT3n9f((&oBxeM+P&kE~3;dt9F!{ZI3?qHK!2MLeI2G{nj63`6mNTskt-MDcL9C
z&H3{VhwDnsw=}D>*B?}$H61m#z at yxKIVrHp7kYFF;eb+$n0OPtuh2Ri%M>iOtgJtX
z7M9pjRE$zf5$$IgR6Qo?uZQ6M`|<++R5cm}<==Qs<d@$XaUTyhr5Zn}sjKkY&-I4a
z^SfT)(oTW+ja+;J;C;6%eF~~_D*)Fu?zA$zN?!yYxLp~O5xErJy1Xf>i)T41rk^V<
zrR!O+;L1o*nVx<i8OH;^pHSBnm9Ytt<%><ZeXDX}B9dm(ayiEf)Ub&R7FxA+_Fe
ztBfWq@>h38#(G3PpyX}0SEY}DXI=5B0oPu47tdyh`nmq;?%I_m|K&#hE)Yo{LC<yl
z2gWXi(s;^0MKZD0NYUqRmrDOD3Va4$yYIRZ*6tT;u9S>Nz??>%6gb)K&*;li{_GUj
zH`br4``dtBy;EFSZ*hq9kZ3;>^}a(a{oy`1ETls1Dz{c2WXbnYuCW{^rW0zxFiY^?
zxbi3`=2Q+?0ymVstVm;iQage77jb)2EGbiXSsNzV3`;;y#h(6gq at CSf#UZV-q)o$Y
zqhTjz+(^ea5L~N_K>2zj+Dd3m3Oa&vWqm_u(~mtwsq+Y5?)Lo=v_C#Z;i^kXJ(MbJ
z0I$@jFAuoLnw>JKKwq6DTkDjGd%h<v*?Om}3(PBD_nyY)iB1`Nl=3ZvY!`xSYsz-?
z71J5gLvZ(U!uPs;4_PYbrraqix<oZl at n9so?sNMJL1X04b6WAOwcwr3l)gs*XJE*>
zcBQ1UbLkG4z6J(+5PrbzTL>yDm!=#lDmu?bsO+Z7gKpn at prbLCT$eko_{snYe3dh$
z?<BxaQv13#uKW&AA9Qlp4Q=2<0M!t_xs8!}K=%^9wGAwz1mC)F-I1~ob!wX2*A>uW
z!gsZSj{&ri^>}w1_<F$qqV_#bxaU`Zj>N3*dcf*>%)%>;*K;leB7D#(R6Q>Q{w5PW
z+!lWq*ksOqzi5je1x)lGGq~z`C7 at 5J`nV0LgK_LZaQ)hXeDe^!h|rTMFLCD8o!xgC
zpuZA+D&>8T1?w at Lo{cW~EC<H*Zr?|i-qR^upqhce0;=?W(Az=1>)gI#G<z$8>$mOf
z`PN&qXWQBEJpx&Jf28}pv*YW5))TnM{^XSD0kh1Kz3P<d0duJ(d)+D1gYZ+xrVc=U
zZ#rc<zgfUV_I{!)J~=7hE=%j*PAz(+tIzj$OW{9>3d%QnpvmG>r_9k`)<fYB2(B;M
zw7>5?E8!ujjtNQ1)N{rlr7l2l4NNudqx;?-VDAynF}U)5g6Ls6fCi_=n^XBF0TOsf
zYP>fn-xk2nQF~|`?H4V0SR3sDgOys1;3{&usH^q_OXhdV^ql#yB^%?EF`cv8yA3hc
zCpxtp)xOM9n3SlXd{<kt$xd0k+I=5c3QL^|y35QNs?;S2uH{adB-Vwy(o(4JP{CP>
ze_E;y?Nl8_3E*%hIW~5vrF>^u3MaHva1`oAORFh0e&F!(0HG%*UnwR8$tTuM!C~eC
zOKVFzEnPuf&{T^MT-!SIM){Um3g;$TP`<k@*^We+c#5MnMphWXbwP*L%|W@&(%Q3s
zEoVbKV(DMsvA&}<vW6Q6_U>O*`Hr=;Zs=IcQK2_jsy8`RrCsDl_bP9`$@bokwHzL{
zSgQB$Usd^Dv$P)USj*wz#1SU%CpuQu?S3D$QbwX>o=#<2eQ5CxK+QU9Is+ON)cS2|
zX<SP(<B#gO9Kz?h(EYtNeQ}0UzH5Mg#DuS;vaHsT>tBElABFg<ZQx0O&LjL*>P4=&
z_7#9WBK$X}kM`t(8PQVs*r{Mwu9QUi0tLp*z7Dl8Ray%FbSiKjHWprhLQWwZ`L|QS
z;Yc2YqVPYbLZTy4OG|kib#7}Z-y at cS%c<aSq)U-f$0N8>oeB;|>MeyVr-Ge at DbKGg
zEpLZf%7?2jI-j0S1&1TGQ1~T+tG83Z;mGeTg+We*L`Q}d8#9AD)Kb2+mcme{g2R!g
zp^)o`BY92*ha+Pl6ot`Fg+xboSX%xLwUqCDOQF=M;BaJe3D(XCuCY!9ha)#z3X`1*
ziH>+M&cw{r4z-kTg{4sLRB$+QCluUeaAbz(=bYGO(P(DcuE0gM!YN~C)T5s6D&H}d
z)^YpS()vuPe79KotDO2Qneu&U$s$f!JV&iHYmD)0_5QU?- at OE?A0W6kdmL-xo}UAn
zHx}@j9&^Iu3n6+7p|hQu+4li*j|05RGXyT`v!m>;Km@(i!*g at J((bhc=nd4p%cIXC
zrNG$_0O~Ow at I%rDMmYyal;{&}lurZnGU2D3%KrdTb{Np#I+c4(0(2hX=bUi%m4N<D
z_zzASDTgby9KrRnQT~9<kzEJqal)^92$%xCWT9_(4(e$YF#U`^N<HF+?hWqj+6hR9
z;Cj=U?qv&o+mSB2=m?x;A-LXg>Yihv?>TgPy$Liw0NszYn<{%WVy6)KuM|hOY_GF{
zyh1cJO;>ip*y!~aOCc>$LG>Cr(In0=GU;L*7OGb>WKSTt`a5OuKG>F1y`F<^@g(RE
z{66|#>B7CHBf%~v8tO=-dhG?2G8u55fn|vG>I+EVkq+4Vem at 0ww_CDlPTAChDC;ss
zsS^=gGmVUgTd$UFv1D_cGHvrq$d*h+x}^@8>J<Sb at No{<xbc=H3p-^xtD~pkOdY`$
z(K6NR1;mQWfvh&#GE#c;iqTxay?=fP+F&{up3VObOrJ^cJk|BFyYD-Q^|j)kd;0D}
z+^f1TUkYo*DXxAuq1knZ;I%6x^4x`Amuro?=W}5AX=B&XZg<vik(cV3i)fh8atk_0
z<_TO&ypXW_AD-;Tg~5RDlE%x0-ZI$r@{*=XzYXs3@}c`fk9~R0{hlYi6ivemp6*XP
z*`ZY00pBelxwl?yR6+MD=(zvS)9ZE**4J3IyM1Xo8_7`e%KkTGyj0;1q!I8Q$>L at E
z)08>~!96u?jE(y40 at 5cP=nax*O5A73RJWP$LTHHA&pXzV*7MEDQ0gWG_sf!RiX_&#
z`|h!1uNoPX7+LQwxMqOh{)>3lCf)s(>}?~9r;{e1j`~Qy0-b=fjr$`HnxiK;mpe68
zI>`(~M3JlL^i<T~y{wtER5bS-QT%sW_hXsXlkUoTk4^2XL39hD%=AytY_6<-0rvh6
ztV;hFthD17Y3W~s=d}*^mubG;R+{eVd426Pey}Q?-Amm2Z(4dc at Vt)V{wmG)2B@^R
z*W|<Oy*_AopJT$FBjKtva$n<{m;Q(b4%iS%D<723B-%^Wa|_^`Sj1({G|H}w^Z`(o
z9`{)q>fjKly4+8=4`xNB7eOYTKJ8ZShal?W`MoH7nqnKUYg6}sab4>4bJ6c5op^hy
z-8#JwgVCda8vVOaG|@jV73S|2_43r-tk{1eVy6>zm42huWHYG#g{VK1l8u{*>Iek)
zYbo2I;hl_39If+g$|2`KYFm|(?V<h)yniqQoGbMKSAP!Svk+0eFNKv0z)3mzS at d+y
zF?1AqD*aQ42V)eZj=}}|kzib at z1(Rt!7M<|seRn8?D>eSqsqbVq3GOMOT;DSz$^W!
zecipuvz{f}^8mu|e5ig-c>xTkV3Z^pR at p;<8p9iCIQZR$Vb619SKOp<UzOphI2Z-=
zyvASO&D}AQvrrH3WSk4YmGvx*`T7GA_=Akw1%5%`GXQ@=?R^<uj4 at 053k&{FhF at UO
z?iuc(Pukr7&Cr_O*J-79D}G*rOq%vpFx|T!1)KM0==x7X#5F)Wg0^`<++LC~aA77c
zA0nx{HAAHgdJ-}BF&SCs(q#6Z5nI#^NRt#pqv;nwCIj-QjO=BQibhOIlyx=JrSHP8
z48LU=;uc#Yhs)XLp|0EIC35iN9Z;A1#Eii_vRDpm%E-ElhO!5v9>x4FsTqx?-w&BM
za8gEgjis?$Dk<x6rc39Y3UT1%45^Mb4(R%z11>dWk5{Q7d$FV%(kmN3Ilb_62Y$ME
z3b>eZ`y3No$AiZuQ<03d>{K<>v$!1TJWmd*0p&$G&vV{G55?FSg&&p6?!FBY&r^99
zf!s^>dG=WEZ_&o`qw*dA`YI)VNR+$*l&1immsy?OF*GbcoNrWK`jPsoy5~=fi$vv(
z0>~3_&ueYfwMTi2AzqK*dHrx&lOKo4Qy}7{2G5^66kiLml=AJkSn_6ZRNgZX{~wLN
z^IU%z=a0&z>z@&PI!{f<eRKrRyHb3S=Zyt$Ji+%Rk+xI|;6j2QN}a^b9eNeeUsCch
zL77?RqMFq3)cP5?QIdXG{z_0D9?~bMyi>v7iI5(kovg^A&>TU<^hvI)C}Lh&r;HS6
zvVqo8Yt-Y=;_avODJLQB6peh32BvCAjrtlfUO!1Mr!AMxMCIbtP7Rw0mtH97QhXCk
z6m;>kt_r%0y@#>PX%fpU|Bb|sd|Sx${|TAVYdBSA773YEE at bxcLgt((WbO_j^KKS0
z|Cd4*ydh-aS3(x`$)}ZyQ9>3UDP+m<LYDGkRzc>n?LwAcC*+vNgdF=4Nso*FA!OGV
zLN3X~WvGH4yZZ>aY`Bm;B|<JQ7jne{Ay-ujxw=lsHEV at jdzz5z&k?eBmyjE-5pv_L
zLT-LQ$j^T*<d)}z-1?f3+usp#$3KPK`IV5n(oyXNJ?`l#<lf;z?k^GYK!9XGl~nS8
z>X{M?Hwjs}TS(+rLRP;nWDVP}U_jmfgf#TP7%CXhSSaL#`9hk)LSh?*wConL_8uW8
zJul?s*M*$&o{){-2syPIE=m;)*fc=M<`N-i9VX=Lg+jI-C*+(pLeAYF<boYSc0MEI
z!hZ<4=qn++x);*s?twxs9VcYZJRw(93%PQ=kgKi~a`nAJu6coEXx(Q*>R000Pr=Xz
zsimPO{7Pa?uL_BNASCv+kmdo!)NCmg(mGqn+Eqf<og!rYg+fkzN5}>@F2fWIJ!znj
zlP3x}Wx0 at zYlNJ-S;(eKg`9Seke at v%<n%X$Z2p&!GqQ0-reNrqV})#4B;>3*A!lzB
zvUQJ;Z8r%y=RP6lJ|$%Pt3uBIhmZ?g7 at Gw{cjgGWuvo}N(}i5TNXVsCLiW at Px#AQd
zSMCsU?Oq|*Js{-zXN2s1og{DNCqh=GW7aOni}V+=x>(4XBZbuRl1)KgU89it(}gr#
zBBb#)AtyW`r0I1b(NBcLGR7d?@W4PJ6HA3m;?<af;gi=0nX*yH)SW`6-6*8|5g|wZ
zQONZ7gv|J#5NrWr@>#=$%sxWMoJB(Bt`suwR3Y=v6SClXAqyW8vgiepqUN`Sv`8l^
zYAqZ`aIN at Rv`+e2(fWr3Jn;`gHoPz7q_pwWJbAE?Qzi at 9xJ<~YygE}*wCNlnr(G`O
zXAcND{W&3<-w|@gS3=J0ei##M87kzg at j}jCEM)6yA=@?zId`{^9rp-1|9K%hKNNDI
z`*2#hXn>H5ON8vgW*~r<R14X?UdW|8g<N)<kUdWex%_WJuK1sjEBj$lQBZW%SRq%>
z6>`mSLavPox$ayc*WV~)@2`d2 at TQO(zZ7y)KCa0W6y1E7ke|;Ma!ZYnTQ>{2?K&a1
zKPKdkcZA%XiF5ISqI>!Xxp$P12LnPLnlI#Ge2X0`pnX_A7M_6PW9nDaaYRhNVDN8-
z0e6jHH2q>%*0ne$dC$O)($Fpg$+5GjZYH#LyRf0h)rxeYZ5iw`g9hgfrgi0#L-V)+
zP_M`sK~ee=SJtMuae<Z^NFSI5T4tafbYav;<R=H_qjw|j6cv at zm1D#e7C~&Q(Tjjq
zGPf0SfOdP`E|FeAbEf3IA<sw)6%PWPPJAShv}#w at a>j}#G8PugEQ>}*&jL!zX*ITG
zkp{)G@;?vN5^l*VUC-+gu9AhYRXP<5<TRI`YhXWDi2l#1#%P&D)3Hh at Ay-Dud2*RM
z9Dp0=Pbr0^T|m+^{G~v~l=13A={%gsc{0l0=!cZEX at h797e4;wjPiWTUrmlDNTugw
zqR6hXyzVw`1JJ%|{FQ{#$I?rIQk0)3I%TZ@%JwiNIsaaA6qG*O4Oyo8c^*_I1z=J9
zzoDF%pWDm)FEdK6Orn?}RoMr`cmt{IKjerV#vebUWx{2l5=-b^8M!iYeu+vlt`p0O
zsY1?A&QGrNPt#E^ss1?t4qt+wBDBv0E<*im8h<sQ65;B}u{ZkpQ^shSMA<pYwo>{V
z3N93m7zKVt{p{#R<nk>1M0Bo{p}CI%JsoUUZ|M$@RBzxikZv<>1n!j|UI*}Uid2DX
zD4N-!=w^!M^W4KLKQamecM at IF7B#jWq-b_qkqZ2hXhmDpBzT&l>2g9LE;;;qo}#%T
zV!nE99C(H3;<l)<^(IC0+KN=*U82XZsPQuB1QYi`lsyY)tCjK6OLD20i3dY8f#SJw
z*C|$ksX)6e5Sww=Ce8-hNd3ieeW|gDYk}^j<e0cbTe=!(w`GZzZUp)}>PO=Gy6#`3
z{_;fhb)vI6Dn#Df5Pd}PLP?}^{gl8WJ6DzaNxo8F1I!v&nmU{FL2l{@R2W$Az|wvo
z9=Du24Fu~Om^&E4Jg_|nmKIW&k;^@i6ToH<$_+p`4Q#JLrE@{j-MPGAdo0-AgL037
zFbuZOpwfB at Gjh4CKOJn}0l8e-pGS6JE|>RLkR6oECH^gBb8 at -Ne~9ehTrTyWCOagT
z%l$u*9h%D}|GQ*|iQUi04i~#AbHL_{T`$=YVs`-9kz#iQ*->J5EZG9FTTZr6>{gI1
z${jFLsSwzMa%9A<2HUS#ros(i4<0D!X0V6AU)0LEVEgCfE=IClU<WRp<jELVk$*XO
zHpalkD*qabUy`bFPlDoJDjqY*;~lt66gjj99<3FHU!I|IuY=;PR18t^I8kK73=C>T
z;g8QyfqSX6`9-MfF;w~xfYgk@<HXOP6J~7vhQOK3zyQw at IGctvkoN}wuMxb~Hs{SB
z#hH at 5EAOumy-)FVGXP2&EiU~h(A3nxXB6JR>B%7sd_(klJ6}oS)jc(BE<`um9ymo=
z6y3 at yj@vS+`cQNS`&y!C@*s+?qVXxi$X?@R?^J;ihz!b?Atd91KWa)b(GfCbs=ydV
zhTAGCa0G#o at nI)vrj`R8cv at gK$>~zNvkO>53-CLwd=cRt+RyT%7<s}ty at HYRWt7TT
z&#MMdOYj$tHi{D1CV94<FlA2j-c!J=9>njFlE~IkQ%+>cEA;el7f~mecq(LPA>=el
zRr5y$&S8QJq*?f*0_PLBIIb~q7l5moteNMq-nb-iJymz|1lQ{@a5K?eiMn?Xz0 at wF
zna%Gbx<}BRI6Kr0DK+fB1o6^GAorvOo}}92q9#>GnF{=l=w(vMgv5cDDf*>|B*8~C
zuI+vTwuA<9-9<{h3B|#e4fXsT^y0xM=YItH74X5QsQi84ndjh*8TtRR_*1*(e+r&6
z=ip7={I4zkw4V7X^RPC=nd{)6^~*mPyreySc>YlEY|FuCj?NzmekgUejLY|fFCl-{
zr2KK<=aN5rM*eZ&&m_NfL4Fv#*gSVxegyng#J8`?Uk6_7?`X_F3H;5(FNo!z2L3+s
zJ6rR&fS0rvug%|P>F+)>|3dIQ2_JmvcID at sKGc&A$UFGh{47u@{tA`f%Sv)whVl=G
zzV2)+3Dz%d;`*RVf0Ta_B{Z))p>QI}Z2}m8(ZLIIPXb#GcF1%&%q#}muh74ZNvW%o
z%28Jvy&jT78lg3o{+fkioOh|f9tek>D~Vr(vhwpRFmNr=^Wx}~n+e?ErHVMM0(TO*
z(^iQW#dOgJDc>EJ)2rz!@HpWs6X6+86Q1W1Tza1LL6hbW6y6n=8Td8AcMB{<Ht=5w
z>sdkE71`~$(4qYI;CH6y11R*H^#y)qcAJ$lUvsImx`SgoWy~66IIo&f0Cw1X?OKAt
z8D*3$(lXlzuVgmk2+9_AR3xnsm`;U9+ZM}+7EpA)h@@2lO9||hnvoxe=va#M3=v23
zDuG5QxlBNDPMc~VdR<&K5F>Dt01k8=(T5Y!jYRiI<H$5CocxIKyv>lGL!D~{v{$Tp
z0 at e=fr2GOqEAL!f>QR1n_`qcp$pJ`rHJKi%sRCD1bagz{X_D$p{FX at 4n<&3V5=b^v
zZYOY?*ilpNW8 at qi2|UKgcH5K+JV9Vb9GLPffg5C6Re66z<TV1jXjsp+tWTBq7SQ)8
zxxB5!<nswdw}@HM4}3x3RvXavC#wZO at 1cc22HA(~W>%AX5V)Qx0)5HujmrZ43EXa5
zo33UIA+o^H9i=A*@(JJQPz;PFa<d@(QGsy;er~Ja at J-+m8_@kSuN>$?gxo*I)8-uw
zAWZO82UrJS9l<vp;Hdz%5q!r1?gVfp!H*o^4FK*Y_%8?eFo35Be&GP02k-{LZ{lF~
z-vRuSphs5*MJoFXAlw?0o9RTm138GO&xsBOQb at F)6Xp5#RHDP2=xiWI5gp+`bMtZC
zE(r9{9639v0o$)JcOuXhup>0O5o~^b?h>HqgB_WZdpy`niH?+0gImD%E6BSa<OzgP
zB~nUWu~T`!2k<(<@ec6s06sw|@H at aS0c0$K=0peR12B-_YzKHKfKq}B9pDiFW)VEf
z0agGwp5O`x7y-~iu*w0R0$?k_hy&aS;3|R*4)7)b_Y-V(fR6)so?y8RdU-Kb1zsh3
z8F at 2Q-vaP4!4p|SUR_O}0Z6R?cxoIBbO%td&IY`^NQ*H>^hEO7VD87bUOEV1VNUKB
zVDrKDTbP at Qi=q?A&Y$hs*l$k$4DdsM^_vR~@LcQl!|`P-FAd32cOw=HD<By+dUpQt
zpe)JgIVyjp#m`O6uebPl8Tl<1Kfhc4$riuBn}52+FYJ}S&EgmJ%in4775(!sv-rh1
z`PYHxoH%;P at ci4rbNU#)bhHZGhe+{CsZg1_xYEPn`7y$)+QCl|jtVSGMw#4Ak{2jz
zX`93x#$KmrZ3oGW{2j_;BA1n>vG_4zJzv?rnG~N<q$e&rg%PR65LHTxGL;IX6Q~k@
z<;QkW1+plr7F{lB&3xUPXgKbUHq)PIjh)z>kPIOjapX3fzzK;a3yC%h>d+lSbi14-
zN-5?a27mo at GH?V%x5^n}Tojl_^maKlbf9yHo-c<y8#V4#P;{4^b0mt6p=hU^8YYUW
zD7r^Z4HHGR6m5)GCgmy+C3;3%)U5wbq-aB1kqT at gdU{*bBshzrljF6obJ#)jltgqF
z(amj9W9CYV&XEo(*+ at YcRTFQ3=otk6*0=*~el_t0pr284eq18?Py7bxkR^~@5|`*S
zBY at 7M<jS~2r&$7Y9VL6?66t2*M&MM4ichtNkXILU3(=q1s0wT+u+;{P+C at Zn#O+G)
zr2ho=P;^m;m2w?L7bm3B-rPdbt`0 at _Qj}0`UCVioK=c&Fo5Vp$9(Q%n5$w;y at LR%L
zOo11u8Il1&_f+5&0{X0js0#d<K)v{WtRxOGG4ECd-l1rX7?)M7aHoor$UmaIHtt4(
zQs6(7pD1!!JV{GP`oPx|$sJX%l;AB`l>&OTeVPiSFNM-s@$_l96XR533rzM=X*J6d
zIGC(n^-1ICHP{fMdX-KTQ*AzxCaDzZPys)I_3`%82 at fZ#&!cogTo2NJCxN(@PKCTA
zovG&D2G9B$p+rheM9rH4t@#^Gv at 57<=`+x70(@65?Bb%Nc^R&cPr?FkQzqoaDJ=b>
z|AUt76;<=MQwe{ZTwP1MVmt3cR`Q{MtmG9(BjPYIcRDnC0OQ}>jff1?yk+-M6V+~2
zLSf`lI8x%K#DWbF(Qd{hxN<clvUf~xnNo|NYm;z9f9$%w91!#N{E1s-)ciNwsQdyJ
zF1Bp{5+d97>j}2!?=uMpfV!4`2C)ZztbtQYT}zm(`y@#GtYLlYM7Ei!85NUf;O>Wl
z3lh44@{gEHr71qhZpF#t{*qw0L!?p>(hxEbSQlgazWZR|=0%siR`baF*Pijpvel<t
zvf)ehk3CPmUywP!?}{t$8hCJ at 4+d{O_U>~pJnI_h--YligjW#WMfe<{8#3;XFbZJ;
z!W;x{Mgmc63jVRS8D~53k6VQ47rPUipMTtcMjh4@|JdsoZ#8n+(uO!~u$}lPj}e1f
z`LO1h#*(x1G0uGW#|n1l!QREV<%3nX#Q4`y-C8=VPlk?kn3m;>Rh*gGc+;7gPhWFh
z&uNG+MyNJ{c@!b=?|1~pM<DQzJ3|?Nqpw8mHpiW0)q;TWB!A4GZJwe$XxmJ??TM!%
zu&vV(*w)<<ya?F{y%A^{eNCZH%WxSCIuwC at 21_`h?BMi?SOF-<WeLI<gs}+Y5$F@{
zO)FM0^`?MMMPPZ$5vC)|LcrxXg_Bd!!MTD$)hmwU6$T4|RwA%|Xr~5r6~bzSI)nxU
z;!#73AIo&Fc(=kgY5c;oHxxF1{#xbcZP)!V<Fc>UfBfs4)=!J=xbuPy75f at LeE6zy
z`CAv=e|5p$9S^)eB)DPkiJ7;1yS3caT-s-1m!}@w`tZ(Y{<VI^n<GZNH{<fR|Fg<H
zZ&vxFrM(J$$3(ZjUiMAnXDhZ|?BD*U&l|2=ceMKSt^UWmFI?jL`#X!y_Aa<*cU8{L
z4f~!t<M-#?ck3}XZ@>2R)FWJhE3SX$i{+CB<)-(0uyDiPeJggqwb*m;U;9p+9DM0_
z*X+Kn^za$0P9I<W)z+y`-RP?6|EM=waNhd7{O2Eh(%a{)>;-in9=dw?-UWBO{K~@{
z%D(hYe6Y_Q!OGHJQ+r?k(cllWUV7`~^%ws6n-MvOe0c7=`(|GL{%rq!efPdG;`!y@
zbpQE at FMfIL9Y5Rf=kY7wTRr5%tQYq!_x|>%&o96H%|*V|7hiY!rs4%>=Nxmy7YiQy
z^y~Z+CtUgL`4jFq|C8qqd2#34{THr&=FrzK*nVlox>eUzzxBH*u^qdQTlLr6nv9B~
zgKnMp>DWtGUbb%Ap4pe5vGAbG(HqaqymwUZiH}|U%H$ny|K{w#&IkH^b?f>44|(<v
zsotU6cK!P=%_Djox%c#a`8|s!4}R?7-EW=HV_~l+Cq!4T{KddqQzxB&_SqX>y!Fo`
zZhPu)3m>@P4=d9j-m~G$;d6TYcg4^12kxs_{ws9cml57a_!`0M;bl<tIfR)A$09T!
zY(m(H at G!!22yY{NiqHj}zCS_{!W4uh2&)jbAY6)YE5a`kUPO2o;Y)-p43fbJr3ljz
zmLt?5Y(zL8;W~u-5q^vC7lcm`JeWlLA&f+*K&U}jhp-jla)dh&evR-Eg6e{Chfshp
z384a^24Nk-l?ZnsJc;ls!bb=ku-OQC2;&jvAOsPb5Kc$97~v*_Um!e>@Hd3d5V~Rx
z9e^+zVJgB>gb2b0gmV$DLg0&9euMBD!p8_MOklkb4n;T&VJ^b)2vLO12)ht&MtB6_
z1%$sNe2$Qb2?g(PQpE_<5RO7vjc^jec7&@D{)F%$La!{$edT&i;{zp}gYd_jlAPvv
z2eFSJa?_Cz_X!$^mo*6SYKMV%*N+fy1{#Pb%Y=9iZ6F at 42yxE^XJh>FayB7e<u+Q}
zj6sN7BZg52Q>M}4C3 at p3Z_84PcWR9m_wl2DDn6A3TYMr5|9m(BgwGd%@Q-&&n3PK}
zlT=>k0f?{pFk0L%KrL<uH4yLZ5*m!UFbR2|l at PZ|8ZF-IB*dML2I4a;g!oj8fq18t
z&};F8yuD0_w|$Kk_tEp%!JQR=xXT`7gC at Wg@3ArscUPJ;s}LnriePG)J4Xm{BZ+aG
zw-gBRPJ>A}!r0<wP6Kg|5w*CZ!r0;^4MJSyo3<DUF9~rAi-CAgn-Fh68(X|*O^91f
z4Yb45G0$?1U)+8}EnY at 35V!vl;`R^YggnFn=rOdafq0XeTHJ$b%*%5zfG$AX_{D8C
z)Z)DnW1bi62yt0%5^~!JA#Myd5VtxJ;w}@Dqddt0XmY&Ryw^@GZkaU+`Q%9|ARb}?
z@%bbWJ`)1M=U9y1HZvT#O~ydH5J+phK4>7`X(z- at wFZ)H`+&Hm$CQ#&C$;#<n$g;9
z3jP^jqs6Cs=-CGd(Bkt{Abj8k|9r*-gn#lnAkep<Zy>%*iW%IGV65@=ORN~~|A7{F
zHyLGlpazn^qRd8_+oPDCmn2Z3{FB$^fbumuCLy;=P>VY#j253YfP&(CJD~MH1pM>C
z4iG-E0m47NVTwul1}u{&?^_b$y-Wk~qAMX at i!}+kO^XmOv6wsu8aKEH!)WoMAhmd{
z&_LW!L5TaK4J41r0rH?OOpe^-K`mZzG3I$+l at Ra3nS}Dt51__)&suH@)C$<x;yx56
z<PBD1ix2z|;xk0X7Pp=d;sy}|aT5n2?$b69x0w*)u5bf!R|Fwmvohv+OOg=pz8Ece
zGy_m`{3yabUew~PHj|LM;t27S+9Z@$G6CXaY6jv{LDb?CZw8Wws{r+k*95Q4Qj1pt
zjFvpz1nAzl7B>h|i<`;VE%C?QFNC;}-6Z7Z8A9CmZXkJ^6d=AV#6Y}aPc2@^HxPIG
z5aMPW196iIA>QOS5I5iv;;Fi+3GUG$#4YwlOP+xO#C?CJY57P7wfGc;(R!h)hIrCx
zw1$~!iW}jK7B?+1A$JiOi1$7T at lL2o$ome2cp2SjaW at a4^tksEjH}#bWVCoqfm(c$
z^l(u8aVHBQUcWSD<fcAC+~wDUI(kPFAwGOyY;hwHAwCLVAa36w#2pa^;^rhm&&3n+
zF)u>guV|W<w^s=9GQLU3r-0G`@i|od^Fc at uK79(p2TMV?854w0Q-bi1TasvqPb3(K
z4=<$x;yZx=@d-x|J~YNyJgGcf2|ez#G;Seg{hb76uyRkf;(XYae;egjpAmvJr~yH?
z8x|vu>D$R4HFDGm|Juo))3}^*b|ioEJLLO}99 at im?d)4;zOMC)lxwZm<?WW9u^n3M
z3OtkbF5o%hH{TflaJ0<wZgx-Y&ZglX^`;?wK40sxobqSsO+79395f~MYAN_0_AY?h
zyT;zP<@*ryp8Fnpe}mqAM$gnkyK=Cs{Bx~eFh^=4eRnFNUaLMvA;L0joTtml{=mPC
zQ;cD&ywi1gc~+Dv=S?n`>&vX}3WSx9;3}Hj*jO8>3dQgZqG-{ws)p)tVW_dOXlg?}
zzNit47EKGcglq9xgQlXz4Gp#UB0<E`n-;DKHP^-p*W!y9MpD!qZ7Qma)E5;N7Dei-
zYMZOWMO7n57PS<s1CS9uVN_IwZyc;FDlRS at U07me`9tzrP#cQXG&I#ki{^%^=2t8$
zY&3wQ;1$zm+u~^T8Y!eH-A|ZR5k6{CB;SIH{*<}?^f^XK#*O(YOK3hZ^8-3)lAVSv
ziF5E6KB}^kgAi|+Z)jRaE*h(@4%ZZ};-s%XO`*Rw1`)m+V<)h`{AJSUI3tmUXiaN1
zIeeCew#YIm`5?ddW4?Z+^MI1&gysNag0y)i#%D0_(IW^j2hk|vVic6$G13BR at naeB
z7{6p>V*HYZHi5%lkTH|cikg&G)FeezX9qKIN_Rx?n9b}j8#!{2?;DvovXE~ZA!-?Q
z#90c=9V~_BpvDYzM?eH?M_a%upc at TFiOmuPpJ8gF!I-fX<YO3Gxk`T+gC_LnNC2}I
z%?C4xTjrR*`4ooK8{O7w2~llXi!^V21;eUunCI66V4a^Uu=D}7Wg+MH1PbwyI5~Qx
zmZ&cFTBDz*d)Ie7DQTNhS~sP1nU&JI%+nKZ44x%W%O-GXM?ZK)T1wN+sV<L7OSwHQ
zW4k98a`k}6({+z0d$}h)?Qf}W$~I?a<ah>mot5grJCv_ze85u%9+H$ddpv+_kS67-
zQy%b40XHu#qsHyV at kzY{pHK${FM)bNp8!SG74SIQ4fIA(bcBMdKv8$ScWYX(85E@`
z;JFQ&sDM|NagnOvC{U~)3vhzO^-BSkm6C3<k&grI0^F<_3V3{FI;_cfC#Jxxb_?FX
z-3ioO+BJrrYUm6 at _hB_l`R#_THFO~C5P#IrD-7Le=<$Y5GBn3ftSVWaG}M90l7DUI
z5Ew&z?nqPu?XHDV7MP9D<KOwHlq_J at +OWXLw`;Lnai{*HCJt88ziHxcnD{;uPe=M5
zu1D2#CVnXr^k5?M_ZfIcRJ{g$XZ-PmcoF<_%5O|aKQAGEQiA^Z3G%BF;+XX84}1O;
z-*q_fxj8>sVdwS}eMZ7jnSOk at 44<#mhlrU~{5EaE_dLsijhD~1;VW at XGpq0g;A!~Q
zh6>`tCNeW&qQ!SiXo8<gN!GUWYveGtq at G{x3N8vqoAIp{hw%h2+k9 at -uFoI$=?&-i
zO_DX`_~=S-d2!hSetB(PxV1tK)P8>05oIbaZHq6OJ<ohE_D3~OIc<&?lNFKm;ZCp?
oT)B2_5GM`MhI%YGV(Wq}qt*1OQ}JoKs&FH|)5Wi0j^@<y|4{hK!vFvP
literal 0
HcmV?d00001
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