[llvm] b61ac4a - [DWARFLinkerParallel] Add support for -odr mode. (#68721)

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 23 02:56:40 PST 2023


Author: avl-llvm
Date: 2023-11-23T13:56:34+03:00
New Revision: b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d

URL: https://github.com/llvm/llvm-project/commit/b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d
DIFF: https://github.com/llvm/llvm-project/commit/b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d.diff

LOG: [DWARFLinkerParallel] Add support for -odr mode. (#68721)

This patch is extracted from D96035, it adds support for the type
deduplication mode. With this patch DWARFLinkerParallel handles --odr
option. It also processes clang modules.

Added: 
    llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
    llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
    llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
    llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
    llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
    llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
    llvm/lib/DWARFLinkerParallel/TypePool.h
    llvm/lib/DWARFLinkerParallel/Utils.h
    llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
    llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
    llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o
    llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o
    llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o
    llvm/test/tools/dsymutil/X86/Inputs/String/main.o
    llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test

Modified: 
    llvm/lib/DWARFLinkerParallel/ArrayList.h
    llvm/lib/DWARFLinkerParallel/CMakeLists.txt
    llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
    llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
    llvm/lib/DWARFLinkerParallel/DIEGenerator.h
    llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
    llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
    llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
    llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
    llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
    llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
    llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
    llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
    llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
    llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
    llvm/lib/DWARFLinkerParallel/DependencyTracker.h
    llvm/lib/DWARFLinkerParallel/OutputSections.cpp
    llvm/lib/DWARFLinkerParallel/OutputSections.h
    llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
    llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
    llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
    llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
    llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
    llvm/test/tools/dsymutil/X86/dead-stripped.cpp
    llvm/test/tools/dsymutil/X86/dummy-debug-map.map
    llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
    llvm/test/tools/dsymutil/X86/empty-CU.test
    llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
    llvm/test/tools/dsymutil/X86/keep-func.test
    llvm/test/tools/dsymutil/X86/location-expression.test
    llvm/test/tools/dsymutil/X86/modules-empty.m
    llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
    llvm/test/tools/dsymutil/X86/op-convert.test
    llvm/test/tools/dsymutil/X86/union-fwd-decl.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
    llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
    llvm/tools/dsymutil/DwarfLinkerForBinary.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
new file mode 100644
index 000000000000000..5ec25cfe5fd26e1
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp
@@ -0,0 +1,295 @@
+//=== AcceleratorRecordsSaver.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AcceleratorRecordsSaver.h"
+#include "Utils.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/Support/DJB.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE,
+                                       int ChildRecurseDepth = 0) {
+  const char *Name = nullptr;
+  CompileUnit *CU = &InputCU;
+  std::optional<DWARFFormValue> RefVal;
+
+  if (Error Err = finiteLoop([&]() -> Expected<bool> {
+        if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
+          Name = CurrentName;
+
+        if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
+            !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
+          return false;
+
+        if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
+          return false;
+
+        std::optional<UnitEntryPairTy> RefDie = CU->resolveDIEReference(
+            *RefVal, ResolveInterCUReferencesMode::Resolve);
+        if (!RefDie)
+          return false;
+
+        if (!RefDie->DieEntry)
+          return false;
+
+        CU = RefDie->CU;
+        InputDIE = RefDie->CU->getDIE(RefDie->DieEntry);
+        return true;
+      })) {
+    consumeError(std::move(Err));
+  }
+
+  if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
+    Name = "(anonymous namespace)";
+
+  DWARFDie ParentDie = InputDIE.getParent();
+  if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
+    return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));
+
+  return djbHash(
+      (Name ? Name : ""),
+      djbHash((Name ? "::" : ""),
+              hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth)));
+}
+
+void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry,
+                                   DIE *OutDIE, AttributesInfo &AttrInfo,
+                                   TypeEntry *TypeEntry) {
+  if (GlobalData.getOptions().AccelTables.empty())
+    return;
+
+  DWARFDie InputDIE = InUnit.getDIE(InputDieEntry);
+
+  // Look for short name recursively if short name is not known yet.
+  if (AttrInfo.Name == nullptr)
+    if (const char *ShortName = InputDIE.getShortName())
+      AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first;
+
+  switch (InputDieEntry->getTag()) {
+  case dwarf::DW_TAG_array_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_enumeration_type:
+  case dwarf::DW_TAG_pointer_type:
+  case dwarf::DW_TAG_reference_type:
+  case dwarf::DW_TAG_string_type:
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_subroutine_type:
+  case dwarf::DW_TAG_typedef:
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_ptr_to_member_type:
+  case dwarf::DW_TAG_set_type:
+  case dwarf::DW_TAG_subrange_type:
+  case dwarf::DW_TAG_base_type:
+  case dwarf::DW_TAG_const_type:
+  case dwarf::DW_TAG_constant:
+  case dwarf::DW_TAG_file_type:
+  case dwarf::DW_TAG_namelist:
+  case dwarf::DW_TAG_packed_type:
+  case dwarf::DW_TAG_volatile_type:
+  case dwarf::DW_TAG_restrict_type:
+  case dwarf::DW_TAG_atomic_type:
+  case dwarf::DW_TAG_interface_type:
+  case dwarf::DW_TAG_unspecified_type:
+  case dwarf::DW_TAG_shared_type:
+  case dwarf::DW_TAG_immutable_type:
+  case dwarf::DW_TAG_rvalue_reference_type: {
+    if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr &&
+        !AttrInfo.Name->getKey().empty()) {
+      uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE);
+
+      uint64_t RuntimeLang =
+          dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
+              .value_or(0);
+
+      bool ObjCClassIsImplementation =
+          (RuntimeLang == dwarf::DW_LANG_ObjC ||
+           RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
+          dwarf::toUnsigned(
+              InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
+              .value_or(0);
+
+      saveTypeRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), Hash,
+                     ObjCClassIsImplementation, TypeEntry);
+    }
+  } break;
+  case dwarf::DW_TAG_namespace: {
+    if (AttrInfo.Name == nullptr)
+      AttrInfo.Name =
+          GlobalData.getStringPool().insert("(anonymous namespace)").first;
+
+    saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
+                        TypeEntry);
+  } break;
+  case dwarf::DW_TAG_imported_declaration: {
+    if (AttrInfo.Name != nullptr)
+      saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
+                          TypeEntry);
+  } break;
+  case dwarf::DW_TAG_compile_unit:
+  case dwarf::DW_TAG_lexical_block: {
+    // Nothing to do.
+  } break;
+  default:
+    if (TypeEntry)
+      // Do not store this kind of accelerator entries for type entries.
+      return;
+
+    if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
+      if (AttrInfo.Name)
+        saveNameRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(),
+                       InputDieEntry->getTag() ==
+                           dwarf::DW_TAG_inlined_subroutine);
+
+      // Look for mangled name recursively if mangled name is not known yet.
+      if (!AttrInfo.MangledName)
+        if (const char *LinkageName = InputDIE.getLinkageName())
+          AttrInfo.MangledName =
+              GlobalData.getStringPool().insert(LinkageName).first;
+
+      if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
+        saveNameRecord(AttrInfo.MangledName, OutDIE, InputDieEntry->getTag(),
+                       InputDieEntry->getTag() ==
+                           dwarf::DW_TAG_inlined_subroutine);
+
+      // Strip template parameters from the short name.
+      if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name &&
+          (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
+        if (std::optional<StringRef> Name =
+                StripTemplateParameters(AttrInfo.Name->getKey())) {
+          StringEntry *NameWithoutTemplateParams =
+              GlobalData.getStringPool().insert(*Name).first;
+
+          saveNameRecord(NameWithoutTemplateParams, OutDIE,
+                         InputDieEntry->getTag(), true);
+        }
+      }
+
+      if (AttrInfo.Name)
+        saveObjC(InputDieEntry, OutDIE, AttrInfo);
+    }
+    break;
+  }
+}
+
+void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry,
+                                       DIE *OutDIE, AttributesInfo &AttrInfo) {
+  std::optional<ObjCSelectorNames> Names =
+      getObjCNamesIfSelector(AttrInfo.Name->getKey());
+  if (!Names)
+    return;
+
+  StringEntry *Selector =
+      GlobalData.getStringPool().insert(Names->Selector).first;
+  saveNameRecord(Selector, OutDIE, InputDieEntry->getTag(), true);
+  StringEntry *ClassName =
+      GlobalData.getStringPool().insert(Names->ClassName).first;
+  saveObjCNameRecord(ClassName, OutDIE, InputDieEntry->getTag());
+  if (Names->ClassNameNoCategory) {
+    StringEntry *ClassNameNoCategory =
+        GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first;
+    saveObjCNameRecord(ClassNameNoCategory, OutDIE, InputDieEntry->getTag());
+  }
+  if (Names->MethodNameNoCategory) {
+    StringEntry *MethodNameNoCategory =
+        GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first;
+    saveNameRecord(MethodNameNoCategory, OutDIE, InputDieEntry->getTag(), true);
+  }
+}
+
+void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE,
+                                             dwarf::Tag Tag,
+                                             bool AvoidForPubSections) {
+  DwarfUnit::AccelInfo Info;
+
+  Info.Type = DwarfUnit::AccelType::Name;
+  Info.String = Name;
+  Info.OutOffset = OutDIE->getOffset();
+  Info.Tag = Tag;
+  Info.AvoidForPubSections = AvoidForPubSections;
+
+  OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+}
+void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry *Name,
+                                                  DIE *OutDIE, dwarf::Tag Tag,
+                                                  TypeEntry *TypeEntry) {
+  if (OutUnit.isCompileUnit()) {
+    assert(TypeEntry == nullptr);
+    DwarfUnit::AccelInfo Info;
+
+    Info.Type = DwarfUnit::AccelType::Namespace;
+    Info.String = Name;
+    Info.OutOffset = OutDIE->getOffset();
+    Info.Tag = Tag;
+
+    OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+    return;
+  }
+
+  assert(TypeEntry != nullptr);
+  TypeUnit::TypeUnitAccelInfo Info;
+  Info.Type = DwarfUnit::AccelType::Namespace;
+  Info.String = Name;
+  Info.OutOffset = 0xbaddef;
+  Info.Tag = Tag;
+  Info.OutDIE = OutDIE;
+  Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
+
+  OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
+}
+
+void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE,
+                                                 dwarf::Tag Tag) {
+  DwarfUnit::AccelInfo Info;
+
+  Info.Type = DwarfUnit::AccelType::ObjC;
+  Info.String = Name;
+  Info.OutOffset = OutDIE->getOffset();
+  Info.Tag = Tag;
+  Info.AvoidForPubSections = true;
+
+  OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+}
+
+void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE,
+                                             dwarf::Tag Tag,
+                                             uint32_t QualifiedNameHash,
+                                             bool ObjcClassImplementation,
+                                             TypeEntry *TypeEntry) {
+  if (OutUnit.isCompileUnit()) {
+    assert(TypeEntry == nullptr);
+    DwarfUnit::AccelInfo Info;
+
+    Info.Type = DwarfUnit::AccelType::Type;
+    Info.String = Name;
+    Info.OutOffset = OutDIE->getOffset();
+    Info.Tag = Tag;
+    Info.QualifiedNameHash = QualifiedNameHash;
+    Info.ObjcClassImplementation = ObjcClassImplementation;
+
+    OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info);
+    return;
+  }
+
+  assert(TypeEntry != nullptr);
+  TypeUnit::TypeUnitAccelInfo Info;
+
+  Info.Type = DwarfUnit::AccelType::Type;
+  Info.String = Name;
+  Info.OutOffset = 0xbaddef;
+  Info.Tag = Tag;
+  Info.QualifiedNameHash = QualifiedNameHash;
+  Info.ObjcClassImplementation = ObjcClassImplementation;
+  Info.OutDIE = OutDIE;
+  Info.TypeEntryBodyPtr = TypeEntry->getValue().load();
+  OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info);
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm

diff  --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
new file mode 100644
index 000000000000000..5e7f4d0c3166fd1
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h
@@ -0,0 +1,70 @@
+//===- AcceleratorRecordsSaver.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H
+
+#include "DIEAttributeCloner.h"
+#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerGlobalData.h"
+#include "DWARFLinkerTypeUnit.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// This class helps to store information for accelerator entries.
+/// It prepares accelerator info for the certain DIE and store it inside
+/// OutUnit.
+class AcceleratorRecordsSaver {
+public:
+  AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
+                          CompileUnit *OutUnit)
+      : AcceleratorRecordsSaver(GlobalData, InUnit,
+                                CompileUnit::OutputUnitVariantPtr(OutUnit)) {}
+
+  AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
+                          TypeUnit *OutUnit)
+      : AcceleratorRecordsSaver(GlobalData, InUnit,
+                                CompileUnit::OutputUnitVariantPtr(OutUnit)) {}
+
+  /// Save accelerator info for the specified \p OutDIE inside OutUnit.
+  /// Side effects: set attributes in \p AttrInfo.
+  void save(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
+            AttributesInfo &AttrInfo, TypeEntry *TypeEntry);
+
+protected:
+  AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit,
+                          CompileUnit::OutputUnitVariantPtr OutUnit)
+      : GlobalData(GlobalData), InUnit(InUnit), OutUnit(OutUnit) {}
+
+  void saveObjC(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE,
+                AttributesInfo &AttrInfo);
+
+  void saveNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
+                      bool AvoidForPubSections);
+  void saveNamespaceRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
+                           TypeEntry *TypeEntry);
+  void saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag);
+  void saveTypeRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag,
+                      uint32_t QualifiedNameHash, bool ObjcClassImplementation,
+                      TypeEntry *TypeEntry);
+
+  /// Global linking data.
+  LinkingGlobalData &GlobalData;
+
+  /// Comiple unit corresponding to input DWARF.
+  CompileUnit &InUnit;
+
+  /// Compile unit or Artificial type unit corresponding to the output DWARF.
+  CompileUnit::OutputUnitVariantPtr OutUnit;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H

diff  --git a/llvm/lib/DWARFLinkerParallel/ArrayList.h b/llvm/lib/DWARFLinkerParallel/ArrayList.h
index 58d550982c8dfc0..def83f91bc6f319 100644
--- a/llvm/lib/DWARFLinkerParallel/ArrayList.h
+++ b/llvm/lib/DWARFLinkerParallel/ArrayList.h
@@ -21,6 +21,9 @@ namespace dwarflinker_parallel {
 /// Method add() can be called asynchronously.
 template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
 public:
+  ArrayList(parallel::PerThreadBumpPtrAllocator *Allocator)
+      : Allocator(Allocator) {}
+
   /// Add specified \p Item to the list.
   T &add(const T &Item) {
     assert(Allocator);
@@ -73,8 +76,27 @@ template <typename T, size_t ItemsGroupSize = 512> class ArrayList {
     LastGroup = nullptr;
   }
 
-  void setAllocator(parallel::PerThreadBumpPtrAllocator *Allocator) {
-    this->Allocator = Allocator;
+  void sort(function_ref<bool(const T &LHS, const T &RHS)> Comparator) {
+    SmallVector<T> SortedItems;
+    forEach([&](T &Item) { SortedItems.push_back(Item); });
+
+    if (SortedItems.size()) {
+      std::sort(SortedItems.begin(), SortedItems.end(), Comparator);
+
+      size_t SortedItemIdx = 0;
+      forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; });
+      assert(SortedItemIdx == SortedItems.size());
+    }
+  }
+
+  size_t size() {
+    size_t Result = 0;
+
+    for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr;
+         CurGroup = CurGroup->Next)
+      Result += CurGroup->getItemsCount();
+
+    return Result;
   }
 
 protected:

diff  --git a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
index d321ecf8d5ce847..b0f0b3910e586ab 100644
--- a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
+++ b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt
@@ -1,14 +1,17 @@
 add_llvm_component_library(LLVMDWARFLinkerParallel
+  AcceleratorRecordsSaver.cpp
   DependencyTracker.cpp
   DIEAttributeCloner.cpp
   DWARFEmitterImpl.cpp
   DWARFFile.cpp
   DWARFLinker.cpp
   DWARFLinkerCompileUnit.cpp
+  DWARFLinkerTypeUnit.cpp
   DWARFLinkerImpl.cpp
   DWARFLinkerUnit.cpp
   OutputSections.cpp
   StringPool.cpp
+  SyntheticTypeNameBuilder.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/DWARFLinkerParallel

diff  --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
index d05fd8d61b85743..81fc57f7cabbb79 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp
@@ -13,18 +13,16 @@ namespace llvm {
 namespace dwarflinker_parallel {
 
 void DIEAttributeCloner::clone() {
-  DWARFUnit &U = CU.getOrigUnit();
-
   // Extract and clone every attribute.
-  DWARFDataExtractor Data = U.getDebugInfoExtractor();
+  DWARFDataExtractor Data = InUnit.getOrigUnit().getDebugInfoExtractor();
 
   uint64_t Offset = InputDieEntry->getOffset();
   // Point to the next DIE (generally there is always at least a NULL
   // entry after the current one). If this is a lone
   // DW_TAG_compile_unit without any children, point to the next unit.
-  uint64_t NextOffset = (InputDIEIdx + 1 < U.getNumDIEs())
-                            ? U.getDIEAtIndex(InputDIEIdx + 1).getOffset()
-                            : U.getNextUnitOffset();
+  uint64_t NextOffset = (InputDIEIdx + 1 < InUnit.getOrigUnit().getNumDIEs())
+                            ? InUnit.getDIEAtIndex(InputDIEIdx + 1).getOffset()
+                            : InUnit.getOrigUnit().getNextUnitOffset();
 
   // We could copy the data only if we need to apply a relocation to it. After
   // testing, it seems there is no performance downside to doing the copy
@@ -34,8 +32,8 @@ void DIEAttributeCloner::clone() {
       DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
 
   // Modify the copy with relocated addresses.
-  CU.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
-                                                   Data.isLittleEndian());
+  InUnit.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset,
+                                                       Data.isLittleEndian());
 
   // Reset the Offset to 0 as we will be working on the local copy of
   // the data.
@@ -45,17 +43,18 @@ void DIEAttributeCloner::clone() {
   Offset += getULEB128Size(Abbrev->getCode());
 
   // Set current output offset.
-  AttrOutOffset = OutDIE->getOffset();
+  AttrOutOffset = OutUnit.isCompileUnit() ? OutDIE->getOffset() : 0;
   for (const auto &AttrSpec : Abbrev->attributes()) {
     // Check whether current attribute should be skipped.
     if (shouldSkipAttribute(AttrSpec)) {
       DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
-                                U.getFormParams());
+                                InUnit.getFormParams());
       continue;
     }
 
     DWARFFormValue Val = AttrSpec.getFormValue();
-    Val.extractValue(Data, &Offset, U.getFormParams(), &U);
+    Val.extractValue(Data, &Offset, InUnit.getFormParams(),
+                     &InUnit.getOrigUnit());
 
     // Clone current attribute.
     switch (AttrSpec.Form) {
@@ -107,10 +106,10 @@ void DIEAttributeCloner::clone() {
       AttrOutOffset += cloneAddressAttr(Val, AttrSpec);
       break;
     default:
-      CU.warn("unsupported attribute form " +
-                  dwarf::FormEncodingString(AttrSpec.Form) +
-                  " in DieAttributeCloner::clone(). Dropping.",
-              InputDieEntry);
+      InUnit.warn("unsupported attribute form " +
+                      dwarf::FormEncodingString(AttrSpec.Form) +
+                      " in DieAttributeCloner::clone(). Dropping.",
+                  InputDieEntry);
     }
   }
 
@@ -118,19 +117,20 @@ void DIEAttributeCloner::clone() {
   // Check if original compile unit already has DW_AT_str_offsets_base
   // attribute.
   if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
-      CU.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
+      InUnit.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) {
     DebugInfoOutputSection.notePatchWithOffsetUpdate(
-        DebugOffsetPatch{
-            AttrOutOffset,
-            &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets),
-            true},
+        DebugOffsetPatch{AttrOutOffset,
+                         &OutUnit->getOrCreateSectionDescriptor(
+                             DebugSectionKind::DebugStrOffsets),
+                         true},
         PatchesOffsets);
 
-    AttrOutOffset += Generator
-                         .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
-                                             dwarf::DW_FORM_sec_offset,
-                                             CU.getDebugStrOffsetsHeaderSize())
-                         .second;
+    AttrOutOffset +=
+        Generator
+            .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
+                                dwarf::DW_FORM_sec_offset,
+                                OutUnit->getDebugStrOffsetsHeaderSize())
+            .second;
   }
 }
 
@@ -142,28 +142,28 @@ bool DIEAttributeCloner::shouldSkipAttribute(
   case dwarf::DW_AT_low_pc:
   case dwarf::DW_AT_high_pc:
   case dwarf::DW_AT_ranges:
-    if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
+    if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
       return false;
 
     // Skip address attribute if we are in function scope and function does not
     // reference live address.
-    return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
+    return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
            !FuncAddressAdjustment.has_value();
   case dwarf::DW_AT_rnglists_base:
     // In case !Update the .debug_addr table is not generated/preserved.
     // Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used.
     // Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the
     // DW_AT_rnglists_base is removed.
-    return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
+    return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
   case dwarf::DW_AT_loclists_base:
     // In case !Update the .debug_addr table is not generated/preserved.
     // Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used.
     // Since DW_AT_loclists_base is used for only DW_FORM_loclistx the
     // DW_AT_loclists_base is removed.
-    return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
+    return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
   case dwarf::DW_AT_location:
   case dwarf::DW_AT_frame_base:
-    if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
+    if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
       return false;
 
     // When location expression contains an address: skip this attribute
@@ -173,7 +173,7 @@ bool DIEAttributeCloner::shouldSkipAttribute(
 
     // Skip location attribute if we are in function scope and function does not
     // reference live address.
-    return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
+    return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() &&
            !FuncAddressAdjustment.has_value();
   }
 }
@@ -183,19 +183,12 @@ size_t DIEAttributeCloner::cloneStringAttr(
     const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
   std::optional<const char *> String = dwarf::toString(Val);
   if (!String) {
-    CU.warn("cann't read string attribute.");
+    InUnit.warn("cann't read string attribute.");
     return 0;
   }
 
   StringEntry *StringInPool =
-      CU.getGlobalData().getStringPool().insert(*String).first;
-  if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
-    DebugInfoOutputSection.notePatchWithOffsetUpdate(
-        DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
-    return Generator
-        .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp)
-        .second;
-  }
+      InUnit.getGlobalData().getStringPool().insert(*String).first;
 
   // Update attributes info.
   if (AttrSpec.Attr == dwarf::DW_AT_name)
@@ -204,9 +197,29 @@ size_t DIEAttributeCloner::cloneStringAttr(
            AttrSpec.Attr == dwarf::DW_AT_linkage_name)
     AttrInfo.MangledName = StringInPool;
 
-  if (CU.getVersion() < 5) {
-    DebugInfoOutputSection.notePatchWithOffsetUpdate(
-        DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
+  if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
+    if (OutUnit.isTypeUnit()) {
+      DebugInfoOutputSection.notePatch(DebugTypeLineStrPatch{
+          AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx),
+          StringInPool});
+    } else {
+      DebugInfoOutputSection.notePatchWithOffsetUpdate(
+          DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
+    }
+    return Generator
+        .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp)
+        .second;
+  }
+
+  if (Use_DW_FORM_strp) {
+    if (OutUnit.isTypeUnit()) {
+      DebugInfoOutputSection.notePatch(
+          DebugTypeStrPatch{AttrOutOffset, OutDIE,
+                            InUnit.getDieTypeEntry(InputDIEIdx), StringInPool});
+    } else {
+      DebugInfoOutputSection.notePatchWithOffsetUpdate(
+          DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets);
+    }
 
     return Generator
         .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_strp)
@@ -215,7 +228,7 @@ size_t DIEAttributeCloner::cloneStringAttr(
 
   return Generator
       .addIndexedStringAttribute(AttrSpec.Attr, dwarf::DW_FORM_strx,
-                                 CU.getDebugStrIndex(StringInPool))
+                                 OutUnit->getDebugStrIndex(StringInPool))
       .second;
 }
 
@@ -225,22 +238,48 @@ size_t DIEAttributeCloner::cloneDieRefAttr(
   if (AttrSpec.Attr == dwarf::DW_AT_sibling)
     return 0;
 
-  std::optional<std::pair<CompileUnit *, uint32_t>> RefDiePair =
-      CU.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve);
-  if (!RefDiePair) {
+  std::optional<UnitEntryPairTy> RefDiePair =
+      InUnit.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve);
+  if (!RefDiePair || !RefDiePair->DieEntry) {
     // If the referenced DIE is not found,  drop the attribute.
-    CU.warn("cann't find referenced DIE.", InputDieEntry);
+    InUnit.warn("cann't find referenced DIE.", InputDieEntry);
     return 0;
   }
-  assert(RefDiePair->first->getStage() >= CompileUnit::Stage::Loaded);
-  assert(RefDiePair->second != 0);
+
+  TypeEntry *RefTypeName = nullptr;
+  const CompileUnit::DIEInfo &RefDIEInfo =
+      RefDiePair->CU->getDIEInfo(RefDiePair->DieEntry);
+  if (RefDIEInfo.needToPlaceInTypeTable())
+    RefTypeName = RefDiePair->CU->getDieTypeEntry(RefDiePair->DieEntry);
+
+  if (OutUnit.isTypeUnit()) {
+    assert(RefTypeName && "Type name for referenced DIE is not set");
+    assert(InUnit.getDieTypeEntry(InputDIEIdx) &&
+           "Type name for DIE is not set");
+
+    DebugInfoOutputSection.notePatch(DebugType2TypeDieRefPatch{
+        AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx),
+        RefTypeName});
+
+    return Generator
+        .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref4, 0xBADDEF)
+        .second;
+  }
+
+  if (RefTypeName) {
+    DebugInfoOutputSection.notePatchWithOffsetUpdate(
+        DebugDieTypeRefPatch{AttrOutOffset, RefTypeName}, PatchesOffsets);
+
+    return Generator
+        .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref_addr, 0xBADDEF)
+        .second;
+  }
 
   // Get output offset for referenced DIE.
-  uint64_t OutDieOffset =
-      RefDiePair->first->getDieOutOffset(RefDiePair->second);
+  uint64_t OutDieOffset = RefDiePair->CU->getDieOutOffset(RefDiePair->DieEntry);
 
   // Examine whether referenced DIE is in current compile unit.
-  bool IsLocal = CU.getUniqueID() == RefDiePair->first->getUniqueID();
+  bool IsLocal = OutUnit->getUniqueID() == RefDiePair->CU->getUniqueID();
 
   // Set attribute form basing on the kind of referenced DIE(local or not?).
   dwarf::Form NewForm = IsLocal ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr;
@@ -254,8 +293,9 @@ size_t DIEAttributeCloner::cloneDieRefAttr(
   // If offset value is not known at this point then create patch for the
   // reference value and write dummy value into the attribute.
   DebugInfoOutputSection.notePatchWithOffsetUpdate(
-      DebugDieRefPatch{AttrOutOffset, &CU, RefDiePair->first,
-                       RefDiePair->second},
+      DebugDieRefPatch{AttrOutOffset, OutUnit.getAsCompileUnit(),
+                       RefDiePair->CU,
+                       RefDiePair->CU->getDIEIndex(RefDiePair->DieEntry)},
       PatchesOffsets);
   return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, 0xBADDEF).second;
 }
@@ -267,41 +307,47 @@ size_t DIEAttributeCloner::cloneScalarAttr(
   // Create patches for attribute referencing other non invariant section.
   // Invariant section could not be updated here as this section and
   // reference to it do not change value in case --update.
-  if (AttrSpec.Attr == dwarf::DW_AT_macro_info) {
+  switch (AttrSpec.Attr) {
+  case dwarf::DW_AT_macro_info: {
     if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
       const DWARFDebugMacro *Macro =
-          CU.getContaingFile().Dwarf->getDebugMacinfo();
+          InUnit.getContaingFile().Dwarf->getDebugMacinfo();
       if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))
         return 0;
 
       DebugInfoOutputSection.notePatchWithOffsetUpdate(
-          DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
-                                              DebugSectionKind::DebugMacinfo)},
+          DebugOffsetPatch{AttrOutOffset,
+                           &OutUnit->getOrCreateSectionDescriptor(
+                               DebugSectionKind::DebugMacinfo)},
           PatchesOffsets);
     }
-  } else if (AttrSpec.Attr == dwarf::DW_AT_macros) {
+  } break;
+  case dwarf::DW_AT_macros: {
     if (std::optional<uint64_t> Offset = Val.getAsSectionOffset()) {
       const DWARFDebugMacro *Macro =
-          CU.getContaingFile().Dwarf->getDebugMacro();
+          InUnit.getContaingFile().Dwarf->getDebugMacro();
       if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset))
         return 0;
 
       DebugInfoOutputSection.notePatchWithOffsetUpdate(
-          DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
-                                              DebugSectionKind::DebugMacro)},
+          DebugOffsetPatch{AttrOutOffset,
+                           &OutUnit->getOrCreateSectionDescriptor(
+                               DebugSectionKind::DebugMacro)},
           PatchesOffsets);
     }
-  } else if (AttrSpec.Attr == dwarf::DW_AT_stmt_list) {
+  } break;
+  case dwarf::DW_AT_stmt_list: {
     DebugInfoOutputSection.notePatchWithOffsetUpdate(
-        DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor(
+        DebugOffsetPatch{AttrOutOffset, &OutUnit->getOrCreateSectionDescriptor(
                                             DebugSectionKind::DebugLine)},
         PatchesOffsets);
-  } else if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) {
+  } break;
+  case dwarf::DW_AT_str_offsets_base: {
     DebugInfoOutputSection.notePatchWithOffsetUpdate(
-        DebugOffsetPatch{
-            AttrOutOffset,
-            &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets),
-            true},
+        DebugOffsetPatch{AttrOutOffset,
+                         &OutUnit->getOrCreateSectionDescriptor(
+                             DebugSectionKind::DebugStrOffsets),
+                         true},
         PatchesOffsets);
 
     // Use size of .debug_str_offsets header as attribute value. The offset
@@ -309,9 +355,36 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     AttrInfo.HasStringOffsetBaseAttr = true;
     return Generator
         .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form,
-                            CU.getDebugStrOffsetsHeaderSize())
+                            OutUnit->getDebugStrOffsetsHeaderSize())
         .second;
-  }
+  } break;
+  case dwarf::DW_AT_decl_file: {
+    // Value of DW_AT_decl_file may exceed original form. Longer
+    // form can affect offsets to the following attributes. To not
+    // update offsets of the following attributes we always remove
+    // original DW_AT_decl_file and attach it to the last position
+    // later.
+    if (OutUnit.isTypeUnit()) {
+      if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename =
+              InUnit.getDirAndFilenameFromLineTable(Val))
+        DebugInfoOutputSection.notePatch(DebugTypeDeclFilePatch{
+            OutDIE,
+            InUnit.getDieTypeEntry(InputDIEIdx),
+            OutUnit->getGlobalData()
+                .getStringPool()
+                .insert(DirAndFilename->first)
+                .first,
+            OutUnit->getGlobalData()
+                .getStringPool()
+                .insert(DirAndFilename->second)
+                .first,
+        });
+      return 0;
+    }
+  } break;
+  default: {
+  } break;
+  };
 
   uint64_t Value;
   if (AttrSpec.Attr == dwarf::DW_AT_const_value &&
@@ -319,7 +392,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
        InputDieEntry->getTag() == dwarf::DW_TAG_constant))
     AttrInfo.HasLiveAddress = true;
 
-  if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) {
+  if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) {
     if (auto OptionalValue = Val.getAsUnsignedConstant())
       Value = *OptionalValue;
     else if (auto OptionalValue = Val.getAsSignedConstant())
@@ -327,8 +400,8 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     else if (auto OptionalValue = Val.getAsSectionOffset())
       Value = *OptionalValue;
     else {
-      CU.warn("unsupported scalar attribute form. Dropping attribute.",
-              InputDieEntry);
+      InUnit.warn("unsupported scalar attribute form. Dropping attribute.",
+                  InputDieEntry);
       return 0;
     }
 
@@ -350,12 +423,13 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     // to DW_FORM_sec_offset here.
     std::optional<uint64_t> Index = Val.getAsSectionOffset();
     if (!Index) {
-      CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+      InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
       return 0;
     }
-    std::optional<uint64_t> Offset = CU.getOrigUnit().getRnglistOffset(*Index);
+    std::optional<uint64_t> Offset =
+        InUnit.getOrigUnit().getRnglistOffset(*Index);
     if (!Offset) {
-      CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+      InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
       return 0;
     }
 
@@ -367,12 +441,13 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     // to DW_FORM_sec_offset here.
     std::optional<uint64_t> Index = Val.getAsSectionOffset();
     if (!Index) {
-      CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+      InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
       return 0;
     }
-    std::optional<uint64_t> Offset = CU.getOrigUnit().getLoclistOffset(*Index);
+    std::optional<uint64_t> Offset =
+        InUnit.getOrigUnit().getLoclistOffset(*Index);
     if (!Offset) {
-      CU.warn("cann't read the attribute. Dropping.", InputDieEntry);
+      InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry);
       return 0;
     }
 
@@ -380,11 +455,14 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     ResultingForm = dwarf::DW_FORM_sec_offset;
   } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
              InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
-    std::optional<uint64_t> LowPC = CU.getLowPc();
+    if (!OutUnit.isCompileUnit())
+      return 0;
+
+    std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc();
     if (!LowPC)
       return 0;
     // Dwarf >= 4 high_pc is an size, not an address.
-    Value = CU.getHighPc() - *LowPC;
+    Value = OutUnit.getAsCompileUnit()->getHighPc() - *LowPC;
   } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
     Value = *Val.getAsSectionOffset();
   else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
@@ -392,8 +470,8 @@ size_t DIEAttributeCloner::cloneScalarAttr(
   else if (auto OptionalValue = Val.getAsUnsignedConstant())
     Value = *OptionalValue;
   else {
-    CU.warn("unsupported scalar attribute form. Dropping attribute.",
-            InputDieEntry);
+    InUnit.warn("unsupported scalar attribute form. Dropping attribute.",
+                InputDieEntry);
     return 0;
   }
 
@@ -408,7 +486,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
   } else if (DWARFAttribute::mayHaveLocationList(AttrSpec.Attr) &&
              dwarf::doesFormBelongToClass(AttrSpec.Form,
                                           DWARFFormValue::FC_SectionOffset,
-                                          CU.getOrigUnit().getVersion())) {
+                                          InUnit.getOrigUnit().getVersion())) {
     int64_t AddrAdjustmentValue = 0;
     if (VarAddressAdjustment)
       AddrAdjustmentValue = *VarAddressAdjustment;
@@ -422,7 +500,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     DebugInfoOutputSection.notePatchWithOffsetUpdate(
         DebugOffsetPatch{
             AttrOutOffset,
-            &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr),
+            &OutUnit->getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr),
             true},
         PatchesOffsets);
 
@@ -430,7 +508,7 @@ size_t DIEAttributeCloner::cloneScalarAttr(
     // .debug_addr would be added later while patching.
     return Generator
         .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form,
-                            CU.getDebugAddrHeaderSize())
+                            OutUnit->getDebugAddrHeaderSize())
         .second;
   } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
     AttrInfo.IsDeclaration = true;
@@ -443,6 +521,9 @@ size_t DIEAttributeCloner::cloneBlockAttr(
     const DWARFFormValue &Val,
     const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {
 
+  if (OutUnit.isTypeUnit())
+    return 0;
+
   size_t NumberOfPatchesAtStart = PatchesOffsets.size();
 
   // If the block is a DWARF Expression, clone it into the temporary
@@ -452,15 +533,14 @@ size_t DIEAttributeCloner::cloneBlockAttr(
   if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) &&
       (Val.isFormClass(DWARFFormValue::FC_Block) ||
        Val.isFormClass(DWARFFormValue::FC_Exprloc))) {
-    DWARFUnit &OrigUnit = CU.getOrigUnit();
     DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()),
-                       OrigUnit.isLittleEndian(),
-                       OrigUnit.getAddressByteSize());
-    DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(),
-                         OrigUnit.getFormParams().Format);
+                       InUnit.getOrigUnit().isLittleEndian(),
+                       InUnit.getOrigUnit().getAddressByteSize());
+    DWARFExpression Expr(Data, InUnit.getOrigUnit().getAddressByteSize(),
+                         InUnit.getFormParams().Format);
 
-    CU.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection,
-                              VarAddressAdjustment, PatchesOffsets);
+    InUnit.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection,
+                                  VarAddressAdjustment, PatchesOffsets);
     Bytes = Buffer;
   }
 
@@ -491,7 +571,7 @@ size_t DIEAttributeCloner::cloneBlockAttr(
   if (HasLocationExpressionAddress)
     AttrInfo.HasLiveAddress =
         VarAddressAdjustment.has_value() ||
-        CU.getGlobalData().getOptions().UpdateIndexTablesOnly;
+        InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly;
 
   return FinalAttributeSize;
 }
@@ -502,11 +582,14 @@ size_t DIEAttributeCloner::cloneAddressAttr(
   if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
     AttrInfo.HasLiveAddress = true;
 
-  if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly)
+  if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly)
     return Generator
         .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Val.getRawUValue())
         .second;
 
+  if (OutUnit.isTypeUnit())
+    return 0;
+
   // Cloned Die may have address attributes relocated to a
   // totally unrelated value. This can happen:
   //   - If high_pc is an address (Dwarf version == 2), then it might have been
@@ -520,25 +603,25 @@ size_t DIEAttributeCloner::cloneAddressAttr(
   //  Info.PCOffset here.
 
   std::optional<DWARFFormValue> AddrAttribute =
-      CU.find(InputDieEntry, AttrSpec.Attr);
+      InUnit.find(InputDieEntry, AttrSpec.Attr);
   if (!AddrAttribute)
     llvm_unreachable("Cann't find attribute");
 
   std::optional<uint64_t> Addr = AddrAttribute->getAsAddress();
   if (!Addr) {
-    CU.warn("cann't read address attribute value.");
+    InUnit.warn("cann't read address attribute value.");
     return 0;
   }
 
   if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
       AttrSpec.Attr == dwarf::DW_AT_low_pc) {
-    if (std::optional<uint64_t> LowPC = CU.getLowPc())
+    if (std::optional<uint64_t> LowPC = OutUnit.getAsCompileUnit()->getLowPc())
       Addr = *LowPC;
     else
       return 0;
   } else if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit &&
              AttrSpec.Attr == dwarf::DW_AT_high_pc) {
-    if (uint64_t HighPc = CU.getHighPc())
+    if (uint64_t HighPc = OutUnit.getAsCompileUnit()->getHighPc())
       Addr = HighPc;
     else
       return 0;
@@ -556,20 +639,14 @@ size_t DIEAttributeCloner::cloneAddressAttr(
 
   return Generator
       .addScalarAttribute(AttrSpec.Attr, dwarf::Form::DW_FORM_addrx,
-                          CU.getDebugAddrIndex(*Addr))
+                          OutUnit.getAsCompileUnit()->getDebugAddrIndex(*Addr))
       .second;
 }
 
 unsigned DIEAttributeCloner::finalizeAbbreviations(bool HasChildrenToClone) {
-  size_t SizeOfAbbreviationNumber =
-      Generator.finalizeAbbreviations(HasChildrenToClone);
-
-  // We need to update patches offsets after we know the size of the
-  // abbreviation number.
-  updatePatchesWithSizeOfAbbreviationNumber(SizeOfAbbreviationNumber);
-
   // Add the size of the abbreviation number to the output offset.
-  AttrOutOffset += SizeOfAbbreviationNumber;
+  AttrOutOffset +=
+      Generator.finalizeAbbreviations(HasChildrenToClone, &PatchesOffsets);
 
   return AttrOutOffset;
 }

diff  --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
index 74d80e131480171..e18c0a15cefc63d 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
+++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h
@@ -13,6 +13,7 @@
 #include "DIEGenerator.h"
 #include "DWARFLinkerCompileUnit.h"
 #include "DWARFLinkerGlobalData.h"
+#include "DWARFLinkerTypeUnit.h"
 
 namespace llvm {
 namespace dwarflinker_parallel {
@@ -44,20 +45,28 @@ struct AttributesInfo {
 /// attribute, adds cloned attribute to the output DIE.
 class DIEAttributeCloner {
 public:
-  DIEAttributeCloner(DIE *OutDIE, CompileUnit &CU,
+  DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, CompileUnit *OutUnit,
                      const DWARFDebugInfoEntry *InputDieEntry,
                      DIEGenerator &Generator,
                      std::optional<int64_t> FuncAddressAdjustment,
                      std::optional<int64_t> VarAddressAdjustment,
                      bool HasLocationExpressionAddress)
-      : OutDIE(OutDIE), CU(CU),
-        DebugInfoOutputSection(
-            CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)),
-        InputDieEntry(InputDieEntry), Generator(Generator),
-        FuncAddressAdjustment(FuncAddressAdjustment),
-        VarAddressAdjustment(VarAddressAdjustment),
-        HasLocationExpressionAddress(HasLocationExpressionAddress) {
-    InputDIEIdx = CU.getDIEIndex(InputDieEntry);
+      : DIEAttributeCloner(OutDIE, InUnit,
+                           CompileUnit::OutputUnitVariantPtr(OutUnit),
+                           InputDieEntry, Generator, FuncAddressAdjustment,
+                           VarAddressAdjustment, HasLocationExpressionAddress) {
+  }
+
+  DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, TypeUnit *OutUnit,
+                     const DWARFDebugInfoEntry *InputDieEntry,
+                     DIEGenerator &Generator,
+                     std::optional<int64_t> FuncAddressAdjustment,
+                     std::optional<int64_t> VarAddressAdjustment,
+                     bool HasLocationExpressionAddress)
+      : DIEAttributeCloner(OutDIE, InUnit,
+                           CompileUnit::OutputUnitVariantPtr(OutUnit),
+                           InputDieEntry, Generator, FuncAddressAdjustment,
+                           VarAddressAdjustment, HasLocationExpressionAddress) {
   }
 
   /// Clone attributes of input DIE.
@@ -69,7 +78,36 @@ class DIEAttributeCloner {
   /// Cannot be used concurrently.
   AttributesInfo AttrInfo;
 
+  unsigned getOutOffset() { return AttrOutOffset; }
+
 protected:
+  DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit,
+                     CompileUnit::OutputUnitVariantPtr OutUnit,
+                     const DWARFDebugInfoEntry *InputDieEntry,
+                     DIEGenerator &Generator,
+                     std::optional<int64_t> FuncAddressAdjustment,
+                     std::optional<int64_t> VarAddressAdjustment,
+                     bool HasLocationExpressionAddress)
+      : OutDIE(OutDIE), InUnit(InUnit), OutUnit(OutUnit),
+        DebugInfoOutputSection(
+            OutUnit->getSectionDescriptor(DebugSectionKind::DebugInfo)),
+        InputDieEntry(InputDieEntry), Generator(Generator),
+        FuncAddressAdjustment(FuncAddressAdjustment),
+        VarAddressAdjustment(VarAddressAdjustment),
+        HasLocationExpressionAddress(HasLocationExpressionAddress) {
+    InputDIEIdx = InUnit.getDIEIndex(InputDieEntry);
+
+    // Use DW_FORM_strp form for string attributes for DWARF version less than 5
+    // or if output unit is type unit and we need to produce deterministic
+    // result. (We can not generate deterministic results for debug_str_offsets
+    // section when attributes are cloned parallelly).
+    Use_DW_FORM_strp =
+        (InUnit.getVersion() < 5) ||
+        (OutUnit.isTypeUnit() &&
+         ((InUnit.getGlobalData().getOptions().Threads != 1) &&
+          !InUnit.getGlobalData().getOptions().AllowNonDeterministicOutput));
+  }
+
   /// Clone string attribute.
   size_t
   cloneStringAttr(const DWARFFormValue &Val,
@@ -99,18 +137,14 @@ class DIEAttributeCloner {
   bool
   shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec);
 
-  /// Update patches offsets with the size of abbreviation number.
-  void
-  updatePatchesWithSizeOfAbbreviationNumber(unsigned SizeOfAbbreviationNumber) {
-    for (uint64_t *OffsetPtr : PatchesOffsets)
-      *OffsetPtr += SizeOfAbbreviationNumber;
-  }
-
   /// Output DIE.
   DIE *OutDIE = nullptr;
 
-  /// Compile unit for the output DIE.
-  CompileUnit &CU;
+  /// Input compilation unit.
+  CompileUnit &InUnit;
+
+  /// Output unit(either "plain" compilation unit, either artificial type unit).
+  CompileUnit::OutputUnitVariantPtr OutUnit;
 
   /// .debug_info section descriptor.
   SectionDescriptor &DebugInfoOutputSection;
@@ -139,6 +173,9 @@ class DIEAttributeCloner {
 
   /// Patches for the cloned attributes.
   OffsetsPtrVector PatchesOffsets;
+
+  /// This flag forces using DW_FORM_strp for string attributes.
+  bool Use_DW_FORM_strp = false;
 };
 
 } // end of namespace dwarflinker_parallel

diff  --git a/llvm/lib/DWARFLinkerParallel/DIEGenerator.h b/llvm/lib/DWARFLinkerParallel/DIEGenerator.h
index c0bbce0f520143c..42bf00f55ff1801 100644
--- a/llvm/lib/DWARFLinkerParallel/DIEGenerator.h
+++ b/llvm/lib/DWARFLinkerParallel/DIEGenerator.h
@@ -23,6 +23,9 @@ class DIEGenerator {
   DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU)
       : Allocator(Allocator), CU(CU) {}
 
+  DIEGenerator(DIE *OutputDIE, BumpPtrAllocator &Allocator, DwarfUnit &CU)
+      : Allocator(Allocator), CU(CU), OutputDIE(OutputDIE) {}
+
   /// Creates a DIE of specified tag \p DieTag and \p OutOffset.
   DIE *createDIE(dwarf::Tag DieTag, uint32_t OutOffset) {
     OutputDIE = DIE::get(Allocator, DieTag);
@@ -32,6 +35,8 @@ class DIEGenerator {
     return OutputDIE;
   }
 
+  DIE *getDIE() { return OutputDIE; }
+
   /// Adds a specified \p Child to the current DIE.
   void addChild(DIE *Child) {
     assert(Child != nullptr);
@@ -126,8 +131,10 @@ class DIEGenerator {
   }
 
   /// Creates appreviations for the current DIE. Returns value of
-  /// abbreviation number.
-  size_t finalizeAbbreviations(bool CHILDREN_yes) {
+  /// abbreviation number. Updates offsets with the size of abbreviation
+  /// number.
+  size_t finalizeAbbreviations(bool CHILDREN_yes,
+                               OffsetsPtrVector *OffsetsList) {
     // Create abbreviations for output DIE.
     DIEAbbrev NewAbbrev = OutputDIE->generateAbbrev();
     if (CHILDREN_yes)
@@ -136,7 +143,15 @@ class DIEGenerator {
     CU.assignAbbrev(NewAbbrev);
     OutputDIE->setAbbrevNumber(NewAbbrev.getNumber());
 
-    return getULEB128Size(OutputDIE->getAbbrevNumber());
+    size_t AbbrevNumberSize = getULEB128Size(OutputDIE->getAbbrevNumber());
+
+    // Add size of abbreviation number to the offsets.
+    if (OffsetsList != nullptr) {
+      for (uint64_t *OffsetPtr : *OffsetsList)
+        *OffsetPtr += AbbrevNumberSize;
+    }
+
+    return AbbrevNumberSize;
   }
 
 protected:

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
index f082fd603610038..269f24b1a13b9ab 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "DWARFLinkerImpl.h"
+#include "DependencyTracker.h"
 
 std::unique_ptr<llvm::dwarflinker_parallel::DWARFLinker>
 llvm::dwarflinker_parallel::DWARFLinker::createLinker(

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
index c1181a264f879f0..48e7cb1fd7e2f36 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp
@@ -7,17 +7,65 @@
 //===----------------------------------------------------------------------===//
 
 #include "DWARFLinkerCompileUnit.h"
+#include "AcceleratorRecordsSaver.h"
 #include "DIEAttributeCloner.h"
 #include "DIEGenerator.h"
-#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "DependencyTracker.h"
+#include "SyntheticTypeNameBuilder.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
 #include "llvm/Support/DJB.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+#include <utility>
 
 using namespace llvm;
 using namespace llvm::dwarflinker_parallel;
 
+CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, unsigned ID,
+                         StringRef ClangModuleName, DWARFFile &File,
+                         OffsetToUnitTy UnitFromOffset,
+                         dwarf::FormParams Format, llvm::endianness Endianess)
+    : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
+      getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded),
+      AcceleratorRecords(&GlobalData.getAllocator()) {
+  UnitName = File.FileName;
+  setOutputFormat(Format, Endianess);
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+}
+
+CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit,
+                         unsigned ID, StringRef ClangModuleName,
+                         DWARFFile &File, OffsetToUnitTy UnitFromOffset,
+                         dwarf::FormParams Format, llvm::endianness Endianess)
+    : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
+      OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset),
+      Stage(Stage::CreatedNotLoaded),
+      AcceleratorRecords(&GlobalData.getAllocator()) {
+  setOutputFormat(Format, Endianess);
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+
+  DWARFDie CUDie = OrigUnit.getUnitDIE();
+  if (!CUDie)
+    return;
+
+  if (std::optional<DWARFFormValue> Val = CUDie.find(dwarf::DW_AT_language)) {
+    uint16_t LangVal = dwarf::toUnsigned(Val, 0);
+    if (isODRLanguage(LangVal))
+      Language = LangVal;
+  }
+
+  if (!GlobalData.getOptions().NoODR && Language.has_value())
+    NoODR = false;
+
+  if (const char *CUName = CUDie.getName(DINameKind::ShortName))
+    UnitName = CUName;
+  else
+    UnitName = File.FileName;
+  SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
+}
+
 void CompileUnit::loadLineTable() {
   LineTablePtr = File.Dwarf->getLineTableForUnit(&getOrigUnit());
 }
@@ -39,6 +87,7 @@ void CompileUnit::maybeResetToLoadedStage() {
   HighPc = 0;
   Labels.clear();
   Ranges.clear();
+  Dependencies.reset(nullptr);
 
   if (getStage() < Stage::Cloned) {
     setStage(Stage::Loaded);
@@ -53,6 +102,8 @@ void CompileUnit::maybeResetToLoadedStage() {
 
   for (uint64_t &Offset : OutDieOffsetArray)
     Offset = 0;
+  for (TypeEntry *&Name : TypeEntries)
+    Name = nullptr;
   eraseSections();
 
   setStage(Stage::CreatedNotLoaded);
@@ -66,21 +117,30 @@ bool CompileUnit::loadInputDIEs() {
   // load input dies, resize Info structures array.
   DieInfoArray.resize(getOrigUnit().getNumDIEs());
   OutDieOffsetArray.resize(getOrigUnit().getNumDIEs(), 0);
+  if (!NoODR)
+    TypeEntries.resize(getOrigUnit().getNumDIEs());
   return true;
 }
 
 void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
-                                           bool IsInModule, bool IsInFunction) {
+                                           bool IsODRUnavailableFunctionScope) {
+  CompileUnit::DIEInfo &DieInfo = getDIEInfo(DieEntry);
+
   for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry);
        CurChild && CurChild->getAbbreviationDeclarationPtr();
        CurChild = getSiblingEntry(CurChild)) {
     CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild);
+    bool ChildIsODRUnavailableFunctionScope = IsODRUnavailableFunctionScope;
 
-    if (IsInModule)
+    if (DieInfo.getIsInMouduleScope())
       ChildInfo.setIsInMouduleScope();
-    if (IsInFunction)
+
+    if (DieInfo.getIsInFunctionScope())
       ChildInfo.setIsInFunctionScope();
 
+    if (DieInfo.getIsInAnonNamespaceScope())
+      ChildInfo.setIsInAnonNamespaceScope();
+
     switch (CurChild->getTag()) {
     case dwarf::DW_TAG_module:
       ChildInfo.setIsInMouduleScope();
@@ -91,19 +151,35 @@ void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
       break;
     case dwarf::DW_TAG_subprogram:
       ChildInfo.setIsInFunctionScope();
+      if (!ChildIsODRUnavailableFunctionScope &&
+          !ChildInfo.getIsInMouduleScope()) {
+        if (find(CurChild,
+                 {dwarf::DW_AT_abstract_origin, dwarf::DW_AT_specification}))
+          ChildIsODRUnavailableFunctionScope = true;
+      }
       break;
+    case dwarf::DW_TAG_namespace: {
+      UnitEntryPairTy NamespaceEntry = {this, CurChild};
+
+      if (find(CurChild, dwarf::DW_AT_extension))
+        NamespaceEntry = NamespaceEntry.getNamespaceOrigin();
+
+      if (!NamespaceEntry.CU->find(NamespaceEntry.DieEntry, dwarf::DW_AT_name))
+        ChildInfo.setIsInAnonNamespaceScope();
+    } break;
     default:
       break;
     }
 
-    if (IsInModule)
-      ChildInfo.setIsInMouduleScope();
-    if (IsInFunction)
-      ChildInfo.setIsInFunctionScope();
+    if (!isClangModule() && !getGlobalData().getOptions().UpdateIndexTablesOnly)
+      ChildInfo.setTrackLiveness();
+
+    if ((!ChildInfo.getIsInAnonNamespaceScope() &&
+         !ChildIsODRUnavailableFunctionScope && !NoODR))
+      ChildInfo.setODRAvailable();
 
     if (CurChild->hasChildren())
-      analyzeDWARFStructureRec(CurChild, ChildInfo.getIsInMouduleScope(),
-                               ChildInfo.getIsInFunctionScope());
+      analyzeDWARFStructureRec(CurChild, ChildIsODRUnavailableFunctionScope);
   }
 }
 
@@ -162,8 +238,11 @@ void CompileUnit::cleanupDataAfterClonning() {
   AbbreviationsSet.clear();
   ResolvedFullPaths.shrink_and_clear();
   ResolvedParentPaths.clear();
+  FileNames.shrink_and_clear();
   DieInfoArray = SmallVector<DIEInfo>();
   OutDieOffsetArray = SmallVector<uint64_t>();
+  TypeEntries = SmallVector<TypeEntry *>();
+  Dependencies.reset(nullptr);
   getOrigUnit().clear();
 }
 
@@ -184,7 +263,7 @@ static SmallString<128> guessToolchainBaseDir(StringRef SysRoot) {
 /// Collect references to parseable Swift interfaces in imported
 /// DW_TAG_module blocks.
 void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) {
-  if (getLanguage() != dwarf::DW_LANG_Swift)
+  if (!Language || Language != dwarf::DW_LANG_Swift)
     return;
 
   if (!GlobalData.getOptions().ParseableSwiftInterfaces)
@@ -231,12 +310,43 @@ void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) {
   }
 }
 
+Error CompileUnit::assignTypeNames(TypePool &TypePoolRef) {
+  if (!getUnitDIE().isValid())
+    return Error::success();
+
+  SyntheticTypeNameBuilder NameBuilder(TypePoolRef);
+  return assignTypeNamesRec(getDebugInfoEntry(0), NameBuilder);
+}
+
+Error CompileUnit::assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry,
+                                      SyntheticTypeNameBuilder &NameBuilder) {
+  OrderedChildrenIndexAssigner ChildrenIndexAssigner(*this, DieEntry);
+  for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry);
+       CurChild && CurChild->getAbbreviationDeclarationPtr();
+       CurChild = getSiblingEntry(CurChild)) {
+    CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild);
+    if (!ChildInfo.needToPlaceInTypeTable())
+      continue;
+
+    assert(ChildInfo.getODRAvailable());
+    if (Error Err = NameBuilder.assignName(
+            {this, CurChild},
+            ChildrenIndexAssigner.getChildIndex(*this, CurChild)))
+      return Err;
+
+    if (Error Err = assignTypeNamesRec(CurChild, NameBuilder))
+      return Err;
+  }
+
+  return Error::success();
+}
+
 void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
   if (std::optional<SectionDescriptor *> DebugInfoSection =
           tryGetSectionDescriptor(DebugSectionKind::DebugInfo)) {
 
     (*DebugInfoSection)
-        ->ListDebugDieRefPatch.forEach([](DebugDieRefPatch &Patch) {
+        ->ListDebugDieRefPatch.forEach([&](DebugDieRefPatch &Patch) {
           /// Replace stored DIE indexes with DIE output offsets.
           Patch.RefDieIdxOrClonedOffset =
               Patch.RefCU.getPointer()->getDieOutOffset(
@@ -245,7 +355,7 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
 
     (*DebugInfoSection)
         ->ListDebugULEB128DieRefPatch.forEach(
-            [](DebugULEB128DieRefPatch &Patch) {
+            [&](DebugULEB128DieRefPatch &Patch) {
               /// Replace stored DIE indexes with DIE output offsets.
               Patch.RefDieIdxOrClonedOffset =
                   Patch.RefCU.getPointer()->getDieOutOffset(
@@ -278,45 +388,53 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
   }
 }
 
-std::optional<std::pair<CompileUnit *, uint32_t>>
-CompileUnit::resolveDIEReference(
+std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference(
     const DWARFFormValue &RefValue,
     ResolveInterCUReferencesMode CanResolveInterCUReferences) {
   if (std::optional<DWARFFormValue::UnitOffset> Ref =
           *RefValue.getAsRelativeReference()) {
-    if (Ref->Unit != nullptr) {
+    if (Ref->Unit == OrigUnit) {
       // Referenced DIE is in current compile unit.
-
       if (std::optional<uint32_t> RefDieIdx =
-              getDIEIndexForOffset(Ref->Unit->getOffset() + Ref->Offset))
-        return std::make_pair(this, *RefDieIdx);
+              getDIEIndexForOffset(OrigUnit->getOffset() + Ref->Offset))
+        return UnitEntryPairTy{this, OrigUnit->getDebugInfoEntry(*RefDieIdx)};
     }
-
-    if (CompileUnit *RefCU = getUnitFromOffset(Ref->Offset)) {
-      if (RefCU->getUniqueID() == getUniqueID()) {
+    uint64_t RefDIEOffset =
+        Ref->Unit ? Ref->Unit->getOffset() + Ref->Offset : Ref->Offset;
+    if (CompileUnit *RefCU = getUnitFromOffset(RefDIEOffset)) {
+      if (RefCU == this) {
         // Referenced DIE is in current compile unit.
         if (std::optional<uint32_t> RefDieIdx =
-                getDIEIndexForOffset(Ref->Offset))
-          return std::make_pair(this, *RefDieIdx);
+                getDIEIndexForOffset(RefDIEOffset))
+          return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)};
       } else if (CanResolveInterCUReferences) {
         // Referenced DIE is in other compile unit.
 
         // Check whether DIEs are loaded for that compile unit.
         enum Stage ReferredCUStage = RefCU->getStage();
         if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned)
-          return std::make_pair(RefCU, 0);
+          return UnitEntryPairTy{RefCU, nullptr};
 
         if (std::optional<uint32_t> RefDieIdx =
-                RefCU->getDIEIndexForOffset(Ref->Offset))
-          return std::make_pair(RefCU, *RefDieIdx);
+                RefCU->getDIEIndexForOffset(RefDIEOffset))
+          return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)};
       } else
-        return std::make_pair(RefCU, 0);
+        return UnitEntryPairTy{RefCU, nullptr};
     }
   }
 
   return std::nullopt;
 }
 
+std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference(
+    const DWARFDebugInfoEntry *DieEntry, dwarf::Attribute Attr,
+    ResolveInterCUReferencesMode CanResolveInterCUReferences) {
+  if (std::optional<DWARFFormValue> AttrVal = find(DieEntry, Attr))
+    return resolveDIEReference(*AttrVal, CanResolveInterCUReferences);
+
+  return std::nullopt;
+}
+
 void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
                                    int64_t PcOffset) {
   std::lock_guard<std::mutex> Guard(RangesMutex);
@@ -565,48 +683,6 @@ Error CompileUnit::emitDebugAddrSection() {
   return Error::success();
 }
 
-Error CompileUnit::emitDebugStringOffsetSection() {
-  if (getVersion() < 5)
-    return Error::success();
-
-  if (DebugStringIndexMap.empty())
-    return Error::success();
-
-  SectionDescriptor &OutDebugStrOffsetsSection =
-      getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets);
-
-  // Emit section header.
-
-  //   Emit length.
-  OutDebugStrOffsetsSection.emitUnitLength(0xBADDEF);
-  uint64_t OffsetAfterSectionLength = OutDebugStrOffsetsSection.OS.tell();
-
-  //   Emit version.
-  OutDebugStrOffsetsSection.emitIntVal(5, 2);
-
-  //   Emit padding.
-  OutDebugStrOffsetsSection.emitIntVal(0, 2);
-
-  //   Emit index to offset map.
-  for (const StringEntry *String : DebugStringIndexMap.getValues()) {
-    // Note patch for string offset value.
-    OutDebugStrOffsetsSection.notePatch(
-        DebugStrPatch{{OutDebugStrOffsetsSection.OS.tell()}, String});
-
-    // Emit placeholder for offset value.
-    OutDebugStrOffsetsSection.emitOffset(0xBADDEF);
-  }
-
-  // Patch section length.
-  OutDebugStrOffsetsSection.apply(
-      OffsetAfterSectionLength -
-          OutDebugStrOffsetsSection.getFormParams().getDwarfOffsetByteSize(),
-      dwarf::DW_FORM_sec_offset,
-      OutDebugStrOffsetsSection.OS.tell() - OffsetAfterSectionLength);
-
-  return Error::success();
-}
-
 Error CompileUnit::cloneAndEmitRanges() {
   if (getGlobalData().getOptions().UpdateIndexTablesOnly)
     return Error::success();
@@ -1165,20 +1241,25 @@ void CompileUnit::cloneDieAttrExpression(
   }
 }
 
-Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple) {
+Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple,
+                                TypeUnit *ArtificialTypeUnit) {
   BumpPtrAllocator Allocator;
 
   DWARFDie OrigUnitDIE = getOrigUnit().getUnitDIE();
   if (!OrigUnitDIE.isValid())
     return Error::success();
 
+  TypeEntry *RootEntry = nullptr;
+  if (ArtificialTypeUnit)
+    RootEntry = ArtificialTypeUnit->getTypePool().getRoot();
+
   // Clone input DIE entry recursively.
-  DIE *OutCUDie =
-      cloneDIE(OrigUnitDIE.getDebugInfoEntry(), getDebugInfoHeaderSize(),
-               std::nullopt, std::nullopt, Allocator);
-  setOutUnitDIE(OutCUDie);
+  std::pair<DIE *, TypeEntry *> OutCUDie = cloneDIE(
+      OrigUnitDIE.getDebugInfoEntry(), RootEntry, getDebugInfoHeaderSize(),
+      std::nullopt, std::nullopt, Allocator, ArtificialTypeUnit);
+  setOutUnitDIE(OutCUDie.first);
 
-  if (getGlobalData().getOptions().NoOutput || (OutCUDie == nullptr))
+  if (getGlobalData().getOptions().NoOutput || (OutCUDie.first == nullptr))
     return Error::success();
 
   assert(TargetTriple.has_value());
@@ -1188,6 +1269,7 @@ Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple) {
   if (Error Err = cloneAndEmitDebugMacro())
     return Err;
 
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
   if (Error Err = emitDebugInfo(*TargetTriple))
     return Err;
 
@@ -1215,27 +1297,103 @@ Error CompileUnit::cloneAndEmit(std::optional<Triple> TargetTriple) {
   return emitAbbreviations();
 }
 
-bool needToClone(CompileUnit::DIEInfo &Info) {
-  return Info.getKeep() || Info.getKeepChildren();
-}
-
-DIE *CompileUnit::cloneDIE(const DWARFDebugInfoEntry *InputDieEntry,
-                           uint64_t OutOffset,
-                           std::optional<int64_t> FuncAddressAdjustment,
-                           std::optional<int64_t> VarAddressAdjustment,
-                           BumpPtrAllocator &Allocator) {
+std::pair<DIE *, TypeEntry *> CompileUnit::cloneDIE(
+    const DWARFDebugInfoEntry *InputDieEntry, TypeEntry *ClonedParentTypeDIE,
+    uint64_t OutOffset, std::optional<int64_t> FuncAddressAdjustment,
+    std::optional<int64_t> VarAddressAdjustment, BumpPtrAllocator &Allocator,
+    TypeUnit *ArtificialTypeUnit) {
   uint32_t InputDieIdx = getDIEIndex(InputDieEntry);
   CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx);
 
-  if (!needToClone(Info))
-    return nullptr;
+  bool NeedToClonePlainDIE = Info.needToKeepInPlainDwarf();
+  bool NeedToCloneTypeDIE =
+      (InputDieEntry->getTag() != dwarf::DW_TAG_compile_unit) &&
+      Info.needToPlaceInTypeTable();
+  std::pair<DIE *, TypeEntry *> ClonedDIE;
+
+  DIEGenerator PlainDIEGenerator(Allocator, *this);
+
+  if (NeedToClonePlainDIE)
+    // Create a cloned DIE which would be placed into the cloned version
+    // of input compile unit.
+    ClonedDIE.first = createPlainDIEandCloneAttributes(
+        InputDieEntry, PlainDIEGenerator, OutOffset, FuncAddressAdjustment,
+        VarAddressAdjustment);
+  if (NeedToCloneTypeDIE) {
+    // Create a cloned DIE which would be placed into the artificial type
+    // unit.
+    assert(ArtificialTypeUnit != nullptr);
+    DIEGenerator TypeDIEGenerator(
+        ArtificialTypeUnit->getTypePool().getThreadLocalAllocator(), *this);
+
+    ClonedDIE.second = createTypeDIEandCloneAttributes(
+        InputDieEntry, TypeDIEGenerator, ClonedParentTypeDIE,
+        ArtificialTypeUnit);
+  }
+  TypeEntry *TypeParentForChild =
+      ClonedDIE.second ? ClonedDIE.second : ClonedParentTypeDIE;
+
+  bool HasPlainChildrenToClone =
+      (ClonedDIE.first && Info.getKeepPlainChildren());
+
+  bool HasTypeChildrenToClone =
+      ((ClonedDIE.second ||
+        InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) &&
+       Info.getKeepTypeChildren());
+
+  // Recursively clone children.
+  if (HasPlainChildrenToClone || HasTypeChildrenToClone) {
+    for (const DWARFDebugInfoEntry *CurChild =
+             getFirstChildEntry(InputDieEntry);
+         CurChild && CurChild->getAbbreviationDeclarationPtr();
+         CurChild = getSiblingEntry(CurChild)) {
+      std::pair<DIE *, TypeEntry *> ClonedChild = cloneDIE(
+          CurChild, TypeParentForChild, OutOffset, FuncAddressAdjustment,
+          VarAddressAdjustment, Allocator, ArtificialTypeUnit);
+
+      if (ClonedChild.first) {
+        OutOffset =
+            ClonedChild.first->getOffset() + ClonedChild.first->getSize();
+        PlainDIEGenerator.addChild(ClonedChild.first);
+      }
+    }
+    assert(ClonedDIE.first == nullptr ||
+           HasPlainChildrenToClone == ClonedDIE.first->hasChildren());
+
+    // Account for the end of children marker.
+    if (HasPlainChildrenToClone)
+      OutOffset += sizeof(int8_t);
+  }
+
+  // Update our size.
+  if (ClonedDIE.first != nullptr)
+    ClonedDIE.first->setSize(OutOffset - ClonedDIE.first->getOffset());
 
+  return ClonedDIE;
+}
+
+DIE *CompileUnit::createPlainDIEandCloneAttributes(
+    const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator,
+    uint64_t &OutOffset, std::optional<int64_t> &FuncAddressAdjustment,
+    std::optional<int64_t> &VarAddressAdjustment) {
+  uint32_t InputDieIdx = getDIEIndex(InputDieEntry);
+  CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx);
+  DIE *ClonedDIE = nullptr;
   bool HasLocationExpressionAddress = false;
   if (InputDieEntry->getTag() == dwarf::DW_TAG_subprogram) {
     // Get relocation adjustment value for the current function.
     FuncAddressAdjustment =
         getContaingFile().Addresses->getSubprogramRelocAdjustment(
             getDIE(InputDieEntry));
+  } else if (InputDieEntry->getTag() == dwarf::DW_TAG_label) {
+    // Get relocation adjustment value for the current label.
+    std::optional<uint64_t> lowPC =
+        dwarf::toAddress(find(InputDieEntry, dwarf::DW_AT_low_pc));
+    if (lowPC) {
+      LabelMapTy::iterator It = Labels.find(*lowPC);
+      if (It != Labels.end())
+        FuncAddressAdjustment = It->second;
+    }
   } else if (InputDieEntry->getTag() == dwarf::DW_TAG_variable) {
     // Get relocation adjustment value for the current variable.
     std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
@@ -1248,51 +1406,132 @@ DIE *CompileUnit::cloneDIE(const DWARFDebugInfoEntry *InputDieEntry,
       VarAddressAdjustment = *LocExprAddrAndRelocAdjustment.second;
   }
 
-  DIEGenerator DIEGenerator(Allocator, *this);
-  DIE *ClonedDIE = DIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset);
+  ClonedDIE = PlainDIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset);
+
+  // Offset to the DIE would be used after output DIE tree is deleted.
+  // Thus we need to remember DIE offset separately.
   rememberDieOutOffset(InputDieIdx, OutOffset);
 
   // Clone Attributes.
-  DIEAttributeCloner AttributesCloner(
-      ClonedDIE, *this, InputDieEntry, DIEGenerator, FuncAddressAdjustment,
-      VarAddressAdjustment, HasLocationExpressionAddress);
+  DIEAttributeCloner AttributesCloner(ClonedDIE, *this, this, InputDieEntry,
+                                      PlainDIEGenerator, FuncAddressAdjustment,
+                                      VarAddressAdjustment,
+                                      HasLocationExpressionAddress);
   AttributesCloner.clone();
 
   // Remember accelerator info.
-  rememberAcceleratorEntries(InputDieEntry, OutOffset,
-                             AttributesCloner.AttrInfo);
+  AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this, this);
+  AccelRecordsSaver.save(InputDieEntry, ClonedDIE, AttributesCloner.AttrInfo,
+                         nullptr);
 
-  bool HasChildrenToClone = Info.getKeepChildren();
-  OutOffset = AttributesCloner.finalizeAbbreviations(HasChildrenToClone);
+  OutOffset =
+      AttributesCloner.finalizeAbbreviations(Info.getKeepPlainChildren());
 
-  if (HasChildrenToClone) {
-    // Recursively clone children.
-    for (const DWARFDebugInfoEntry *CurChild =
-             getFirstChildEntry(InputDieEntry);
-         CurChild && CurChild->getAbbreviationDeclarationPtr();
-         CurChild = getSiblingEntry(CurChild)) {
-      if (DIE *ClonedChild =
-              cloneDIE(CurChild, OutOffset, FuncAddressAdjustment,
-                       VarAddressAdjustment, Allocator)) {
-        OutOffset = ClonedChild->getOffset() + ClonedChild->getSize();
-        DIEGenerator.addChild(ClonedChild);
-      }
+  return ClonedDIE;
+}
+
+/// Allocates output DIE for the specified \p TypeDescriptor.
+DIE *CompileUnit::allocateTypeDie(TypeEntryBody *TypeDescriptor,
+                                  DIEGenerator &TypeDIEGenerator,
+                                  dwarf::Tag DieTag, bool IsDeclaration,
+                                  bool IsParentDeclaration) {
+  DIE *DefinitionDie = TypeDescriptor->Die;
+  // Do not allocate any new DIE if definition DIE is already met.
+  if (DefinitionDie)
+    return nullptr;
+
+  DIE *DeclarationDie = TypeDescriptor->DeclarationDie;
+  bool OldParentIsDeclaration = TypeDescriptor->ParentIsDeclaration;
+
+  if (IsDeclaration && !DeclarationDie) {
+    // Alocate declaration DIE.
+    DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+    if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie,
+                                                             NewDie))
+      return NewDie;
+  } else if (IsDeclaration && !IsParentDeclaration && OldParentIsDeclaration) {
+    // Overwrite existing declaration DIE if it's parent is also an declaration
+    // while parent of current declaration DIE is a definition.
+    if (TypeDescriptor->ParentIsDeclaration.compare_exchange_weak(
+            OldParentIsDeclaration, false)) {
+      DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+      TypeDescriptor->DeclarationDie = NewDie;
+      return NewDie;
+    }
+  } else if (!IsDeclaration && IsParentDeclaration && !DeclarationDie) {
+    // Alocate declaration DIE since parent of current DIE is marked as
+    // declaration.
+    DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+    if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie,
+                                                             NewDie))
+      return NewDie;
+  } else if (!IsDeclaration && !IsParentDeclaration) {
+    // Allocate definition DIE.
+    DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0);
+    if (TypeDescriptor->Die.compare_exchange_weak(DefinitionDie, NewDie)) {
+      TypeDescriptor->ParentIsDeclaration = false;
+      return NewDie;
     }
+  }
 
-    // Account for the end of children marker.
-    OutOffset += sizeof(int8_t);
+  return nullptr;
+}
+
+TypeEntry *CompileUnit::createTypeDIEandCloneAttributes(
+    const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator,
+    TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit) {
+  assert(ArtificialTypeUnit != nullptr);
+  uint32_t InputDieIdx = getDIEIndex(InputDieEntry);
+
+  TypeEntry *Entry = getDieTypeEntry(InputDieIdx);
+  assert(Entry != nullptr);
+  assert(ClonedParentTypeDIE != nullptr);
+  TypeEntryBody *EntryBody =
+      ArtificialTypeUnit->getTypePool().getOrCreateTypeEntryBody(
+          Entry, ClonedParentTypeDIE);
+  assert(EntryBody);
+
+  bool IsDeclaration =
+      dwarf::toUnsigned(find(InputDieEntry, dwarf::DW_AT_declaration), 0);
+
+  bool ParentIsDeclaration = false;
+  if (std::optional<uint32_t> ParentIdx = InputDieEntry->getParentIdx())
+    ParentIsDeclaration =
+        dwarf::toUnsigned(find(*ParentIdx, dwarf::DW_AT_declaration), 0);
+
+  DIE *OutDIE =
+      allocateTypeDie(EntryBody, TypeDIEGenerator, InputDieEntry->getTag(),
+                      IsDeclaration, ParentIsDeclaration);
+
+  if (OutDIE != nullptr) {
+    assert(ArtificialTypeUnit != nullptr);
+    ArtificialTypeUnit->getSectionDescriptor(DebugSectionKind::DebugInfo);
+
+    DIEAttributeCloner AttributesCloner(OutDIE, *this, ArtificialTypeUnit,
+                                        InputDieEntry, TypeDIEGenerator,
+                                        std::nullopt, std::nullopt, false);
+    AttributesCloner.clone();
+
+    // Remember accelerator info.
+    AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this,
+                                              ArtificialTypeUnit);
+    AccelRecordsSaver.save(InputDieEntry, OutDIE, AttributesCloner.AttrInfo,
+                           Entry);
+
+    // if AttributesCloner.getOutOffset() == 0 then we need to add
+    // 1 to avoid assertion for zero size. We will subtract it back later.
+    OutDIE->setSize(AttributesCloner.getOutOffset() + 1);
   }
 
-  // Update our size.
-  ClonedDIE->setSize(OutOffset - ClonedDIE->getOffset());
-  return ClonedDIE;
+  return Entry;
 }
 
 Error CompileUnit::cloneAndEmitLineTable(Triple &TargetTriple) {
   const DWARFDebugLine::LineTable *InputLineTable =
       getContaingFile().Dwarf->getLineTableForUnit(&getOrigUnit());
   if (InputLineTable == nullptr) {
-    warn("cann't load line table.");
+    if (getOrigUnit().getUnitDIE().find(dwarf::DW_AT_stmt_list))
+      warn("cann't load line table.");
     return Error::success();
   }
 
@@ -1413,230 +1652,228 @@ void CompileUnit::insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() {
-  llvm::errs() << "{\n";
+  llvm::errs() << "{";
   llvm::errs() << "  Placement: ";
   switch (getPlacement()) {
   case NotSet:
-    llvm::errs() << "NotSet\n";
+    llvm::errs() << "NotSet";
     break;
   case TypeTable:
-    llvm::errs() << "TypeTable\n";
+    llvm::errs() << "TypeTable";
     break;
   case PlainDwarf:
-    llvm::errs() << "PlainDwarf\n";
+    llvm::errs() << "PlainDwarf";
     break;
   case Both:
-    llvm::errs() << "Both\n";
-    break;
-  case Parent:
-    llvm::errs() << "Parent\n";
+    llvm::errs() << "Both";
     break;
   }
 
   llvm::errs() << "  Keep: " << getKeep();
-  llvm::errs() << "  KeepChildren: " << getKeepChildren();
-  llvm::errs() << "  ReferrencedBy: " << getReferrencedBy();
+  llvm::errs() << "  KeepPlainChildren: " << getKeepPlainChildren();
+  llvm::errs() << "  KeepTypeChildren: " << getKeepTypeChildren();
   llvm::errs() << "  IsInMouduleScope: " << getIsInMouduleScope();
   llvm::errs() << "  IsInFunctionScope: " << getIsInFunctionScope();
+  llvm::errs() << "  IsInAnonNamespaceScope: " << getIsInAnonNamespaceScope();
+  llvm::errs() << "  ODRAvailable: " << getODRAvailable();
+  llvm::errs() << "  TrackLiveness: " << getTrackLiveness();
   llvm::errs() << "}\n";
 }
 #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 
-static uint32_t hashFullyQualifiedName(CompileUnit *InputCU, DWARFDie &InputDIE,
-                                       int ChildRecurseDepth = 0) {
-  const char *Name = nullptr;
-  CompileUnit *CU = InputCU;
-  std::optional<DWARFFormValue> RefVal;
+std::optional<std::pair<StringRef, StringRef>>
+CompileUnit::getDirAndFilenameFromLineTable(
+    const DWARFFormValue &FileIdxValue) {
+  uint64_t FileIdx;
+  if (std::optional<uint64_t> Val = FileIdxValue.getAsUnsignedConstant())
+    FileIdx = *Val;
+  else if (std::optional<int64_t> Val = FileIdxValue.getAsSignedConstant())
+    FileIdx = *Val;
+  else if (std::optional<uint64_t> Val = FileIdxValue.getAsSectionOffset())
+    FileIdx = *Val;
+  else
+    return std::nullopt;
 
-  // Usually name`s depth does not exceed 3. Set maximal depth
-  // to 1000 here, to avoid infinite loop in case incorrect input
-  // DWARF.
-  size_t MaxNameDepth = 1000;
-  size_t CurNameDepth = 0;
+  return getDirAndFilenameFromLineTable(FileIdx);
+}
 
-  while (CurNameDepth++ < MaxNameDepth) {
-    if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName))
-      Name = CurrentName;
+static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) {
+  // Debug info can contain paths from any OS, not necessarily
+  // an OS we're currently running on. Moreover 
diff erent compilation units can
+  // be compiled on 
diff erent operating systems and linked together later.
+  return sys::path::is_absolute(Path, sys::path::Style::posix) ||
+         sys::path::is_absolute(Path, sys::path::Style::windows);
+}
 
-    if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) &&
-        !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin)))
-      break;
+std::optional<std::pair<StringRef, StringRef>>
+CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) {
+  FileNamesCache::iterator FileData = FileNames.find(FileIdx);
+  if (FileData != FileNames.end())
+    return std::make_pair(StringRef(FileData->second.first),
+                          StringRef(FileData->second.second));
 
-    if (!RefVal->isFormClass(DWARFFormValue::FC_Reference))
-      break;
+  if (const DWARFDebugLine::LineTable *LineTable =
+          getOrigUnit().getContext().getLineTableForUnit(&getOrigUnit())) {
+    if (LineTable->hasFileAtIndex(FileIdx)) {
 
-    std::optional<std::pair<CompileUnit *, uint32_t>> RefDie =
-        CU->resolveDIEReference(*RefVal, ResolveInterCUReferencesMode::Resolve);
-    if (!RefDie)
-      break;
+      const llvm::DWARFDebugLine::FileNameEntry &Entry =
+          LineTable->Prologue.getFileNameEntry(FileIdx);
+
+      Expected<const char *> Name = Entry.Name.getAsCString();
+      if (!Name) {
+        warn(Name.takeError());
+        return std::nullopt;
+      }
+
+      std::string FileName = *Name;
+      if (isPathAbsoluteOnWindowsOrPosix(FileName)) {
+        FileNamesCache::iterator FileData =
+            FileNames
+                .insert(std::make_pair(
+                    FileIdx,
+                    std::make_pair(std::string(""), std::move(FileName))))
+                .first;
+        return std::make_pair(StringRef(FileData->second.first),
+                              StringRef(FileData->second.second));
+      }
+
+      SmallString<256> FilePath;
+      StringRef IncludeDir;
+      // Be defensive about the contents of Entry.
+      if (getVersion() >= 5) {
+        // DirIdx 0 is the compilation directory, so don't include it for
+        // relative names.
+        if ((Entry.DirIdx != 0) &&
+            Entry.DirIdx < LineTable->Prologue.IncludeDirectories.size()) {
+          Expected<const char *> DirName =
+              LineTable->Prologue.IncludeDirectories[Entry.DirIdx]
+                  .getAsCString();
+          if (DirName)
+            IncludeDir = *DirName;
+          else {
+            warn(DirName.takeError());
+            return std::nullopt;
+          }
+        }
+      } else {
+        if (0 < Entry.DirIdx &&
+            Entry.DirIdx <= LineTable->Prologue.IncludeDirectories.size()) {
+          Expected<const char *> DirName =
+              LineTable->Prologue.IncludeDirectories[Entry.DirIdx - 1]
+                  .getAsCString();
+          if (DirName)
+            IncludeDir = *DirName;
+          else {
+            warn(DirName.takeError());
+            return std::nullopt;
+          }
+        }
+      }
+
+      StringRef CompDir = getOrigUnit().getCompilationDir();
+
+      if (!CompDir.empty() && !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) {
+        sys::path::append(FilePath, sys::path::Style::native, CompDir);
+      }
 
-    assert(RefDie->second != 0);
+      sys::path::append(FilePath, sys::path::Style::native, IncludeDir);
 
-    CU = RefDie->first;
-    InputDIE = RefDie->first->getDIEAtIndex(RefDie->second);
+      FileNamesCache::iterator FileData =
+          FileNames
+              .insert(
+                  std::make_pair(FileIdx, std::make_pair(std::string(FilePath),
+                                                         std::move(FileName))))
+              .first;
+      return std::make_pair(StringRef(FileData->second.first),
+                            StringRef(FileData->second.second));
+    }
   }
 
-  if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace)
-    Name = "(anonymous namespace)";
+  return std::nullopt;
+}
+
+#define MAX_REFERENCIES_DEPTH 1000
+UnitEntryPairTy UnitEntryPairTy::getNamespaceOrigin() {
+  UnitEntryPairTy CUDiePair(*this);
+  std::optional<UnitEntryPairTy> RefDiePair;
+  int refDepth = 0;
+  do {
+    RefDiePair = CUDiePair.CU->resolveDIEReference(
+        CUDiePair.DieEntry, dwarf::DW_AT_extension,
+        ResolveInterCUReferencesMode::Resolve);
+    if (!RefDiePair || !RefDiePair->DieEntry)
+      return CUDiePair;
+
+    CUDiePair = *RefDiePair;
+  } while (refDepth++ < MAX_REFERENCIES_DEPTH);
+
+  return CUDiePair;
+}
 
-  DWARFDie ParentDie = InputDIE.getParent();
-  if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit)
-    return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::"));
+std::optional<UnitEntryPairTy> UnitEntryPairTy::getParent() {
+  if (std::optional<uint32_t> ParentIdx = DieEntry->getParentIdx())
+    return UnitEntryPairTy{CU, CU->getDebugInfoEntry(*ParentIdx)};
 
-  return djbHash(
-      (Name ? Name : ""),
-      djbHash((Name ? "::" : ""),
-              hashFullyQualifiedName(CU, ParentDie, ++ChildRecurseDepth)));
+  return std::nullopt;
 }
 
-void CompileUnit::rememberAcceleratorEntries(
-    const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
-    AttributesInfo &AttrInfo) {
-  if (GlobalData.getOptions().AccelTables.empty())
-    return;
+CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(CompileUnit *U)
+    : Ptr(U) {
+  assert(U != nullptr);
+}
 
-  DWARFDie InputDIE = getDIE(InputDieEntry);
-
-  // Look for short name recursively if short name is not known yet.
-  if (AttrInfo.Name == nullptr)
-    if (const char *ShortName = InputDIE.getShortName())
-      AttrInfo.Name = getGlobalData().getStringPool().insert(ShortName).first;
-
-  switch (InputDieEntry->getTag()) {
-  case dwarf::DW_TAG_array_type:
-  case dwarf::DW_TAG_class_type:
-  case dwarf::DW_TAG_enumeration_type:
-  case dwarf::DW_TAG_pointer_type:
-  case dwarf::DW_TAG_reference_type:
-  case dwarf::DW_TAG_string_type:
-  case dwarf::DW_TAG_structure_type:
-  case dwarf::DW_TAG_subroutine_type:
-  case dwarf::DW_TAG_typedef:
-  case dwarf::DW_TAG_union_type:
-  case dwarf::DW_TAG_ptr_to_member_type:
-  case dwarf::DW_TAG_set_type:
-  case dwarf::DW_TAG_subrange_type:
-  case dwarf::DW_TAG_base_type:
-  case dwarf::DW_TAG_const_type:
-  case dwarf::DW_TAG_constant:
-  case dwarf::DW_TAG_file_type:
-  case dwarf::DW_TAG_namelist:
-  case dwarf::DW_TAG_packed_type:
-  case dwarf::DW_TAG_volatile_type:
-  case dwarf::DW_TAG_restrict_type:
-  case dwarf::DW_TAG_atomic_type:
-  case dwarf::DW_TAG_interface_type:
-  case dwarf::DW_TAG_unspecified_type:
-  case dwarf::DW_TAG_shared_type:
-  case dwarf::DW_TAG_immutable_type:
-  case dwarf::DW_TAG_rvalue_reference_type: {
-    if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr &&
-        !AttrInfo.Name->getKey().empty()) {
-      uint32_t Hash = hashFullyQualifiedName(this, InputDIE);
-
-      uint64_t RuntimeLang =
-          dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
-              .value_or(0);
-
-      bool ObjCClassIsImplementation =
-          (RuntimeLang == dwarf::DW_LANG_ObjC ||
-           RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
-          dwarf::toUnsigned(
-              InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
-              .value_or(0);
-
-      rememberTypeForAccelerators(AttrInfo.Name, OutOffset,
-                                  InputDieEntry->getTag(), Hash,
-                                  ObjCClassIsImplementation);
-    }
-  } break;
-  case dwarf::DW_TAG_namespace: {
-    if (AttrInfo.Name == nullptr)
-      AttrInfo.Name =
-          getGlobalData().getStringPool().insert("(anonymous namespace)").first;
-
-    rememberNamespaceForAccelerators(AttrInfo.Name, OutOffset,
-                                     InputDieEntry->getTag());
-  } break;
-  case dwarf::DW_TAG_imported_declaration: {
-    if (AttrInfo.Name != nullptr)
-      rememberNamespaceForAccelerators(AttrInfo.Name, OutOffset,
-                                       InputDieEntry->getTag());
-  } break;
-  case dwarf::DW_TAG_compile_unit:
-  case dwarf::DW_TAG_lexical_block: {
-    // Nothing to do.
-  } break;
-  default:
-    if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) {
-      if (AttrInfo.Name != nullptr)
-        rememberNameForAccelerators(
-            AttrInfo.Name, OutOffset, InputDieEntry->getTag(),
-            InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine);
-
-      // Look for mangled name recursively if mangled name is not known yet.
-      if (AttrInfo.MangledName == nullptr)
-        if (const char *LinkageName = InputDIE.getLinkageName())
-          AttrInfo.MangledName =
-              getGlobalData().getStringPool().insert(LinkageName).first;
-
-      if (AttrInfo.MangledName != nullptr &&
-          AttrInfo.MangledName != AttrInfo.Name)
-        rememberNameForAccelerators(
-            AttrInfo.MangledName, OutOffset, InputDieEntry->getTag(),
-            InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine);
-
-      // Strip template parameters from the short name.
-      if (AttrInfo.Name != nullptr && AttrInfo.MangledName != AttrInfo.Name &&
-          (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) {
-        if (std::optional<StringRef> Name =
-                StripTemplateParameters(AttrInfo.Name->getKey())) {
-          StringEntry *NameWithoutTemplateParams =
-              getGlobalData().getStringPool().insert(*Name).first;
-
-          rememberNameForAccelerators(NameWithoutTemplateParams, OutOffset,
-                                      InputDieEntry->getTag(), true);
-        }
-      }
+CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(TypeUnit *U) : Ptr(U) {
+  assert(U != nullptr);
+}
 
-      if (AttrInfo.Name)
-        rememberObjCAccelerator(InputDieEntry, OutOffset, AttrInfo);
-    }
-    break;
-  }
+DwarfUnit *CompileUnit::OutputUnitVariantPtr::operator->() {
+  if (isCompileUnit())
+    return getAsCompileUnit();
+  else
+    return getAsTypeUnit();
 }
 
-void CompileUnit::rememberObjCAccelerator(
-    const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
-    AttributesInfo &AttrInfo) {
-  std::optional<ObjCSelectorNames> Names =
-      getObjCNamesIfSelector(AttrInfo.Name->getKey());
-  if (!Names)
-    return;
+bool CompileUnit::OutputUnitVariantPtr::isCompileUnit() {
+  return Ptr.is<CompileUnit *>();
+}
 
-  StringEntry *Selector =
-      getGlobalData().getStringPool().insert(Names->Selector).first;
-  rememberNameForAccelerators(Selector, OutOffset, InputDieEntry->getTag(),
-                              true);
-  StringEntry *ClassName =
-      getGlobalData().getStringPool().insert(Names->ClassName).first;
-  rememberObjCNameForAccelerators(ClassName, OutOffset,
-                                  InputDieEntry->getTag());
-  if (Names->ClassNameNoCategory) {
-    StringEntry *ClassNameNoCategory = getGlobalData()
-                                           .getStringPool()
-                                           .insert(*Names->ClassNameNoCategory)
-                                           .first;
-    rememberObjCNameForAccelerators(ClassNameNoCategory, OutOffset,
-                                    InputDieEntry->getTag());
-  }
-  if (Names->MethodNameNoCategory) {
-    StringEntry *MethodNameNoCategory =
-        getGlobalData()
-            .getStringPool()
-            .insert(*Names->MethodNameNoCategory)
-            .first;
-    rememberNameForAccelerators(MethodNameNoCategory, OutOffset,
-                                InputDieEntry->getTag(), true);
-  }
+bool CompileUnit::OutputUnitVariantPtr::isTypeUnit() {
+  return Ptr.is<TypeUnit *>();
+}
+
+CompileUnit *CompileUnit::OutputUnitVariantPtr::getAsCompileUnit() {
+  return Ptr.get<CompileUnit *>();
+}
+
+TypeUnit *CompileUnit::OutputUnitVariantPtr::getAsTypeUnit() {
+  return Ptr.get<TypeUnit *>();
+}
+
+bool CompileUnit::resolveDependenciesAndMarkLiveness(
+    bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
+  if (!Dependencies.get())
+    Dependencies.reset(new DependencyTracker(*this));
+
+  return Dependencies->resolveDependenciesAndMarkLiveness(
+      InterCUProcessingStarted, HasNewInterconnectedCUs);
+}
+
+bool CompileUnit::updateDependenciesCompleteness() {
+  assert(Dependencies.get());
+
+  return Dependencies.get()->updateDependenciesCompleteness();
+}
+
+void CompileUnit::verifyDependencies() {
+  assert(Dependencies.get());
+
+  Dependencies.get()->verifyKeepChain();
+}
+
+ArrayRef<dwarf::Attribute> llvm::dwarflinker_parallel::getODRAttributes() {
+  static dwarf::Attribute ODRAttributes[] = {
+      dwarf::DW_AT_type, dwarf::DW_AT_specification,
+      dwarf::DW_AT_abstract_origin, dwarf::DW_AT_import};
+
+  return ODRAttributes;
 }

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
index 54666f684f3a3b0..39e010fd632393d 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
@@ -10,7 +10,6 @@
 #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
 
 #include "DWARFLinkerUnit.h"
-#include "IndexedValuesMap.h"
 #include "llvm/DWARFLinkerParallel/DWARFFile.h"
 #include <optional>
 
@@ -20,6 +19,26 @@ namespace dwarflinker_parallel {
 using OffsetToUnitTy = function_ref<CompileUnit *(uint64_t Offset)>;
 
 struct AttributesInfo;
+class SyntheticTypeNameBuilder;
+class DIEGenerator;
+class TypeUnit;
+class DependencyTracker;
+
+class CompileUnit;
+
+/// This is a helper structure which keeps a debug info entry
+/// with it's containing compilation unit.
+struct UnitEntryPairTy {
+  UnitEntryPairTy() = default;
+  UnitEntryPairTy(CompileUnit *CU, const DWARFDebugInfoEntry *DieEntry)
+      : CU(CU), DieEntry(DieEntry) {}
+
+  CompileUnit *CU = nullptr;
+  const DWARFDebugInfoEntry *DieEntry = nullptr;
+
+  UnitEntryPairTy getNamespaceOrigin();
+  std::optional<UnitEntryPairTy> getParent();
+};
 
 enum ResolveInterCUReferencesMode : bool {
   Resolve = true,
@@ -42,6 +61,13 @@ class CompileUnit : public DwarfUnit {
     /// discovered, type names are assigned if ODR is requested).
     LivenessAnalysisDone,
 
+    /// Check if dependencies have incompatible placement.
+    /// If that is the case modify placement to be compatible.
+    UpdateDependenciesCompleteness,
+
+    /// Type names assigned to DIEs.
+    TypeNamesAssigned,
+
     /// Output DWARF is generated.
     Cloned,
 
@@ -50,38 +76,20 @@ class CompileUnit : public DwarfUnit {
 
     /// Resources(Input DWARF, Output DWARF tree) are released.
     Cleaned,
+
+    /// Compile Unit should be skipped
+    Skipped
   };
 
   CompileUnit(LinkingGlobalData &GlobalData, unsigned ID,
               StringRef ClangModuleName, DWARFFile &File,
               OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format,
-              llvm::endianness Endianess)
-      : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
-        getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded) {
-    UnitName = File.FileName;
-    setOutputFormat(Format, Endianess);
-  }
+              llvm::endianness Endianess);
 
   CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, unsigned ID,
               StringRef ClangModuleName, DWARFFile &File,
               OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format,
-              llvm::endianness Endianess)
-      : DwarfUnit(GlobalData, ID, ClangModuleName), File(File),
-        OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset),
-        Stage(Stage::CreatedNotLoaded) {
-    DWARFDie CUDie = OrigUnit.getUnitDIE();
-    if (!CUDie)
-      return;
-
-    setOutputFormat(Format, Endianess);
-
-    Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0);
-    if (const char *CUName = CUDie.getName(DINameKind::ShortName))
-      UnitName = CUName;
-    else
-      UnitName = File.FileName;
-    SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
-  }
+              llvm::endianness Endianess);
 
   /// Returns stage of overall processing.
   Stage getStage() const { return Stage; }
@@ -114,7 +122,7 @@ class CompileUnit : public DwarfUnit {
 
   /// Navigate DWARF tree and set die properties.
   void analyzeDWARFStructure() {
-    analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false, false);
+    analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false);
   }
 
   /// Cleanup unneeded resources after compile unit is cloned.
@@ -124,25 +132,34 @@ class CompileUnit : public DwarfUnit {
   /// This method copies output offsets for referenced DIEs into DIEs patches.
   void updateDieRefPatchesWithClonedOffsets();
 
+  /// Search for subprograms and variables referencing live code and discover
+  /// dependend DIEs. Mark live DIEs, set placement for DIEs.
+  bool resolveDependenciesAndMarkLiveness(
+      bool InterCUProcessingStarted,
+      std::atomic<bool> &HasNewInterconnectedCUs);
+
+  /// Check dependend DIEs for incompatible placement.
+  /// Make placement to be consistent.
+  bool updateDependenciesCompleteness();
+
+  /// Check DIEs to have a consistent marking(keep marking, placement marking).
+  void verifyDependencies();
+
+  /// Search for type entries and assign names.
+  Error assignTypeNames(TypePool &TypePoolRef);
+
   /// Kinds of placement for the output die.
   enum DieOutputPlacement : uint8_t {
     NotSet = 0,
 
     /// Corresponding DIE goes to the type table only.
-    /// NOTE: Not used yet.
     TypeTable = 1,
 
     /// Corresponding DIE goes to the plain dwarf only.
     PlainDwarf = 2,
 
     /// Corresponding DIE goes to type table and to plain dwarf.
-    /// NOTE: Not used yet.
     Both = 3,
-
-    /// Corresponding DIE needs to examine parent to determine
-    /// the point of placement.
-    /// NOTE: Not used yet.
-    Parent = 4
   };
 
   /// Information gathered about source DIEs.
@@ -204,10 +221,10 @@ class CompileUnit : public DwarfUnit {
     SINGLE_FLAG_METHODS_SET(Keep, 0x08)
 
     /// DIE has children which are part of the linked output.
-    SINGLE_FLAG_METHODS_SET(KeepChildren, 0x10)
+    SINGLE_FLAG_METHODS_SET(KeepPlainChildren, 0x10)
 
-    /// DIE is referenced by other DIE.
-    SINGLE_FLAG_METHODS_SET(ReferrencedBy, 0x20)
+    /// DIE has children which are part of the type table.
+    SINGLE_FLAG_METHODS_SET(KeepTypeChildren, 0x20)
 
     /// DIE is in module scope.
     SINGLE_FLAG_METHODS_SET(IsInMouduleScope, 0x40)
@@ -215,6 +232,18 @@ class CompileUnit : public DwarfUnit {
     /// DIE is in function scope.
     SINGLE_FLAG_METHODS_SET(IsInFunctionScope, 0x80)
 
+    /// DIE is in anonymous namespace scope.
+    SINGLE_FLAG_METHODS_SET(IsInAnonNamespaceScope, 0x100)
+
+    /// DIE is available for ODR type deduplication.
+    SINGLE_FLAG_METHODS_SET(ODRAvailable, 0x200)
+
+    /// Track liveness for the DIE.
+    SINGLE_FLAG_METHODS_SET(TrackLiveness, 0x400)
+
+    /// Track liveness for the DIE.
+    SINGLE_FLAG_METHODS_SET(HasAnAddress, 0x800)
+
     void unsetFlagsWhichSetDuringLiveAnalysis() {
       auto InputData = Flags.load();
       while (!Flags.compare_exchange_weak(
@@ -228,6 +257,18 @@ class CompileUnit : public DwarfUnit {
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
     LLVM_DUMP_METHOD void dump();
 #endif
+
+    bool needToPlaceInTypeTable() const {
+      return (getKeep() && (getPlacement() == CompileUnit::TypeTable ||
+                            getPlacement() == CompileUnit::Both)) ||
+             getKeepTypeChildren();
+    }
+
+    bool needToKeepInPlainDwarf() const {
+      return (getKeep() && (getPlacement() == CompileUnit::PlainDwarf ||
+                            getPlacement() == CompileUnit::Both)) ||
+             getKeepPlainChildren();
+    }
   };
 
   /// \defgroup Group of functions returning DIE info.
@@ -273,6 +314,29 @@ class CompileUnit : public DwarfUnit {
         ->load();
   }
 
+  /// \p Idx index of the DIE.
+  /// \returns type entry.
+  TypeEntry *getDieTypeEntry(uint32_t Idx) {
+    return reinterpret_cast<std::atomic<TypeEntry *> *>(&TypeEntries[Idx])
+        ->load();
+  }
+
+  /// \p InputDieEntry debug info entry.
+  /// \returns DieInfo descriptor.
+  uint64_t getDieOutOffset(const DWARFDebugInfoEntry *InputDieEntry) {
+    return reinterpret_cast<std::atomic<uint64_t> *>(
+               &OutDieOffsetArray[getOrigUnit().getDIEIndex(InputDieEntry)])
+        ->load();
+  }
+
+  /// \p InputDieEntry debug info entry.
+  /// \returns type entry.
+  TypeEntry *getDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry) {
+    return reinterpret_cast<std::atomic<TypeEntry *> *>(
+               &TypeEntries[getOrigUnit().getDIEIndex(InputDieEntry)])
+        ->load();
+  }
+
   /// \p Idx index of the DIE.
   /// \returns DieInfo descriptor.
   void rememberDieOutOffset(uint32_t Idx, uint64_t Offset) {
@@ -280,6 +344,22 @@ class CompileUnit : public DwarfUnit {
         ->store(Offset);
   }
 
+  /// \p Idx index of the DIE.
+  /// \p Type entry.
+  void setDieTypeEntry(uint32_t Idx, TypeEntry *Entry) {
+    reinterpret_cast<std::atomic<TypeEntry *> *>(&TypeEntries[Idx])
+        ->store(Entry);
+  }
+
+  /// \p InputDieEntry debug info entry.
+  /// \p Type entry.
+  void setDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry,
+                       TypeEntry *Entry) {
+    reinterpret_cast<std::atomic<TypeEntry *> *>(
+        &TypeEntries[getOrigUnit().getDIEIndex(InputDieEntry)])
+        ->store(Entry);
+  }
+
   /// @}
 
   /// Returns value of DW_AT_low_pc attribute.
@@ -299,9 +379,15 @@ class CompileUnit : public DwarfUnit {
   /// RefValue. The resulting DIE might be in another CompileUnit.
   /// \returns referenced die and corresponding compilation unit.
   ///          compilation unit is null if reference could not be resolved.
-  std::optional<std::pair<CompileUnit *, uint32_t>>
+  std::optional<UnitEntryPairTy>
   resolveDIEReference(const DWARFFormValue &RefValue,
                       ResolveInterCUReferencesMode CanResolveInterCUReferences);
+
+  std::optional<UnitEntryPairTy>
+  resolveDIEReference(const DWARFDebugInfoEntry *DieEntry,
+                      dwarf::Attribute Attr,
+                      ResolveInterCUReferencesMode CanResolveInterCUReferences);
+
   /// @}
 
   /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying
@@ -312,7 +398,8 @@ class CompileUnit : public DwarfUnit {
   const RangesTy &getFunctionRanges() const { return Ranges; }
 
   /// Clone and emit this compilation unit.
-  Error cloneAndEmit(std::optional<Triple> TargetTriple);
+  Error cloneAndEmit(std::optional<Triple> TargetTriple,
+                     TypeUnit *ArtificialTypeUnit);
 
   /// Clone and emit debug locations(.debug_loc/.debug_loclists).
   Error cloneAndEmitDebugLocations();
@@ -324,10 +411,12 @@ class CompileUnit : public DwarfUnit {
   Error cloneAndEmitDebugMacro();
 
   // Clone input DIE entry.
-  DIE *cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset,
-                std::optional<int64_t> FuncAddressAdjustment,
-                std::optional<int64_t> VarAddressAdjustment,
-                BumpPtrAllocator &Allocator);
+  std::pair<DIE *, TypeEntry *>
+  cloneDIE(const DWARFDebugInfoEntry *InputDieEntry,
+           TypeEntry *ClonedParentTypeDIE, uint64_t OutOffset,
+           std::optional<int64_t> FuncAddressAdjustment,
+           std::optional<int64_t> VarAddressAdjustment,
+           BumpPtrAllocator &Allocator, TypeUnit *ArtificialTypeUnit);
 
   // Clone and emit line table.
   Error cloneAndEmitLineTable(Triple &TargetTriple);
@@ -344,10 +433,13 @@ class CompileUnit : public DwarfUnit {
     return DebugAddrIndexMap.getValueIndex(Addr);
   }
 
-  /// Returns index(inside .debug_str_offsets) of specified string.
-  uint64_t getDebugStrIndex(const StringEntry *String) {
-    return DebugStringIndexMap.getValueIndex(String);
-  }
+  /// Returns directory and file from the line table by index.
+  std::optional<std::pair<StringRef, StringRef>>
+  getDirAndFilenameFromLineTable(const DWARFFormValue &FileIdxValue);
+
+  /// Returns directory and file from the line table by index.
+  std::optional<std::pair<StringRef, StringRef>>
+  getDirAndFilenameFromLineTable(uint64_t FileIdx);
 
   /// \defgroup Helper methods to access OrigUnit.
   ///
@@ -469,10 +561,44 @@ class CompileUnit : public DwarfUnit {
 
   /// @}
 
+  /// Save specified accelerator info \p Info.
+  void saveAcceleratorInfo(const DwarfUnit::AccelInfo &Info) {
+    AcceleratorRecords.add(Info);
+  }
+
+  /// Enumerates all units accelerator records.
+  void
+  forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) override {
+    AcceleratorRecords.forEach(Handler);
+  }
+
+  /// Output unit selector.
+  class OutputUnitVariantPtr {
+  public:
+    OutputUnitVariantPtr(CompileUnit *U);
+    OutputUnitVariantPtr(TypeUnit *U);
+
+    /// Accessor for common functionality.
+    DwarfUnit *operator->();
+
+    bool isCompileUnit();
+
+    bool isTypeUnit();
+
+    /// Returns CompileUnit if applicable.
+    CompileUnit *getAsCompileUnit();
+
+    /// Returns TypeUnit if applicable.
+    TypeUnit *getAsTypeUnit();
+
+  protected:
+    PointerUnion<CompileUnit *, TypeUnit *> Ptr;
+  };
+
 private:
   /// Navigate DWARF tree recursively and set die properties.
   void analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry,
-                                bool IsInModule, bool IsInFunction);
+                                bool IsODRUnavailableFunctionScope);
 
   struct LinkedLocationExpressionsWithOffsetPatches {
     DWARFLocationExpression Expression;
@@ -495,9 +621,6 @@ class CompileUnit : public DwarfUnit {
   /// Emit the .debug_addr section fragment for current unit.
   Error emitDebugAddrSection();
 
-  /// Emit the .debug_str_offsets section for current unit.
-  Error emitDebugStringOffsetSection();
-
   /// Emit .debug_aranges.
   void emitAranges(AddressRanges &LinkedFunctionRanges);
 
@@ -521,13 +644,25 @@ class CompileUnit : public DwarfUnit {
   void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
                           uint64_t OffsetToMacroTable, bool hasDWARFv5Header);
 
-  /// Store accelerator information for the \p InputDieEntry.
-  void rememberAcceleratorEntries(const DWARFDebugInfoEntry *InputDieEntry,
-                                  uint64_t OutOffset, AttributesInfo &AttrInfo);
+  /// Creates DIE which would be placed into the "Plain" compile unit.
+  DIE *createPlainDIEandCloneAttributes(
+      const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator,
+      uint64_t &OutOffset, std::optional<int64_t> &FuncAddressAdjustment,
+      std::optional<int64_t> &VarAddressAdjustment);
+
+  /// Creates DIE which would be placed into the "Type" compile unit.
+  TypeEntry *createTypeDIEandCloneAttributes(
+      const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator,
+      TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit);
+
+  /// Create output DIE inside specified \p TypeDescriptor.
+  DIE *allocateTypeDie(TypeEntryBody *TypeDescriptor,
+                       DIEGenerator &TypeDIEGenerator, dwarf::Tag DieTag,
+                       bool IsDeclaration, bool IsParentDeclaration);
 
-  /// Store ObjC accelerator information for the \p InputDieEntry.
-  void rememberObjCAccelerator(const DWARFDebugInfoEntry *InputDieEntry,
-                               uint64_t OutOffset, AttributesInfo &AttrInfo);
+  /// Enumerate \p DieEntry children and assign names for them.
+  Error assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry,
+                           SyntheticTypeNameBuilder &NameBuilder);
 
   /// DWARFFile containing this compile unit.
   DWARFFile &File;
@@ -535,6 +670,9 @@ class CompileUnit : public DwarfUnit {
   /// Pointer to the paired compile unit from the input DWARF.
   DWARFUnit *OrigUnit = nullptr;
 
+  /// The DW_AT_language of this unit.
+  std::optional<uint16_t> Language;
+
   /// Line table for this unit.
   const DWARFDebugLine::LineTable *LineTablePtr = nullptr;
 
@@ -547,10 +685,9 @@ class CompileUnit : public DwarfUnit {
   /// Maps an address into the index inside .debug_addr section.
   IndexedValuesMap<uint64_t> DebugAddrIndexMap;
 
-  /// Maps a string into the index inside .debug_str_offsets section.
-  IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
+  std::unique_ptr<DependencyTracker> Dependencies;
 
-  /// \defgroup Data Members accessed asinchroniously.
+  /// \defgroup Data Members accessed asinchronously.
   ///
   /// @{
   OffsetToUnitTy getUnitFromOffset;
@@ -558,6 +695,9 @@ class CompileUnit : public DwarfUnit {
   std::optional<uint64_t> LowPc;
   uint64_t HighPc = 0;
 
+  /// Flag indicating whether type de-duplication is forbidden.
+  bool NoODR = true;
+
   /// The ranges in that map are the PC ranges for functions in this unit,
   /// associated with the PC offset to apply to the addresses to get
   /// the linked address.
@@ -565,7 +705,8 @@ class CompileUnit : public DwarfUnit {
   std::mutex RangesMutex;
 
   /// The DW_AT_low_pc of each DW_TAG_label.
-  SmallDenseMap<uint64_t, uint64_t, 1> Labels;
+  using LabelMapTy = SmallDenseMap<uint64_t, uint64_t, 1>;
+  LabelMapTy Labels;
   std::mutex LabelsMutex;
 
   /// This field keeps current stage of overall compile unit processing.
@@ -574,9 +715,19 @@ class CompileUnit : public DwarfUnit {
   /// DIE info indexed by DIE index.
   SmallVector<DIEInfo> DieInfoArray;
   SmallVector<uint64_t> OutDieOffsetArray;
+  SmallVector<TypeEntry *> TypeEntries;
+
+  /// The list of accelerator records for this unit.
+  ArrayList<AccelInfo> AcceleratorRecords;
   /// @}
 };
 
+/// \returns list of attributes referencing type DIEs which might be
+/// deduplicated.
+/// Note: it does not include DW_AT_containing_type attribute to avoid
+/// infinite recursion.
+ArrayRef<dwarf::Attribute> getODRAttributes();
+
 } // end of namespace dwarflinker_parallel
 } // end namespace llvm
 

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
index 78d0b5468d0495e..220739a1214c690 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
 #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H
 
+#include "TypePool.h"
 #include "llvm/DWARFLinkerParallel/DWARFLinker.h"
 #include "llvm/DWARFLinkerParallel/StringPool.h"
 #include "llvm/Support/PerThreadBumpPtrAllocator.h"

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
index a755d540aef99e1..c49b9ef0cdf989d 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
@@ -9,6 +9,8 @@
 #include "DWARFLinkerImpl.h"
 #include "DIEGenerator.h"
 #include "DependencyTracker.h"
+#include "Utils.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Parallel.h"
 #include "llvm/Support/ThreadPool.h"
@@ -16,6 +18,50 @@
 namespace llvm {
 namespace dwarflinker_parallel {
 
+DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
+                                 MessageHandlerTy WarningHandler,
+                                 TranslatorFuncTy StringsTranslator)
+    : UniqueUnitID(0), DebugStrStrings(GlobalData),
+      DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {
+  GlobalData.setTranslator(StringsTranslator);
+  GlobalData.setErrorHandler(ErrorHandler);
+  GlobalData.setWarningHandler(WarningHandler);
+}
+
+DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData,
+                                          DWARFFile &File,
+                                          StringMap<uint64_t> &ClangModules,
+                                          std::atomic<size_t> &UniqueUnitID,
+                                          std::optional<Triple> TargetTriple)
+    : OutputSections(GlobalData), InputDWARFFile(File),
+      ClangModules(ClangModules), TargetTriple(TargetTriple),
+      UniqueUnitID(UniqueUnitID) {
+
+  if (File.Dwarf) {
+    if (!File.Dwarf->compile_units().empty())
+      CompileUnits.reserve(File.Dwarf->getNumCompileUnits());
+
+    // Set context format&endianness based on the input file.
+    Format.Version = File.Dwarf->getMaxVersion();
+    Format.AddrSize = File.Dwarf->getCUAddrSize();
+    Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little
+                                              : llvm::endianness::big;
+  }
+}
+
+DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit(
+    DWARFFile &File, std::unique_ptr<CompileUnit> Unit)
+    : File(File), Unit(std::move(Unit)) {}
+
+DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit(
+    LinkContext::RefModuleUnit &&Other)
+    : File(Other.File), Unit(std::move(Other.Unit)) {}
+
+void DWARFLinkerImpl::LinkContext::addModulesCompileUnit(
+    LinkContext::RefModuleUnit &&Unit) {
+  ModulesCompileUnits.emplace_back(std::move(Unit));
+}
+
 Error DWARFLinkerImpl::createEmitter(const Triple &TheTriple,
                                      OutputFileType FileType,
                                      raw_pwrite_stream &OutFile) {
@@ -55,6 +101,10 @@ void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader,
   }
 }
 
+void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) {
+  ObjectContexts.reserve(ObjFilesNum);
+}
+
 Error DWARFLinkerImpl::link() {
   // reset compile unit unique ID counter.
   UniqueUnitID = 0;
@@ -71,6 +121,7 @@ Error DWARFLinkerImpl::link() {
                            ? llvm::endianness::little
                            : llvm::endianness::big;
   }
+  std::optional<uint16_t> Language;
 
   for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {
     if (Context->InputDWARFFile.Dwarf.get() == nullptr) {
@@ -101,6 +152,23 @@ Error DWARFLinkerImpl::link() {
         std::max(GlobalFormat.AddrSize, Context->getFormParams().AddrSize);
 
     Context->setOutputFormat(Context->getFormParams(), GlobalEndianness);
+
+    // FIXME: move creation of CompileUnits into the addObjectFile.
+    // This would allow to not scan for context Language and Modules state
+    // twice. And then following handling might be removed.
+    for (const std::unique_ptr<DWARFUnit> &OrigCU :
+         Context->InputDWARFFile.Dwarf->compile_units()) {
+      DWARFDie UnitDie = OrigCU.get()->getUnitDIE();
+
+      if (!Language) {
+        if (std::optional<DWARFFormValue> Val =
+                UnitDie.find(dwarf::DW_AT_language)) {
+          uint16_t LangVal = dwarf::toUnsigned(Val, 0);
+          if (isODRLanguage(LangVal))
+            Language = LangVal;
+        }
+      }
+    }
   }
 
   if (GlobalFormat.AddrSize == 0) {
@@ -113,6 +181,14 @@ Error DWARFLinkerImpl::link() {
 
   CommonSections.setOutputFormat(GlobalFormat, GlobalEndianness);
 
+  if (!GlobalData.Options.NoODR && Language.has_value()) {
+    parallel::TaskGroup TGroup;
+    TGroup.spawn([&]() {
+      ArtificialTypeUnit = std::make_unique<TypeUnit>(
+          GlobalData, UniqueUnitID++, Language, GlobalFormat, GlobalEndianness);
+    });
+  }
+
   // Set parallel options.
   if (GlobalData.getOptions().Threads == 0)
     parallel::strategy = optimal_concurrency(OverallNumberOfCU);
@@ -123,7 +199,7 @@ Error DWARFLinkerImpl::link() {
   if (GlobalData.getOptions().Threads == 1) {
     for (std::unique_ptr<LinkContext> &Context : ObjectContexts) {
       // Link object file.
-      if (Error Err = Context->link())
+      if (Error Err = Context->link(ArtificialTypeUnit.get()))
         GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);
 
       Context->InputDWARFFile.unload();
@@ -133,7 +209,7 @@ Error DWARFLinkerImpl::link() {
     for (std::unique_ptr<LinkContext> &Context : ObjectContexts)
       Pool.async([&]() {
         // Link object file.
-        if (Error Err = Context->link())
+        if (Error Err = Context->link(ArtificialTypeUnit.get()))
           GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName);
 
         Context->InputDWARFFile.unload();
@@ -142,6 +218,19 @@ Error DWARFLinkerImpl::link() {
     Pool.wait();
   }
 
+  if (ArtificialTypeUnit.get() != nullptr && !ArtificialTypeUnit->getTypePool()
+                                                  .getRoot()
+                                                  ->getValue()
+                                                  .load()
+                                                  ->Children.empty()) {
+    std::optional<Triple> OutTriple = TheDwarfEmitter.get() == nullptr
+                                          ? std::optional<Triple>(std::nullopt)
+                                          : TheDwarfEmitter->getTargetTriple();
+
+    if (Error Err = ArtificialTypeUnit.get()->finishCloningAndEmit(OutTriple))
+      return Err;
+  }
+
   // At this stage each compile units are cloned to their own set of debug
   // sections. Now, update patches, assign offsets and assemble final file
   // glueing debug tables from each compile unit.
@@ -175,6 +264,11 @@ Error DWARFLinkerImpl::validateAndUpdateOptions() {
         "set number of threads to 1 to make --verbose to work properly.", "");
   }
 
+  // Do not do types deduplication in case --update.
+  if (GlobalData.getOptions().UpdateIndexTablesOnly &&
+      !GlobalData.Options.NoODR)
+    GlobalData.Options.NoODR = true;
+
   return Error::success();
 }
 
@@ -369,7 +463,7 @@ Error DWARFLinkerImpl::LinkContext::loadClangModule(
   return Error::success();
 }
 
-Error DWARFLinkerImpl::LinkContext::link() {
+Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) {
   InterCUProcessingStarted = false;
   if (!InputDWARFFile.Dwarf)
     return Error::success();
@@ -380,7 +474,7 @@ Error DWARFLinkerImpl::LinkContext::link() {
 
   // Link modules compile units first.
   parallelForEach(ModulesCompileUnits, [&](RefModuleUnit &RefModule) {
-    linkSingleCompileUnit(*RefModule.Unit);
+    linkSingleCompileUnit(*RefModule.Unit, ArtificialTypeUnit);
   });
 
   // Check for live relocations. If there is no any live relocation then we
@@ -420,43 +514,78 @@ Error DWARFLinkerImpl::LinkContext::link() {
     // Link self-sufficient compile units and discover inter-connected compile
     // units.
     parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
-      linkSingleCompileUnit(*CU);
+      linkSingleCompileUnit(*CU, ArtificialTypeUnit);
     });
 
     // Link all inter-connected units.
     if (HasNewInterconnectedCUs) {
       InterCUProcessingStarted = true;
 
-      do {
-        HasNewInterconnectedCUs = false;
-
-        // Load inter-connected units.
-        parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
-          if (CU->isInterconnectedCU()) {
-            CU->maybeResetToLoadedStage();
-            linkSingleCompileUnit(*CU, CompileUnit::Stage::Loaded);
-          }
-        });
+      if (Error Err = finiteLoop([&]() -> Expected<bool> {
+            HasNewInterconnectedCUs = false;
+
+            // Load inter-connected units.
+            parallelForEach(
+                CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+                  if (CU->isInterconnectedCU()) {
+                    CU->maybeResetToLoadedStage();
+                    linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+                                          CompileUnit::Stage::Loaded);
+                  }
+                });
+
+            // Do liveness analysis for inter-connected units.
+            parallelForEach(CompileUnits,
+                            [&](std::unique_ptr<CompileUnit> &CU) {
+                              linkSingleCompileUnit(
+                                  *CU, ArtificialTypeUnit,
+                                  CompileUnit::Stage::LivenessAnalysisDone);
+                            });
+
+            return HasNewInterconnectedCUs.load();
+          }))
+        return Err;
+
+      // Update dependencies.
+      if (Error Err = finiteLoop([&]() -> Expected<bool> {
+            HasNewGlobalDependency = false;
+            parallelForEach(
+                CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+                  linkSingleCompileUnit(
+                      *CU, ArtificialTypeUnit,
+                      CompileUnit::Stage::UpdateDependenciesCompleteness);
+                });
+            return HasNewGlobalDependency.load();
+          }))
+        return Err;
+      parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+        if (CU->isInterconnectedCU() &&
+            CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone)
+          CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness);
+      });
 
-        // Do liveness analysis for inter-connected units.
-        parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
-          linkSingleCompileUnit(*CU, CompileUnit::Stage::LivenessAnalysisDone);
-        });
-      } while (HasNewInterconnectedCUs);
+      // Assign type names.
+      parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
+        linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+                              CompileUnit::Stage::TypeNamesAssigned);
+      });
 
       // Clone inter-connected units.
       parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
-        linkSingleCompileUnit(*CU, CompileUnit::Stage::Cloned);
+        linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+                              CompileUnit::Stage::Cloned);
       });
 
       // Update patches for inter-connected units.
       parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
-        linkSingleCompileUnit(*CU, CompileUnit::Stage::PatchesUpdated);
+        linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+                              CompileUnit::Stage::PatchesUpdated);
       });
 
       // Release data.
       parallelForEach(CompileUnits, [&](std::unique_ptr<CompileUnit> &CU) {
-        linkSingleCompileUnit(*CU, CompileUnit::Stage::Cleaned);
+        linkSingleCompileUnit(*CU, ArtificialTypeUnit,
+                              CompileUnit::Stage::Cleaned);
       });
     }
 
@@ -483,78 +612,119 @@ Error DWARFLinkerImpl::LinkContext::link() {
 }
 
 void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit(
-    CompileUnit &CU, enum CompileUnit::Stage DoUntilStage) {
-  while (CU.getStage() < DoUntilStage) {
-    if (InterCUProcessingStarted != CU.isInterconnectedCU())
-      return;
+    CompileUnit &CU, TypeUnit *ArtificialTypeUnit,
+    enum CompileUnit::Stage DoUntilStage) {
+  if (InterCUProcessingStarted != CU.isInterconnectedCU())
+    return;
 
-    switch (CU.getStage()) {
-    case CompileUnit::Stage::CreatedNotLoaded: {
-      // Load input compilation unit DIEs.
-      // Analyze properties of DIEs.
-      if (!CU.loadInputDIEs()) {
-        // We do not need to do liveness analysis for invalud compilation unit.
-        CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);
-      } else {
-        CU.analyzeDWARFStructure();
-
-        // The registerModuleReference() condition effectively skips
-        // over fully resolved skeleton units. This second pass of
-        // registerModuleReferences doesn't do any new work, but it
-        // will collect top-level errors, which are suppressed. Module
-        // warnings were already displayed in the first iteration.
-        if (registerModuleReference(
-                CU.getOrigUnit().getUnitDIE(), nullptr,
-                [](const DWARFUnit &) {}, 0))
-          CU.setStage(CompileUnit::Stage::PatchesUpdated);
-        else
-          CU.setStage(CompileUnit::Stage::Loaded);
-      }
-    } break;
+  if (Error Err = finiteLoop([&]() -> Expected<bool> {
+        if (CU.getStage() >= DoUntilStage)
+          return false;
+
+        switch (CU.getStage()) {
+        case CompileUnit::Stage::CreatedNotLoaded: {
+          // Load input compilation unit DIEs.
+          // Analyze properties of DIEs.
+          if (!CU.loadInputDIEs()) {
+            // We do not need to do liveness analysis for invalid compilation
+            // unit.
+            CU.setStage(CompileUnit::Stage::Skipped);
+          } else {
+            CU.analyzeDWARFStructure();
+
+            // The registerModuleReference() condition effectively skips
+            // over fully resolved skeleton units. This second pass of
+            // registerModuleReferences doesn't do any new work, but it
+            // will collect top-level errors, which are suppressed. Module
+            // warnings were already displayed in the first iteration.
+            if (registerModuleReference(
+                    CU.getOrigUnit().getUnitDIE(), nullptr,
+                    [](const DWARFUnit &) {}, 0))
+              CU.setStage(CompileUnit::Stage::PatchesUpdated);
+            else
+              CU.setStage(CompileUnit::Stage::Loaded);
+          }
+        } break;
 
-    case CompileUnit::Stage::Loaded: {
-      // Mark all the DIEs that need to be present in the generated output.
-      // If ODR requested, build type names.
-      if (!DependencyTracker(*this).resolveDependenciesAndMarkLiveness(CU)) {
-        assert(HasNewInterconnectedCUs);
-        return;
-      }
+        case CompileUnit::Stage::Loaded: {
+          // Mark all the DIEs that need to be present in the generated output.
+          // If ODR requested, build type names.
+          if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted,
+                                                     HasNewInterconnectedCUs)) {
+            assert(HasNewInterconnectedCUs &&
+                   "Flag indicating new inter-connections is not set");
+            return false;
+          }
 
-      CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);
-    } break;
+          CU.setStage(CompileUnit::Stage::LivenessAnalysisDone);
+        } break;
 
-    case CompileUnit::Stage::LivenessAnalysisDone:
+        case CompileUnit::Stage::LivenessAnalysisDone: {
+          if (InterCUProcessingStarted) {
+            if (CU.updateDependenciesCompleteness())
+              HasNewGlobalDependency = true;
+            return false;
+          } else {
+            if (Error Err = finiteLoop([&]() -> Expected<bool> {
+                  return CU.updateDependenciesCompleteness();
+                }))
+              return std::move(Err);
+
+            CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness);
+          }
+        } break;
 
+        case CompileUnit::Stage::UpdateDependenciesCompleteness:
 #ifndef NDEBUG
-      DependencyTracker::verifyKeepChain(CU);
+          CU.verifyDependencies();
 #endif
 
-      // Clone input compile unit.
-      if (CU.isClangModule() || GlobalData.getOptions().UpdateIndexTablesOnly ||
-          CU.getContaingFile().Addresses->hasValidRelocs()) {
-        if (Error Err = CU.cloneAndEmit(TargetTriple))
-          CU.error(std::move(Err));
-      }
+          if (ArtificialTypeUnit) {
+            if (Error Err =
+                    CU.assignTypeNames(ArtificialTypeUnit->getTypePool()))
+              return std::move(Err);
+          }
+          CU.setStage(CompileUnit::Stage::TypeNamesAssigned);
+          break;
+
+        case CompileUnit::Stage::TypeNamesAssigned:
+          // Clone input compile unit.
+          if (CU.isClangModule() ||
+              GlobalData.getOptions().UpdateIndexTablesOnly ||
+              CU.getContaingFile().Addresses->hasValidRelocs()) {
+            if (Error Err = CU.cloneAndEmit(TargetTriple, ArtificialTypeUnit))
+              return std::move(Err);
+          }
 
-      CU.setStage(CompileUnit::Stage::Cloned);
-      break;
+          CU.setStage(CompileUnit::Stage::Cloned);
+          break;
 
-    case CompileUnit::Stage::Cloned:
-      // Update DIEs referencies.
-      CU.updateDieRefPatchesWithClonedOffsets();
-      CU.setStage(CompileUnit::Stage::PatchesUpdated);
-      break;
+        case CompileUnit::Stage::Cloned:
+          // Update DIEs referencies.
+          CU.updateDieRefPatchesWithClonedOffsets();
+          CU.setStage(CompileUnit::Stage::PatchesUpdated);
+          break;
 
-    case CompileUnit::Stage::PatchesUpdated:
-      // Cleanup resources.
-      CU.cleanupDataAfterClonning();
-      CU.setStage(CompileUnit::Stage::Cleaned);
-      break;
+        case CompileUnit::Stage::PatchesUpdated:
+          // Cleanup resources.
+          CU.cleanupDataAfterClonning();
+          CU.setStage(CompileUnit::Stage::Cleaned);
+          break;
 
-    case CompileUnit::Stage::Cleaned:
-      assert(false);
-      break;
-    }
+        case CompileUnit::Stage::Cleaned:
+          assert(false);
+          break;
+
+        case CompileUnit::Stage::Skipped:
+          // Nothing to do.
+          break;
+        }
+
+        return true;
+      })) {
+    CU.error(std::move(Err));
+    CU.cleanupDataAfterClonning();
+    CU.setStage(CompileUnit::Stage::Skipped);
   }
 }
 
@@ -716,6 +886,9 @@ void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() {
   // units into the resulting file.
   emitCommonSectionsAndWriteCompileUnitsToTheOutput();
 
+  if (ArtificialTypeUnit.get() != nullptr)
+    ArtificialTypeUnit.reset();
+
   // Write common debug sections into the resulting file.
   writeCommonSectionsToTheOutput();
 
@@ -861,47 +1034,101 @@ void DWARFLinkerImpl::forEachOutputString(
       });
     });
 
-    CU->AcceleratorRecords.forEach([&](DwarfUnit::AccelInfo &Info) {
+    CU->forEachAcceleratorRecord([&](DwarfUnit::AccelInfo &Info) {
       StringHandler(DebugStr, Info.String);
     });
   });
+
+  if (ArtificialTypeUnit.get() != nullptr) {
+    ArtificialTypeUnit->forEach([&](SectionDescriptor &OutSection) {
+      OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {
+        StringHandler(StringDestinationKind::DebugStr, Patch.String);
+      });
+
+      OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {
+        StringHandler(StringDestinationKind::DebugLineStr, Patch.String);
+      });
+
+      OutSection.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) {
+        if (Patch.Die == nullptr)
+          return;
+
+        StringHandler(StringDestinationKind::DebugStr, Patch.String);
+      });
+
+      OutSection.ListDebugTypeLineStrPatch.forEach(
+          [&](DebugTypeLineStrPatch &Patch) {
+            if (Patch.Die == nullptr)
+              return;
+
+            StringHandler(StringDestinationKind::DebugStr, Patch.String);
+          });
+    });
+  }
 }
 
 void DWARFLinkerImpl::forEachObjectSectionsSet(
     function_ref<void(OutputSections &)> SectionsSetHandler) {
-  // Handle all modules first(before regular compilation units).
+  // Handle artificial type unit first.
+  if (ArtificialTypeUnit.get() != nullptr)
+    SectionsSetHandler(*ArtificialTypeUnit);
+
+  // Then all modules(before regular compilation units).
   for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
     for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
-      SectionsSetHandler(*ModuleUnit.Unit);
+      if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)
+        SectionsSetHandler(*ModuleUnit.Unit);
 
+  // Finally all compilation units.
   for (const std::unique_ptr<LinkContext> &Context : ObjectContexts) {
     // Handle object file common sections.
     SectionsSetHandler(*Context);
 
     // Handle compilation units.
     for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
-      SectionsSetHandler(*CU);
+      if (CU->getStage() != CompileUnit::Stage::Skipped)
+        SectionsSetHandler(*CU);
   }
 }
 
+void DWARFLinkerImpl::forEachCompileAndTypeUnit(
+    function_ref<void(DwarfUnit *CU)> UnitHandler) {
+  if (ArtificialTypeUnit.get() != nullptr)
+    UnitHandler(ArtificialTypeUnit.get());
+
+  // Enumerate module units.
+  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
+    for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
+      if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)
+        UnitHandler(ModuleUnit.Unit.get());
+
+  // Enumerate compile units.
+  for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
+    for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
+      if (CU->getStage() != CompileUnit::Stage::Skipped)
+        UnitHandler(CU.get());
+}
+
 void DWARFLinkerImpl::forEachCompileUnit(
     function_ref<void(CompileUnit *CU)> UnitHandler) {
   // Enumerate module units.
   for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
     for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits)
-      UnitHandler(ModuleUnit.Unit.get());
+      if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped)
+        UnitHandler(ModuleUnit.Unit.get());
 
   // Enumerate compile units.
   for (const std::unique_ptr<LinkContext> &Context : ObjectContexts)
     for (std::unique_ptr<CompileUnit> &CU : Context->CompileUnits)
-      UnitHandler(CU.get());
+      if (CU->getStage() != CompileUnit::Stage::Skipped)
+        UnitHandler(CU.get());
 }
 
 void DWARFLinkerImpl::patchOffsetsAndSizes() {
   forEachObjectSectionsSet([&](OutputSections &SectionsSet) {
     SectionsSet.forEach([&](SectionDescriptor &OutSection) {
-      SectionsSet.applyPatches(OutSection, DebugStrStrings,
-                               DebugLineStrStrings);
+      SectionsSet.applyPatches(OutSection, DebugStrStrings, DebugLineStrStrings,
+                               ArtificialTypeUnit.get());
     });
   });
 }
@@ -1005,8 +1232,9 @@ void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) {
   AccelTable<AppleAccelTableStaticOffsetData> AppleObjC;
   AccelTable<AppleAccelTableStaticTypeData> AppleTypes;
 
-  forEachCompileUnit([&](CompileUnit *CU) {
-    CU->AcceleratorRecords.forEach([&](const DwarfUnit::AccelInfo &Info) {
+  forEachCompileAndTypeUnit([&](DwarfUnit *CU) {
+    CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {
+      uint64_t OutOffset = Info.OutOffset;
       switch (Info.Type) {
       case DwarfUnit::AccelType::None: {
         llvm_unreachable("Unknown accelerator record");
@@ -1015,25 +1243,25 @@ void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) {
         AppleNamespaces.addName(
             *DebugStrStrings.getExistingEntry(Info.String),
             CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
-                Info.OutOffset);
+                OutOffset);
       } break;
       case DwarfUnit::AccelType::Name: {
         AppleNames.addName(
             *DebugStrStrings.getExistingEntry(Info.String),
             CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
-                Info.OutOffset);
+                OutOffset);
       } break;
       case DwarfUnit::AccelType::ObjC: {
         AppleObjC.addName(
             *DebugStrStrings.getExistingEntry(Info.String),
             CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
-                Info.OutOffset);
+                OutOffset);
       } break;
       case DwarfUnit::AccelType::Type: {
         AppleTypes.addName(
             *DebugStrStrings.getExistingEntry(Info.String),
             CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset +
-                Info.OutOffset,
+                OutOffset,
             Info.Tag,
             Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation
                                          : 0,
@@ -1136,16 +1364,13 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) {
 
   unsigned Id = 0;
 
-  forEachCompileUnit([&](CompileUnit *CU) {
-    CompUnits.push_back(
-        CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)
-            .StartOffset);
-    CUidToIdx[CU->getUniqueID()] = Id++;
-
-    CU->AcceleratorRecords.forEach([&](const DwarfUnit::AccelInfo &Info) {
+  forEachCompileAndTypeUnit([&](DwarfUnit *CU) {
+    bool HasRecords = false;
+    CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {
       if (DebugNames.get() == nullptr)
         DebugNames = std::make_unique<DWARF5AccelTable>();
 
+      HasRecords = true;
       switch (Info.Type) {
       case DwarfUnit::AccelType::Name:
       case DwarfUnit::AccelType::Namespace:
@@ -1158,6 +1383,13 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) {
         break; // Nothing to do.
       };
     });
+
+    if (HasRecords) {
+      CompUnits.push_back(
+          CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)
+              .StartOffset);
+      CUidToIdx[CU->getUniqueID()] = Id++;
+    }
   });
 
   if (DebugNames.get() != nullptr) {

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
index 45dc506b9947ea1..60018eea121f204 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
@@ -11,6 +11,7 @@
 
 #include "DWARFEmitterImpl.h"
 #include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerTypeUnit.h"
 #include "StringEntryToDwarfStringPoolEntryMap.h"
 #include "llvm/ADT/AddressRanges.h"
 #include "llvm/CodeGen/AccelTable.h"
@@ -25,13 +26,7 @@ class DWARFLinkerImpl : public DWARFLinker {
 public:
   DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
                   MessageHandlerTy WarningHandler,
-                  TranslatorFuncTy StringsTranslator)
-      : UniqueUnitID(0), DebugStrStrings(GlobalData),
-        DebugLineStrStrings(GlobalData), CommonSections(GlobalData) {
-    GlobalData.setTranslator(StringsTranslator);
-    GlobalData.setErrorHandler(ErrorHandler);
-    GlobalData.setWarningHandler(WarningHandler);
-  }
+                  TranslatorFuncTy StringsTranslator);
 
   /// Create debug info emitter.
   Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
@@ -74,11 +69,7 @@ class DWARFLinkerImpl : public DWARFLinker {
   }
 
   /// Do not unique types according to ODR.
-  void setNoODR(bool) override {
-    // FIXME: set option when ODR mode will be supported.
-    // getOptions().NoODR = NoODR;
-    GlobalData.Options.NoODR = true;
-  }
+  void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; }
 
   /// Update index tables only(do not modify rest of DWARF).
   void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override {
@@ -114,9 +105,7 @@ class DWARFLinkerImpl : public DWARFLinker {
   }
 
   /// Set estimated objects files amount, for preliminary data allocation.
-  void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override {
-    ObjectContexts.reserve(ObjFilesNum);
-  }
+  void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override;
 
   /// Set verification handler which would be used to report verification
   /// errors.
@@ -173,10 +162,8 @@ class DWARFLinkerImpl : public DWARFLinker {
     /// Keep information for referenced clang module: already loaded DWARF info
     /// of the clang module and a CompileUnit of the module.
     struct RefModuleUnit {
-      RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit)
-          : File(File), Unit(std::move(Unit)) {}
-      RefModuleUnit(RefModuleUnit &&Other)
-          : File(Other.File), Unit(std::move(Other.Unit)) {}
+      RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit);
+      RefModuleUnit(RefModuleUnit &&Other);
       RefModuleUnit(const RefModuleUnit &) = delete;
 
       DWARFFile &File;
@@ -209,28 +196,15 @@ class DWARFLinkerImpl : public DWARFLinker {
     /// if new inter-connected units were found.
     std::atomic<bool> HasNewInterconnectedCUs = {false};
 
+    std::atomic<bool> HasNewGlobalDependency = {false};
+
     /// Counter for compile units ID.
     std::atomic<size_t> &UniqueUnitID;
 
     LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File,
                 StringMap<uint64_t> &ClangModules,
                 std::atomic<size_t> &UniqueUnitID,
-                std::optional<Triple> TargetTriple)
-        : OutputSections(GlobalData), InputDWARFFile(File),
-          ClangModules(ClangModules), TargetTriple(TargetTriple),
-          UniqueUnitID(UniqueUnitID) {
-
-      if (File.Dwarf) {
-        if (!File.Dwarf->compile_units().empty())
-          CompileUnits.reserve(File.Dwarf->getNumCompileUnits());
-
-        // Set context format&endianness based on the input file.
-        Format.Version = File.Dwarf->getMaxVersion();
-        Format.AddrSize = File.Dwarf->getCUAddrSize();
-        Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little
-                                                  : llvm::endianness::big;
-      }
-    }
+                std::optional<Triple> TargetTriple);
 
     /// Check whether specified \p CUDie is a Clang module reference.
     /// if \p Quiet is false then display error messages.
@@ -259,9 +233,7 @@ class DWARFLinkerImpl : public DWARFLinker {
                           unsigned Indent = 0);
 
     /// Add Compile Unit corresponding to the module.
-    void addModulesCompileUnit(RefModuleUnit &&Unit) {
-      ModulesCompileUnits.emplace_back(std::move(Unit));
-    }
+    void addModulesCompileUnit(RefModuleUnit &&Unit);
 
     /// Computes the total size of the debug info.
     uint64_t getInputDebugInfoSize() const {
@@ -277,11 +249,11 @@ class DWARFLinkerImpl : public DWARFLinker {
     }
 
     /// Link compile units for this context.
-    Error link();
+    Error link(TypeUnit *ArtificialTypeUnit);
 
     /// Link specified compile unit until specified stage.
     void linkSingleCompileUnit(
-        CompileUnit &CU,
+        CompileUnit &CU, TypeUnit *ArtificialTypeUnit,
         enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned);
 
     /// Emit invariant sections.
@@ -331,6 +303,9 @@ class DWARFLinkerImpl : public DWARFLinker {
   void forEachObjectSectionsSet(
       function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler);
 
+  /// Enumerates all compile and type units.
+  void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler);
+
   /// Enumerates all comple units.
   void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler);
 
@@ -368,6 +343,9 @@ class DWARFLinkerImpl : public DWARFLinker {
   /// Mapping the PCM filename to the DwoId.
   StringMap<uint64_t> ClangModules;
   std::mutex ClangModulesMutex;
+
+  /// Type unit.
+  std::unique_ptr<TypeUnit> ArtificialTypeUnit;
   /// @}
 
   /// \defgroup Data members accessed sequentially.

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
new file mode 100644
index 000000000000000..9d5c213085c2935
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp
@@ -0,0 +1,391 @@
+//===- DWARFLinkerTypeUnit.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLinkerTypeUnit.h"
+#include "DIEGenerator.h"
+#include "DWARFEmitterImpl.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+using namespace llvm::dwarflinker_parallel;
+
+TypeUnit::TypeUnit(LinkingGlobalData &GlobalData, unsigned ID,
+                   std::optional<uint16_t> Language, dwarf::FormParams Format,
+                   endianness Endianess)
+    : DwarfUnit(GlobalData, ID, ""), Language(Language),
+      AcceleratorRecords(&GlobalData.getAllocator()) {
+
+  UnitName = "__artificial_type_unit";
+
+  setOutputFormat(Format, Endianess);
+
+  // Create line table prologue.
+  LineTable.Prologue.FormParams = getFormParams();
+  LineTable.Prologue.MinInstLength = 1;
+  LineTable.Prologue.MaxOpsPerInst = 1;
+  LineTable.Prologue.DefaultIsStmt = 1;
+  LineTable.Prologue.LineBase = -5;
+  LineTable.Prologue.LineRange = 14;
+  LineTable.Prologue.OpcodeBase = 13;
+  LineTable.Prologue.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0,
+                                              0, 0, 1, 0, 0, 1};
+
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+}
+
+void TypeUnit::createDIETree(BumpPtrAllocator &Allocator) {
+  prepareDataForTreeCreation();
+
+  // TaskGroup is created here as internal code has calls to
+  // PerThreadBumpPtrAllocator which should be called from the task group task.
+  parallel::TaskGroup TG;
+  TG.spawn([&]() {
+    SectionDescriptor &DebugInfoSection =
+        getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+    SectionDescriptor &DebugLineSection =
+        getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);
+
+    DIEGenerator DIETreeGenerator(Allocator, *this);
+    OffsetsPtrVector PatchesOffsets;
+
+    // Create a Die for artificial compilation unit for types.
+    DIE *UnitDIE = DIETreeGenerator.createDIE(dwarf::DW_TAG_compile_unit, 0);
+    uint64_t OutOffset = getDebugInfoHeaderSize();
+    UnitDIE->setOffset(OutOffset);
+
+    SmallString<200> ProducerString;
+    ProducerString += "llvm DWARFLinkerParallel library version ";
+    DebugInfoSection.notePatchWithOffsetUpdate(
+        DebugStrPatch{
+            {OutOffset},
+            GlobalData.getStringPool().insert(ProducerString.str()).first},
+        PatchesOffsets);
+    OutOffset += DIETreeGenerator
+                     .addStringPlaceholderAttribute(dwarf::DW_AT_producer,
+                                                    dwarf::DW_FORM_strp)
+                     .second;
+
+    if (Language) {
+      OutOffset += DIETreeGenerator
+                       .addScalarAttribute(dwarf::DW_AT_language,
+                                           dwarf::DW_FORM_data2, *Language)
+                       .second;
+    }
+
+    DebugInfoSection.notePatchWithOffsetUpdate(
+        DebugStrPatch{{OutOffset},
+                      GlobalData.getStringPool().insert(getUnitName()).first},
+        PatchesOffsets);
+    OutOffset += DIETreeGenerator
+                     .addStringPlaceholderAttribute(dwarf::DW_AT_name,
+                                                    dwarf::DW_FORM_strp)
+                     .second;
+
+    if (!LineTable.Prologue.FileNames.empty()) {
+      DebugInfoSection.notePatchWithOffsetUpdate(
+          DebugOffsetPatch{OutOffset, &DebugLineSection}, PatchesOffsets);
+
+      OutOffset += DIETreeGenerator
+                       .addScalarAttribute(dwarf::DW_AT_stmt_list,
+                                           dwarf::DW_FORM_sec_offset, 0xbaddef)
+                       .second;
+    }
+
+    DebugInfoSection.notePatchWithOffsetUpdate(
+        DebugStrPatch{{OutOffset}, GlobalData.getStringPool().insert("").first},
+        PatchesOffsets);
+    OutOffset += DIETreeGenerator
+                     .addStringPlaceholderAttribute(dwarf::DW_AT_comp_dir,
+                                                    dwarf::DW_FORM_strp)
+                     .second;
+
+    if (!DebugStringIndexMap.empty()) {
+      // Type unit is assumed to be emitted first. Thus we can use direct value
+      // for DW_AT_str_offsets_base attribute(No need to fix it up with unit
+      // offset value).
+      OutOffset += DIETreeGenerator
+                       .addScalarAttribute(dwarf::DW_AT_str_offsets_base,
+                                           dwarf::DW_FORM_sec_offset,
+                                           getDebugStrOffsetsHeaderSize())
+                       .second;
+    }
+
+    UnitDIE->setSize(OutOffset - UnitDIE->getOffset() + 1);
+    OutOffset =
+        finalizeTypeEntryRec(UnitDIE->getOffset(), UnitDIE, Types.getRoot());
+
+    // Update patch offsets.
+    for (uint64_t *OffsetPtr : PatchesOffsets)
+      *OffsetPtr += getULEB128Size(UnitDIE->getAbbrevNumber());
+
+    setOutUnitDIE(UnitDIE);
+  });
+}
+
+void TypeUnit::prepareDataForTreeCreation() {
+  SectionDescriptor &DebugInfoSection =
+      getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+
+  // Type unit data created parallelly. So the order of data is not
+  // deterministic. Order data here if we need deterministic output.
+
+  parallel::TaskGroup TG;
+
+  if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+    TG.spawn([&]() {
+      // Sort types to have a deterministic output.
+      Types.sortTypes();
+    });
+  }
+
+  TG.spawn([&]() {
+    if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+      // Sort decl type patches to have a deterministic output.
+      std::function<bool(const DebugTypeDeclFilePatch &LHS,
+                         const DebugTypeDeclFilePatch &RHS)>
+          PatchesComparator = [&](const DebugTypeDeclFilePatch &LHS,
+                                  const DebugTypeDeclFilePatch &RHS) {
+            return LHS.Directory->first() < RHS.Directory->first() ||
+                   (!(RHS.Directory->first() < LHS.Directory->first()) &&
+                    LHS.FilePath->first() < RHS.FilePath->first());
+          };
+      // Sort patches to have a deterministic output.
+      DebugInfoSection.ListDebugTypeDeclFilePatch.sort(PatchesComparator);
+    }
+
+    // Update DW_AT_decl_file attribute
+    dwarf::Form DeclFileForm =
+        getScalarFormForValue(
+            DebugInfoSection.ListDebugTypeDeclFilePatch.size())
+            .first;
+
+    DebugInfoSection.ListDebugTypeDeclFilePatch.forEach(
+        [&](DebugTypeDeclFilePatch &Patch) {
+          TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+          assert(TypeEntry &&
+                 formatv("No data for type {0}", Patch.TypeName->getKey())
+                     .str()
+                     .c_str());
+          if (&TypeEntry->getFinalDie() != Patch.Die)
+            return;
+
+          uint32_t FileIdx =
+              addFileNameIntoLinetable(Patch.Directory, Patch.FilePath);
+
+          unsigned DIESize = Patch.Die->getSize();
+          DIEGenerator DIEGen(Patch.Die, Types.getThreadLocalAllocator(),
+                              *this);
+
+          DIESize += DIEGen
+                         .addScalarAttribute(dwarf::DW_AT_decl_file,
+                                             DeclFileForm, FileIdx)
+                         .second;
+          Patch.Die->setSize(DIESize);
+        });
+  });
+
+  if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+    // Sort patches to have a deterministic output.
+    TG.spawn([&]() {
+      forEach([&](SectionDescriptor &OutSection) {
+        std::function<bool(const DebugStrPatch &LHS, const DebugStrPatch &RHS)>
+            StrPatchesComparator =
+                [&](const DebugStrPatch &LHS, const DebugStrPatch &RHS) {
+                  return LHS.String->getKey() < RHS.String->getKey();
+                };
+        OutSection.ListDebugStrPatch.sort(StrPatchesComparator);
+
+        std::function<bool(const DebugTypeStrPatch &LHS,
+                           const DebugTypeStrPatch &RHS)>
+            TypeStrPatchesComparator = [&](const DebugTypeStrPatch &LHS,
+                                           const DebugTypeStrPatch &RHS) {
+              return LHS.String->getKey() < RHS.String->getKey();
+            };
+        OutSection.ListDebugTypeStrPatch.sort(TypeStrPatchesComparator);
+      });
+    });
+  }
+
+  if (!GlobalData.getOptions().AllowNonDeterministicOutput) {
+    // Sort patches to have a deterministic output.
+    TG.spawn([&]() {
+      forEach([&](SectionDescriptor &OutSection) {
+        std::function<bool(const DebugLineStrPatch &LHS,
+                           const DebugLineStrPatch &RHS)>
+            LineStrPatchesComparator = [&](const DebugLineStrPatch &LHS,
+                                           const DebugLineStrPatch &RHS) {
+              return LHS.String->getKey() < RHS.String->getKey();
+            };
+        OutSection.ListDebugLineStrPatch.sort(LineStrPatchesComparator);
+
+        std::function<bool(const DebugTypeLineStrPatch &LHS,
+                           const DebugTypeLineStrPatch &RHS)>
+            TypeLineStrPatchesComparator =
+                [&](const DebugTypeLineStrPatch &LHS,
+                    const DebugTypeLineStrPatch &RHS) {
+                  return LHS.String->getKey() < RHS.String->getKey();
+                };
+        OutSection.ListDebugTypeLineStrPatch.sort(TypeLineStrPatchesComparator);
+      });
+    });
+  }
+}
+
+uint64_t TypeUnit::finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE,
+                                        TypeEntry *Entry) {
+  bool HasChildren = !Entry->getValue().load()->Children.empty();
+  DIEGenerator DIEGen(OutDIE, Types.getThreadLocalAllocator(), *this);
+  OutOffset += DIEGen.finalizeAbbreviations(HasChildren, nullptr);
+  OutOffset += OutDIE->getSize() - 1;
+
+  if (HasChildren) {
+    Entry->getValue().load()->Children.forEach([&](TypeEntry *ChildEntry) {
+      DIE *ChildDIE = &ChildEntry->getValue().load()->getFinalDie();
+      DIEGen.addChild(ChildDIE);
+
+      ChildDIE->setOffset(OutOffset);
+
+      OutOffset = finalizeTypeEntryRec(OutOffset, ChildDIE, ChildEntry);
+    });
+
+    // End of children marker.
+    OutOffset += sizeof(int8_t);
+  }
+
+  OutDIE->setSize(OutOffset - OutDIE->getOffset());
+  return OutOffset;
+}
+
+uint32_t TypeUnit::addFileNameIntoLinetable(StringEntry *Dir,
+                                            StringEntry *FileName) {
+  uint32_t DirIdx = 0;
+
+  if (Dir->first() == "") {
+    DirIdx = 0;
+  } else {
+    DirectoriesMapTy::iterator DirEntry = DirectoriesMap.find(Dir);
+    if (DirEntry == DirectoriesMap.end()) {
+      // We currently do not support more than UINT32_MAX directories.
+      assert(LineTable.Prologue.IncludeDirectories.size() < UINT32_MAX);
+      DirIdx = LineTable.Prologue.IncludeDirectories.size();
+      DirectoriesMap.insert({Dir, DirIdx});
+      LineTable.Prologue.IncludeDirectories.push_back(
+          DWARFFormValue::createFromPValue(dwarf::DW_FORM_string,
+                                           Dir->getKeyData()));
+    } else {
+      DirIdx = DirEntry->second;
+    }
+
+    if (getVersion() < 5)
+      DirIdx++;
+  }
+
+  uint32_t FileIdx = 0;
+  FilenamesMapTy::iterator FileEntry = FileNamesMap.find({FileName, DirIdx});
+  if (FileEntry == FileNamesMap.end()) {
+    // We currently do not support more than UINT32_MAX files.
+    assert(LineTable.Prologue.FileNames.size() < UINT32_MAX);
+    FileIdx = LineTable.Prologue.FileNames.size();
+    FileNamesMap.insert({{FileName, DirIdx}, FileIdx});
+    LineTable.Prologue.FileNames.push_back(DWARFDebugLine::FileNameEntry());
+    LineTable.Prologue.FileNames.back().Name = DWARFFormValue::createFromPValue(
+        dwarf::DW_FORM_string, FileName->getKeyData());
+    LineTable.Prologue.FileNames.back().DirIdx = DirIdx;
+  } else {
+    FileIdx = FileEntry->second;
+  }
+
+  return getVersion() < 5 ? FileIdx + 1 : FileIdx;
+}
+
+std::pair<dwarf::Form, uint8_t>
+TypeUnit::getScalarFormForValue(uint64_t Value) const {
+  if (Value > 0xFFFFFFFF)
+    return std::make_pair(dwarf::DW_FORM_data8, 8);
+
+  if (Value > 0xFFFF)
+    return std::make_pair(dwarf::DW_FORM_data4, 4);
+
+  if (Value > 0xFF)
+    return std::make_pair(dwarf::DW_FORM_data2, 2);
+
+  return std::make_pair(dwarf::DW_FORM_data1, 1);
+}
+
+uint8_t TypeUnit::getSizeByAttrForm(dwarf::Form Form) const {
+  if (Form == dwarf::DW_FORM_data1)
+    return 1;
+
+  if (Form == dwarf::DW_FORM_data2)
+    return 2;
+
+  if (Form == dwarf::DW_FORM_data4)
+    return 4;
+
+  if (Form == dwarf::DW_FORM_data8)
+    return 8;
+
+  if (Form == dwarf::DW_FORM_data16)
+    return 16;
+
+  llvm_unreachable("Unsupported Attr Form");
+}
+
+Error TypeUnit::finishCloningAndEmit(std::optional<Triple> TargetTriple) {
+  BumpPtrAllocator Allocator;
+  createDIETree(Allocator);
+
+  if (getGlobalData().getOptions().NoOutput || (getOutUnitDIE() == nullptr))
+    return Error::success();
+
+  // Create sections ahead so that they should not be created asynchronously
+  // later.
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo);
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugLine);
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets);
+  getOrCreateSectionDescriptor(DebugSectionKind::DebugAbbrev);
+  if (llvm::is_contained(GlobalData.getOptions().AccelTables,
+                         DWARFLinker::AccelTableKind::Pub)) {
+    getOrCreateSectionDescriptor(DebugSectionKind::DebugPubNames);
+    getOrCreateSectionDescriptor(DebugSectionKind::DebugPubTypes);
+  }
+
+  SmallVector<std::function<Error(void)>> Tasks;
+
+  // Add task for emitting .debug_line section.
+  if (!LineTable.Prologue.FileNames.empty()) {
+    Tasks.push_back([&]() -> Error {
+      assert(TargetTriple.has_value());
+      return emitDebugLine(*TargetTriple, LineTable);
+    });
+  }
+
+  // Add task for emitting .debug_info section.
+  Tasks.push_back([&]() -> Error { return emitDebugInfo(*TargetTriple); });
+
+  // Add task for emitting Pub accelerator sections.
+  if (llvm::is_contained(GlobalData.getOptions().AccelTables,
+                         DWARFLinker::AccelTableKind::Pub)) {
+    Tasks.push_back([&]() -> Error {
+      emitPubAccelerators();
+      return Error::success();
+    });
+  }
+
+  // Add task for emitting .debug_str_offsets section.
+  Tasks.push_back([&]() -> Error { return emitDebugStringOffsetSection(); });
+
+  // Add task for emitting .debug_abbr section.
+  Tasks.push_back([&]() -> Error { return emitAbbreviations(); });
+
+  if (auto Err = parallelForEachError(
+          Tasks, [&](std::function<Error(void)> F) { return F(); }))
+    return Err;
+
+  return Error::success();
+}

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
new file mode 100644
index 000000000000000..97e620eee0c4245
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h
@@ -0,0 +1,138 @@
+//===- DWARFLinkerTypeUnit.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H
+#define LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H
+
+#include "DWARFLinkerUnit.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// Type Unit is used to represent an artificial compilation unit
+/// which keeps all type information. This type information is referenced
+/// from other compilation units.
+class TypeUnit : public DwarfUnit {
+public:
+  TypeUnit(LinkingGlobalData &GlobalData, unsigned ID,
+           std::optional<uint16_t> Language, dwarf::FormParams Format,
+           llvm::endianness Endianess);
+
+  /// Generates DIE tree based on information from TypesMap.
+  void createDIETree(BumpPtrAllocator &Allocator);
+
+  /// Emits resulting dwarf based on information from DIE tree.
+  Error finishCloningAndEmit(std::optional<Triple> TargetTriple);
+
+  /// Returns global type pool.
+  TypePool &getTypePool() { return Types; }
+
+  /// TypeUnitAccelInfo extends AccelInfo structure with type specific fileds.
+  /// We need these additional fields to decide whether OutDIE should have an
+  /// accelerator record or not. The TypeEntryBodyPtr can refer to the
+  /// declaration DIE and definition DIE corresponding to the type entry.
+  /// Only one of them would be used in final output. So if TypeUnitAccelInfo
+  /// refers OutDIE which does not match with TypeEntryBodyPtr->getFinalDie()
+  /// then such record should be skipped.
+  struct TypeUnitAccelInfo : public AccelInfo {
+    /// Pointer to the output DIE which owns this accelerator record.
+    DIE *OutDIE = nullptr;
+
+    /// Pointer to the type entry body.
+    TypeEntryBody *TypeEntryBodyPtr = nullptr;
+  };
+
+  /// Enumerates all accelerator records and call \p Handler for each.
+  void
+  forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) override {
+    AcceleratorRecords.forEach([&](TypeUnitAccelInfo &Info) {
+      // Check whether current record is for the final DIE.
+      assert(Info.TypeEntryBodyPtr != nullptr);
+
+      if (&Info.TypeEntryBodyPtr->getFinalDie() != Info.OutDIE)
+        return;
+
+      Info.OutOffset = Info.OutDIE->getOffset();
+      Handler(Info);
+    });
+  }
+
+  /// Returns index for the specified \p String inside .debug_str_offsets.
+  uint64_t getDebugStrIndex(const StringEntry *String) override {
+    std::unique_lock<std::mutex> LockGuard(DebugStringIndexMapMutex);
+    return DebugStringIndexMap.getValueIndex(String);
+  }
+
+  /// Adds \p Info to the unit's accelerator records.
+  void saveAcceleratorInfo(const TypeUnitAccelInfo &Info) {
+    AcceleratorRecords.add(Info);
+  }
+
+private:
+  /// Type DIEs are partially created at clonning stage. They are organised
+  /// as a tree using type entries. This function links DIEs(corresponding
+  /// to the type entries) into the tree structure.
+  uint64_t finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE,
+                                TypeEntry *Entry);
+
+  /// Prepares DIEs to be linked into the tree.
+  void prepareDataForTreeCreation();
+
+  /// Add specified \p Dir and \p Filename into the line table
+  /// of this type unit.
+  uint32_t addFileNameIntoLinetable(StringEntry *Dir, StringEntry *FileName);
+
+  std::pair<dwarf::Form, uint8_t> getScalarFormForValue(uint64_t Value) const;
+
+  uint8_t getSizeByAttrForm(dwarf::Form Form) const;
+
+  struct CmpStringEntryRef {
+    bool operator()(const StringEntry *LHS, const StringEntry *RHS) const {
+      return LHS->first() < RHS->first();
+    }
+  };
+  struct CmpDirIDStringEntryRef {
+    bool operator()(const std::pair<StringEntry *, uint64_t> &LHS,
+                    const std::pair<StringEntry *, uint64_t> &RHS) const {
+      return LHS.second < RHS.second ||
+             (!(RHS.second < LHS.second) &&
+              LHS.first->first() < RHS.first->first());
+    }
+  };
+
+  /// The DW_AT_language of this unit.
+  std::optional<uint16_t> Language;
+
+  /// This unit line table.
+  DWARFDebugLine::LineTable LineTable;
+
+  /// Data members keeping file names for line table.
+  using DirectoriesMapTy = std::map<StringEntry *, size_t, CmpStringEntryRef>;
+  using FilenamesMapTy = std::map<std::pair<StringEntry *, uint64_t>, size_t,
+                                  CmpDirIDStringEntryRef>;
+
+  DirectoriesMapTy DirectoriesMap;
+  FilenamesMapTy FileNamesMap;
+
+  /// Type DIEs tree.
+  TypePool Types;
+
+  /// List of accelerator entries for this unit.
+  ArrayList<TypeUnitAccelInfo> AcceleratorRecords;
+
+  /// Guard for DebugStringIndexMap.
+  std::mutex DebugStringIndexMapMutex;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
index 1503015f015575b..b1da1900d65ef70 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp
@@ -88,7 +88,7 @@ void DwarfUnit::emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
   encodeULEB128(0, AbbrevSection.OS);
 }
 
-Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) {
+Error DwarfUnit::emitDebugInfo(const Triple &TargetTriple) {
   DIE *OutUnitDIE = getOutUnitDIE();
   if (OutUnitDIE == nullptr)
     return Error::success();
@@ -119,18 +119,60 @@ Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) {
   return Error::success();
 }
 
-Error DwarfUnit::emitDebugLine(Triple &TargetTriple,
+Error DwarfUnit::emitDebugLine(const Triple &TargetTriple,
                                const DWARFDebugLine::LineTable &OutLineTable) {
   DebugLineSectionEmitter DebugLineEmitter(TargetTriple, *this);
 
   return DebugLineEmitter.emit(OutLineTable);
 }
 
+Error DwarfUnit::emitDebugStringOffsetSection() {
+  if (getVersion() < 5)
+    return Error::success();
+
+  if (DebugStringIndexMap.empty())
+    return Error::success();
+
+  SectionDescriptor &OutDebugStrOffsetsSection =
+      getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets);
+
+  // Emit section header.
+
+  //   Emit length.
+  OutDebugStrOffsetsSection.emitUnitLength(0xBADDEF);
+  uint64_t OffsetAfterSectionLength = OutDebugStrOffsetsSection.OS.tell();
+
+  //   Emit version.
+  OutDebugStrOffsetsSection.emitIntVal(5, 2);
+
+  //   Emit padding.
+  OutDebugStrOffsetsSection.emitIntVal(0, 2);
+
+  //   Emit index to offset map.
+  for (const StringEntry *String : DebugStringIndexMap.getValues()) {
+    // Note patch for string offset value.
+    OutDebugStrOffsetsSection.notePatch(
+        DebugStrPatch{{OutDebugStrOffsetsSection.OS.tell()}, String});
+
+    // Emit placeholder for offset value.
+    OutDebugStrOffsetsSection.emitOffset(0xBADDEF);
+  }
+
+  // Patch section length.
+  OutDebugStrOffsetsSection.apply(
+      OffsetAfterSectionLength -
+          OutDebugStrOffsetsSection.getFormParams().getDwarfOffsetByteSize(),
+      dwarf::DW_FORM_sec_offset,
+      OutDebugStrOffsetsSection.OS.tell() - OffsetAfterSectionLength);
+
+  return Error::success();
+}
+
 /// Emit the pubnames or pubtypes section contribution for \p
 /// Unit into \p Sec. The data is provided in \p Info.
 std::optional<uint64_t>
 DwarfUnit::emitPubAcceleratorEntry(SectionDescriptor &OutSection,
-                                   DwarfUnit::AccelInfo &Info,
+                                   const DwarfUnit::AccelInfo &Info,
                                    std::optional<uint64_t> LengthOffset) {
   if (!LengthOffset) {
     // Emit the header.
@@ -160,7 +202,7 @@ void DwarfUnit::emitPubAccelerators() {
   std::optional<uint64_t> NamesLengthOffset;
   std::optional<uint64_t> TypesLengthOffset;
 
-  AcceleratorRecords.forEach([&](DwarfUnit::AccelInfo &Info) {
+  forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) {
     if (Info.AvoidForPubSections)
       return;
 

diff  --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
index 0835fad1e667a38..9640a8ee711eb0e 100644
--- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
+++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
@@ -10,6 +10,7 @@
 #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
 
 #include "DWARFLinkerGlobalData.h"
+#include "IndexedValuesMap.h"
 #include "OutputSections.h"
 #include "llvm/CodeGen/DIE.h"
 #include "llvm/DWARFLinkerParallel/DWARFLinker.h"
@@ -30,16 +31,11 @@ class DwarfUnit : public OutputSections {
   DwarfUnit(LinkingGlobalData &GlobalData, unsigned ID,
             StringRef ClangModuleName)
       : OutputSections(GlobalData), ID(ID), ClangModuleName(ClangModuleName),
-        OutUnitDIE(nullptr) {
-    AcceleratorRecords.setAllocator(&GlobalData.getAllocator());
-  }
+        OutUnitDIE(nullptr) {}
 
   /// Unique id of the unit.
   unsigned getUniqueID() const { return ID; }
 
-  /// Return language of this unit.
-  uint16_t getLanguage() const { return Language; }
-
   /// Returns size of this(newly generated) compile unit.
   uint64_t getUnitSize() const { return UnitSize; }
 
@@ -91,11 +87,14 @@ class DwarfUnit : public OutputSections {
   Error emitAbbreviations();
 
   /// Emit .debug_info section for unit DIEs.
-  Error emitDebugInfo(Triple &TargetTriple);
+  Error emitDebugInfo(const Triple &TargetTriple);
 
   /// Emit .debug_line section.
-  Error emitDebugLine(Triple &TargetTriple,
+  Error emitDebugLine(const Triple &TargetTriple,
                       const DWARFDebugLine::LineTable &OutLineTable);
+
+  /// Emit the .debug_str_offsets section for current unit.
+  Error emitDebugStringOffsetSection();
   /// @}
 
   /// \defgroup Methods used for reporting warnings and errors:
@@ -124,7 +123,7 @@ class DwarfUnit : public OutputSections {
     StringEntry *String = nullptr;
 
     /// Output offset of the DIE this entry describes.
-    uint64_t OutOffset = 0;
+    uint64_t OutOffset;
 
     /// Hash of the fully qualified name.
     uint32_t QualifiedNameHash = 0;
@@ -135,71 +134,27 @@ class DwarfUnit : public OutputSections {
     /// Type of this accelerator record.
     AccelType Type = AccelType::None;
 
-    /// Avoid using this entry for pub sections.
+    /// Avoid emitting this entry for pub sections.
     bool AvoidForPubSections : 1;
 
     /// Is this an ObjC class implementation?
     bool ObjcClassImplementation : 1;
   };
 
-  void rememberNameForAccelerators(StringEntry *Name, uint64_t OutOffset,
-                                   dwarf::Tag Tag, bool AvoidForPubSections) {
-    AccelInfo Info;
-
-    Info.Type = AccelType::Name;
-    Info.String = Name;
-    Info.OutOffset = OutOffset;
-    Info.Tag = Tag;
-    Info.AvoidForPubSections = AvoidForPubSections;
-
-    AcceleratorRecords.add(Info);
-  }
-  void rememberNamespaceForAccelerators(StringEntry *Name, uint64_t OutOffset,
-                                        dwarf::Tag Tag) {
-    AccelInfo Info;
-
-    Info.Type = AccelType::Namespace;
-    Info.String = Name;
-    Info.OutOffset = OutOffset;
-    Info.Tag = Tag;
-
-    AcceleratorRecords.add(Info);
-  }
-  void rememberObjCNameForAccelerators(StringEntry *Name, uint64_t OutOffset,
-                                       dwarf::Tag Tag) {
-    AccelInfo Info;
-
-    Info.Type = AccelType::ObjC;
-    Info.String = Name;
-    Info.OutOffset = OutOffset;
-    Info.Tag = Tag;
-    Info.AvoidForPubSections = true;
-
-    AcceleratorRecords.add(Info);
-  }
-  void rememberTypeForAccelerators(StringEntry *Name, uint64_t OutOffset,
-                                   dwarf::Tag Tag, uint32_t QualifiedNameHash,
-                                   bool ObjcClassImplementation) {
-    AccelInfo Info;
-
-    Info.Type = AccelType::Type;
-    Info.String = Name;
-    Info.OutOffset = OutOffset;
-    Info.Tag = Tag;
-    Info.QualifiedNameHash = QualifiedNameHash;
-    Info.ObjcClassImplementation = ObjcClassImplementation;
-
-    AcceleratorRecords.add(Info);
-  }
-
   /// Emit .debug_pubnames and .debug_pubtypes for \p Unit.
   void emitPubAccelerators();
 
-  /// Accelerator tables data.
-  ArrayList<AccelInfo> AcceleratorRecords;
+  /// Enumerates accelerator data.
+  virtual void
+  forEachAcceleratorRecord(function_ref<void(AccelInfo &)> Handler) = 0;
 
   /// @}
 
+  /// Returns index(inside .debug_str_offsets) of specified string.
+  virtual uint64_t getDebugStrIndex(const StringEntry *String) {
+    return DebugStringIndexMap.getValueIndex(String);
+  }
+
 protected:
   /// Emit single abbreviation entry.
   void emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev,
@@ -207,16 +162,12 @@ class DwarfUnit : public OutputSections {
 
   /// Emit single pubnames/pubtypes accelerator entry.
   std::optional<uint64_t>
-  emitPubAcceleratorEntry(SectionDescriptor &OutSection,
-                          DwarfUnit::AccelInfo &Info,
+  emitPubAcceleratorEntry(SectionDescriptor &OutSection, const AccelInfo &Info,
                           std::optional<uint64_t> LengthOffset);
 
   /// Unique ID for the unit.
   unsigned ID = 0;
 
-  /// The DW_AT_language of this unit.
-  uint16_t Language = 0;
-
   /// The name of this unit.
   std::string UnitName;
 
@@ -239,8 +190,31 @@ class DwarfUnit : public OutputSections {
 
   /// Output unit DIE.
   DIE *OutUnitDIE = nullptr;
+
+  /// Cache for file names for this unit.
+  using FileNamesCache =
+      DenseMap<uint64_t, std::pair<std::string, std::string>>;
+  FileNamesCache FileNames;
+
+  /// Maps a string into the index inside .debug_str_offsets section.
+  IndexedValuesMap<const StringEntry *> DebugStringIndexMap;
 };
 
+inline bool isODRLanguage(uint16_t Language) {
+  switch (Language) {
+  case dwarf::DW_LANG_C_plus_plus:
+  case dwarf::DW_LANG_C_plus_plus_03:
+  case dwarf::DW_LANG_C_plus_plus_11:
+  case dwarf::DW_LANG_C_plus_plus_14:
+  case dwarf::DW_LANG_ObjC_plus_plus:
+    return true;
+  default:
+    return false;
+  };
+
+  return false;
+}
+
 } // end of namespace dwarflinker_parallel
 } // end namespace llvm
 

diff  --git a/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h b/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
index 4aef0d0d67303da..fc7f8cbc4a8e7bd 100644
--- a/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
+++ b/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h
@@ -149,6 +149,7 @@ class DebugLineSectionEmitter {
       // A null-terminated string containing the full or relative path name of a
       // source file.
       Section.emitString(File.Name.getForm(), *FileNameStr);
+
       // An unsigned LEB128 number representing the directory index of a
       // directory in the include_directories section.
       encodeULEB128(File.DirIdx, Section.OS);

diff  --git a/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp b/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
index 3a69c3821e8b52b..8767cc0fc6e77c4 100644
--- a/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
+++ b/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp
@@ -12,18 +12,20 @@
 namespace llvm {
 namespace dwarflinker_parallel {
 
-#ifndef NDEBUG
 /// A broken link in the keep chain. By recording both the parent and the child
 /// we can show only broken links for DIEs with multiple children.
 struct BrokenLink {
-  BrokenLink(DWARFDie Parent, DWARFDie Child) : Parent(Parent), Child(Child) {}
+  BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
+      : Parent(Parent), Child(Child), Message(Message) {}
   DWARFDie Parent;
   DWARFDie Child;
+  std::string Message;
 };
 
 /// Verify the keep chain by looking for DIEs that are kept but who's parent
 /// isn't.
-void DependencyTracker::verifyKeepChain(CompileUnit &CU) {
+void DependencyTracker::verifyKeepChain() {
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
   SmallVector<DWARFDie> Worklist;
   Worklist.push_back(CU.getOrigUnit().getUnitDIE());
 
@@ -37,176 +39,585 @@ void DependencyTracker::verifyKeepChain(CompileUnit &CU) {
     if (!Current.isValid())
       continue;
 
-    const bool CurrentDieIsKept = CU.getDIEInfo(Current).getKeep() ||
-                                  CU.getDIEInfo(Current).getKeepChildren();
+    CompileUnit::DIEInfo &CurrentInfo =
+        CU.getDIEInfo(Current.getDebugInfoEntry());
+    const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
+    const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
 
     for (DWARFDie Child : reverse(Current.children())) {
       Worklist.push_back(Child);
 
-      const bool ChildDieIsKept = CU.getDIEInfo(Child).getKeep() ||
-                                  CU.getDIEInfo(Child).getKeepChildren();
-      if (!CurrentDieIsKept && ChildDieIsKept)
-        BrokenLinks.emplace_back(Current, Child);
+      CompileUnit::DIEInfo &ChildInfo =
+          CU.getDIEInfo(Child.getDebugInfoEntry());
+      const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
+      const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
+
+      if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
+        BrokenLinks.emplace_back(Current, Child,
+                                 "Found invalid link in keep chain");
+
+      if (Child.getTag() == dwarf::DW_TAG_subprogram) {
+        if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
+                                        &CU, Child.getDebugInfoEntry()))) {
+          BrokenLinks.emplace_back(Current, Child,
+                                   "Live subprogram is not marked as kept");
+        }
+      }
+
+      if (!ChildInfo.getODRAvailable()) {
+        assert(!ChildTypeDieIsKept);
+        continue;
+      }
+
+      if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
+        BrokenLinks.emplace_back(Current, Child,
+                                 "Found invalid link in keep chain");
+
+      if (CurrentInfo.getIsInAnonNamespaceScope() &&
+          ChildInfo.needToPlaceInTypeTable()) {
+        BrokenLinks.emplace_back(Current, Child,
+                                 "Found invalid placement marking for member "
+                                 "of anonymous namespace");
+      }
     }
   }
 
   if (!BrokenLinks.empty()) {
     for (BrokenLink Link : BrokenLinks) {
-      WithColor::error() << formatv(
-          "Found invalid link in keep chain between {0:x} and {1:x}\n",
-          Link.Parent.getOffset(), Link.Child.getOffset());
+      errs() << "\n=================================\n";
+      WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
+                                    Link.Parent.getOffset(),
+                                    Link.Child.getOffset());
 
-      errs() << "Parent:";
+      errs() << "\nParent:";
       Link.Parent.dump(errs(), 0, {});
+      errs() << "\n";
       CU.getDIEInfo(Link.Parent).dump();
 
-      errs() << "Child:";
+      errs() << "\nChild:";
       Link.Child.dump(errs(), 2, {});
+      errs() << "\n";
       CU.getDIEInfo(Link.Child).dump();
     }
     report_fatal_error("invalid keep chain");
   }
-}
 #endif
+}
 
-bool DependencyTracker::resolveDependenciesAndMarkLiveness(CompileUnit &CU) {
-  // We do not track liveness inside Clang modules. We also do not track
-  // liveness if UpdateIndexTablesOnly is requested.
-  TrackLiveness = !(CU.isClangModule() ||
-                    CU.getGlobalData().getOptions().UpdateIndexTablesOnly);
+bool DependencyTracker::resolveDependenciesAndMarkLiveness(
+    bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
   RootEntriesWorkList.clear();
 
   // Search for live root DIEs.
-  collectRootsToKeep(CU, CU.getDebugInfoEntry(0));
+  CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
+  CUInfo.setPlacement(CompileUnit::PlainDwarf);
+  collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
+                     std::nullopt, false);
 
   // Mark live DIEs as kept.
-  return markLiveRootsAsKept();
+  return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
+                                      HasNewInterconnectedCUs);
 }
 
-void DependencyTracker::collectRootsToKeep(CompileUnit &CU,
-                                           const DWARFDebugInfoEntry *Entry) {
-  if (!TrackLiveness) {
-    addItemToWorklist(CU, Entry);
+void DependencyTracker::addActionToRootEntriesWorkList(
+    LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
+    std::optional<UnitEntryPairTy> ReferencedBy) {
+  if (ReferencedBy) {
+    RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
     return;
   }
 
-  switch (Entry->getTag()) {
-  case dwarf::DW_TAG_subprogram:
-  case dwarf::DW_TAG_label:
-    if (isLiveSubprogramEntry(CU, Entry)) {
-      addItemToWorklist(CU, Entry);
+  RootEntriesWorkList.emplace_back(Action, Entry);
+}
+
+void DependencyTracker::collectRootsToKeep(
+    const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
+    bool IsLiveParent) {
+  for (const DWARFDebugInfoEntry *CurChild =
+           Entry.CU->getFirstChildEntry(Entry.DieEntry);
+       CurChild && CurChild->getAbbreviationDeclarationPtr();
+       CurChild = Entry.CU->getSiblingEntry(CurChild)) {
+    UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
+    CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
+
+    bool IsLiveChild = false;
+
+    switch (CurChild->getTag()) {
+    case dwarf::DW_TAG_label: {
+      IsLiveChild = isLiveSubprogramEntry(ChildEntry);
+
+      // Keep label referencing live address.
+      // Keep label which is child of live parent entry.
+      if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
+        addActionToRootEntriesWorkList(
+            LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,
+            ReferencedBy);
+      }
+    } break;
+    case dwarf::DW_TAG_subprogram: {
+      IsLiveChild = isLiveSubprogramEntry(ChildEntry);
+
+      // Keep subprogram referencing live address.
+      if (IsLiveChild) {
+        // If subprogram is in module scope and this module allows ODR
+        // deduplication set "TypeTable" placement, otherwise set "" placement
+        LiveRootWorklistActionTy Action =
+            (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
+                ? LiveRootWorklistActionTy::MarkTypeEntryRec
+                : LiveRootWorklistActionTy::MarkLiveEntryRec;
+
+        addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
+      }
+    } break;
+    case dwarf::DW_TAG_constant:
+    case dwarf::DW_TAG_variable: {
+      IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
+
+      // Keep variable referencing live address.
+      if (IsLiveChild) {
+        // If variable is in module scope and this module allows ODR
+        // deduplication set "TypeTable" placement, otherwise set "" placement
+
+        LiveRootWorklistActionTy Action =
+            (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
+                ? LiveRootWorklistActionTy::MarkTypeEntryRec
+                : LiveRootWorklistActionTy::MarkLiveEntryRec;
+
+        addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
+      }
+    } break;
+    case dwarf::DW_TAG_base_type: {
+      // Always keep base types.
+      addActionToRootEntriesWorkList(
+          LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
+          ReferencedBy);
+    } break;
+    case dwarf::DW_TAG_imported_module:
+    case dwarf::DW_TAG_imported_declaration:
+    case dwarf::DW_TAG_imported_unit: {
+      // Always keep DIEs having DW_AT_import attribute.
+      if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
+        addActionToRootEntriesWorkList(
+            LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
+            ReferencedBy);
+        break;
+      }
+
+      addActionToRootEntriesWorkList(
+          LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,
+          ReferencedBy);
+    } break;
+    case dwarf::DW_TAG_type_unit:
+    case dwarf::DW_TAG_partial_unit:
+    case dwarf::DW_TAG_compile_unit: {
+      llvm_unreachable("Called for incorrect DIE");
+    } break;
+    default:
+      // Nothing to do.
       break;
     }
-    [[fallthrough]];
-  case dwarf::DW_TAG_compile_unit:
-  case dwarf::DW_TAG_namespace:
-  case dwarf::DW_TAG_module:
-  case dwarf::DW_TAG_lexical_block: {
-    for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry);
-         CurChild && CurChild->getAbbreviationDeclarationPtr();
-         CurChild = CU.getSiblingEntry(CurChild))
-      collectRootsToKeep(CU, CurChild);
-  } break;
-  case dwarf::DW_TAG_constant:
-  case dwarf::DW_TAG_variable: {
-    if (isLiveVariableEntry(CU, Entry))
-      addItemToWorklist(CU, Entry);
-  } break;
-  case dwarf::DW_TAG_base_type: {
-    addItemToWorklist(CU, Entry);
-  } break;
-  case dwarf::DW_TAG_imported_module:
-  case dwarf::DW_TAG_imported_declaration:
-  case dwarf::DW_TAG_imported_unit: {
-    addItemToWorklist(CU, Entry);
-  } break;
-  default:
-    // Nothing to do.
-    break;
+
+    collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
   }
 }
 
-bool DependencyTracker::markLiveRootsAsKept() {
+bool DependencyTracker::markCollectedLiveRootsAsKept(
+    bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
   bool Res = true;
 
+  // Mark roots as kept.
   while (!RootEntriesWorkList.empty()) {
-    RootEntryTy CurrentItem = RootEntriesWorkList.pop_back_val();
-
-    if (!markDIEEntryAsKeptRec(CurrentItem, CurrentItem.CU,
-                               CurrentItem.RootEntry))
+    LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
+
+    if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),
+                              Root.getRootEntry(), InterCUProcessingStarted,
+                              HasNewInterconnectedCUs)) {
+      if (Root.hasReferencedByOtherEntry())
+        Dependencies.push_back(Root);
+    } else
       Res = false;
   }
 
   return Res;
 }
 
-bool DependencyTracker::markDIEEntryAsKeptRec(
-    const RootEntryTy &RootItem, CompileUnit &CU,
-    const DWARFDebugInfoEntry *Entry) {
-  if (Entry->getAbbreviationDeclarationPtr() == nullptr)
-    return true;
+bool DependencyTracker::updateDependenciesCompleteness() {
+  bool HasNewDependency = false;
+  for (LiveRootWorklistItemTy &Root : Dependencies) {
+    assert(Root.hasReferencedByOtherEntry() &&
+           "Root entry without dependency inside the dependencies list");
+
+    UnitEntryPairTy RootEntry = Root.getRootEntry();
+    CompileUnit::DIEInfo &RootInfo =
+        RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
+
+    UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
+    CompileUnit::DIEInfo &ReferencedByInfo =
+        ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
+
+    if (!RootInfo.needToPlaceInTypeTable() &&
+        ReferencedByInfo.needToPlaceInTypeTable()) {
+      HasNewDependency = true;
+      setPlainDwarfPlacementRec(ReferencedByEntry);
+
+      // FIXME: we probably need to update getKeepTypeChildren status for
+      // parents of *Root.ReferencedBy.
+    }
+  }
+
+  return HasNewDependency;
+}
+
+void DependencyTracker::setPlainDwarfPlacementRec(
+    const UnitEntryPairTy &Entry) {
+  CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+  if (Info.getPlacement() == CompileUnit::PlainDwarf &&
+      !Info.getKeepTypeChildren())
+    return;
 
-  CompileUnit::DIEInfo &Info = CU.getDIEInfo(Entry);
+  Info.setPlacement(CompileUnit::PlainDwarf);
+  Info.unsetKeepTypeChildren();
+  markParentsAsKeepingChildren(Entry);
 
-  if (Info.getKeep())
+  for (const DWARFDebugInfoEntry *CurChild =
+           Entry.CU->getFirstChildEntry(Entry.DieEntry);
+       CurChild && CurChild->getAbbreviationDeclarationPtr();
+       CurChild = Entry.CU->getSiblingEntry(CurChild))
+    setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
+}
+
+static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
+  switch (Entry->getTag()) {
+  case dwarf::DW_TAG_compile_unit:
+  case dwarf::DW_TAG_module:
+  case dwarf::DW_TAG_namespace:
     return true;
 
-  // Mark parents as 'KeepChildren'.
-  std::optional<uint32_t> ParentIdx = Entry->getParentIdx();
+  default:
+    return false;
+  }
+}
+
+bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,
+                     CompileUnit::DieOutputPlacement NewPlacement) {
+  if (!Info.getKeep())
+    return false;
+
+  switch (NewPlacement) {
+  case CompileUnit::TypeTable:
+    return Info.needToPlaceInTypeTable();
+
+  case CompileUnit::PlainDwarf:
+    return Info.needToKeepInPlainDwarf();
+
+  case CompileUnit::Both:
+    return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
+
+  case CompileUnit::NotSet:
+    llvm_unreachable("Unset placement type is specified.");
+  };
+}
+
+bool isAlreadyMarked(const UnitEntryPairTy &Entry,
+                     CompileUnit::DieOutputPlacement NewPlacement) {
+  return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
+}
+
+void DependencyTracker::markParentsAsKeepingChildren(
+    const UnitEntryPairTy &Entry) {
+  if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
+    return;
+
+  CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+  bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
+  bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
+
+  bool AreTypeParentsDone = !NeedKeepTypeChildren;
+  bool ArePlainParentsDone = !NeedKeepPlainChildren;
+
+  // Mark parents as 'Keep*Children'.
+  std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
   while (ParentIdx) {
-    const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx);
-    CompileUnit::DIEInfo &ParentInfo = CU.getDIEInfo(*ParentIdx);
-    if (ParentInfo.getKeepChildren())
+    const DWARFDebugInfoEntry *ParentEntry =
+        Entry.CU->getDebugInfoEntry(*ParentIdx);
+    CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
+
+    if (!AreTypeParentsDone && NeedKeepTypeChildren) {
+      if (ParentInfo.getKeepTypeChildren())
+        AreTypeParentsDone = true;
+      else {
+        bool AddToWorklist = !isAlreadyMarked(
+            ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);
+        ParentInfo.setKeepTypeChildren();
+        if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
+          addActionToRootEntriesWorkList(
+              LiveRootWorklistActionTy::MarkTypeChildrenRec,
+              UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
+        }
+      }
+    }
+
+    if (!ArePlainParentsDone && NeedKeepPlainChildren) {
+      if (ParentInfo.getKeepPlainChildren())
+        ArePlainParentsDone = true;
+      else {
+        bool AddToWorklist = !isAlreadyMarked(
+            ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);
+        ParentInfo.setKeepPlainChildren();
+        if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
+          addActionToRootEntriesWorkList(
+              LiveRootWorklistActionTy::MarkLiveChildrenRec,
+              UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
+        }
+      }
+    }
+
+    if (AreTypeParentsDone && ArePlainParentsDone)
       break;
-    ParentInfo.setKeepChildren();
+
     ParentIdx = ParentEntry->getParentIdx();
   }
+}
+
+// This function tries to set specified \p Placement for the \p Entry.
+// Depending on the concrete entry, the placement could be:
+//  a) changed to another.
+//  b) joined with current entry placement.
+//  c) set as requested.
+static CompileUnit::DieOutputPlacement
+getFinalPlacementForEntry(const UnitEntryPairTy &Entry,
+                          CompileUnit::DieOutputPlacement Placement) {
+  assert((Placement != CompileUnit::NotSet) && "Placement is not set");
+  CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
+
+  if (!EntryInfo.getODRAvailable())
+    return CompileUnit::PlainDwarf;
+
+  if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
+    // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
+    // time.
+    if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
+        EntryInfo.getPlacement() == CompileUnit::Both)
+      return CompileUnit::PlainDwarf;
+
+    if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)
+      return CompileUnit::PlainDwarf;
+  }
+
+  switch (EntryInfo.getPlacement()) {
+  case CompileUnit::NotSet:
+    return Placement;
+
+  case CompileUnit::TypeTable:
+    return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;
+
+  case CompileUnit::PlainDwarf:
+    return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;
+
+  case CompileUnit::Both:
+    return CompileUnit::Both;
+  };
+
+  llvm_unreachable("Unknown placement type.");
+  return Placement;
+}
+
+bool DependencyTracker::markDIEEntryAsKeptRec(
+    LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
+    const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
+    std::atomic<bool> &HasNewInterconnectedCUs) {
+  if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
+    return true;
+
+  CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+
+  // Calculate final placement placement.
+  CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(
+      Entry,
+      isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);
+  assert((Info.getODRAvailable() || isLiveAction(Action) ||
+          Placement == CompileUnit::PlainDwarf) &&
+         "Wrong kind of placement for ODR unavailable entry");
+
+  if (!isChildrenAction(Action))
+    if (isAlreadyMarked(Entry, Placement))
+      return true;
 
   // Mark current DIE as kept.
   Info.setKeep();
-  setDIEPlacementAndTypename(Info);
+  Info.setPlacement(Placement);
 
-  // Set liveness information.
-  switch (Entry->getTag()) {
-  case dwarf::DW_TAG_constant:
-  case dwarf::DW_TAG_variable: {
-    isLiveVariableEntry(CU, Entry);
-  } break;
-  case dwarf::DW_TAG_subprogram:
-  case dwarf::DW_TAG_label: {
-    isLiveSubprogramEntry(CU, Entry);
-  } break;
-  default:
-    // Nothing to do.
-    break;
-  }
+  // Set keep children property for parents.
+  markParentsAsKeepingChildren(Entry);
+
+  UnitEntryPairTy FinalRootEntry =
+      Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
 
   // Analyse referenced DIEs.
   bool Res = true;
-  if (!maybeAddReferencedRoots(RootItem, CU, Entry))
+  if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
+                               InterCUProcessingStarted,
+                               HasNewInterconnectedCUs))
     Res = false;
 
-  // Navigate children.
-  for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry);
+  // Return if we do not need to process children.
+  if (isSingleAction(Action))
+    return Res;
+
+  // Process children.
+  // Check for subprograms special case.
+  if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
+      Info.getODRAvailable()) {
+    // Subprograms is a special case. As it can be root for type DIEs
+    // and itself may be subject to move into the artificial type unit.
+    //  a) Non removable children(like DW_TAG_formal_parameter) should always
+    //     be cloned. They are placed into the "PlainDwarf" and into the
+    //     "TypeTable".
+    //  b) ODR deduplication candidates(type DIEs) children should not be put
+    //  into the "PlainDwarf".
+    //  c) Children keeping addresses and locations(like DW_TAG_call_site)
+    //  should not be put into the "TypeTable".
+    for (const DWARFDebugInfoEntry *CurChild =
+             Entry.CU->getFirstChildEntry(Entry.DieEntry);
+         CurChild && CurChild->getAbbreviationDeclarationPtr();
+         CurChild = Entry.CU->getSiblingEntry(CurChild)) {
+      CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
+
+      switch (CurChild->getTag()) {
+      case dwarf::DW_TAG_variable:
+      case dwarf::DW_TAG_constant:
+      case dwarf::DW_TAG_subprogram:
+      case dwarf::DW_TAG_label: {
+        if (ChildInfo.getHasAnAddress())
+          continue;
+      } break;
+
+      // Entries having following tags could not be removed from the subprogram.
+      case dwarf::DW_TAG_lexical_block:
+      case dwarf::DW_TAG_friend:
+      case dwarf::DW_TAG_inheritance:
+      case dwarf::DW_TAG_formal_parameter:
+      case dwarf::DW_TAG_unspecified_parameters:
+      case dwarf::DW_TAG_template_type_parameter:
+      case dwarf::DW_TAG_template_value_parameter:
+      case dwarf::DW_TAG_GNU_template_parameter_pack:
+      case dwarf::DW_TAG_GNU_formal_parameter_pack:
+      case dwarf::DW_TAG_GNU_template_template_param:
+      case dwarf::DW_TAG_thrown_type: {
+        // Go to the default child handling.
+      } break;
+
+      default: {
+        bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
+
+        // Skip child marked to be copied into the artificial type unit.
+        if (isLiveAction(Action) && ChildIsTypeTableCandidate)
+          continue;
+
+        // Skip child marked to be copied into the plain unit.
+        if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
+          continue;
+
+        // Go to the default child handling.
+      } break;
+      }
+
+      if (!markDIEEntryAsKeptRec(
+              Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
+              InterCUProcessingStarted, HasNewInterconnectedCUs))
+        Res = false;
+    }
+
+    return Res;
+  }
+
+  // Recursively process children.
+  for (const DWARFDebugInfoEntry *CurChild =
+           Entry.CU->getFirstChildEntry(Entry.DieEntry);
        CurChild && CurChild->getAbbreviationDeclarationPtr();
-       CurChild = CU.getSiblingEntry(CurChild)) {
-    if (!markDIEEntryAsKeptRec(RootItem, CU, CurChild))
+       CurChild = Entry.CU->getSiblingEntry(CurChild)) {
+    CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
+    switch (CurChild->getTag()) {
+    case dwarf::DW_TAG_variable:
+    case dwarf::DW_TAG_constant:
+    case dwarf::DW_TAG_subprogram:
+    case dwarf::DW_TAG_label: {
+      if (ChildInfo.getHasAnAddress())
+        continue;
+    } break;
+    default:
+      break; // Nothing to do.
+    };
+
+    if (!markDIEEntryAsKeptRec(
+            Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
+            InterCUProcessingStarted, HasNewInterconnectedCUs))
       Res = false;
   }
 
   return Res;
 }
 
+bool DependencyTracker::isTypeTableCandidate(
+    const DWARFDebugInfoEntry *DIEEntry) {
+  switch (DIEEntry->getTag()) {
+  default:
+    return false;
+
+  case dwarf::DW_TAG_imported_module:
+  case dwarf::DW_TAG_imported_declaration:
+  case dwarf::DW_TAG_imported_unit:
+  case dwarf::DW_TAG_array_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_enumeration_type:
+  case dwarf::DW_TAG_pointer_type:
+  case dwarf::DW_TAG_reference_type:
+  case dwarf::DW_TAG_string_type:
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_subroutine_type:
+  case dwarf::DW_TAG_typedef:
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_variant:
+  case dwarf::DW_TAG_module:
+  case dwarf::DW_TAG_ptr_to_member_type:
+  case dwarf::DW_TAG_set_type:
+  case dwarf::DW_TAG_subrange_type:
+  case dwarf::DW_TAG_base_type:
+  case dwarf::DW_TAG_const_type:
+  case dwarf::DW_TAG_enumerator:
+  case dwarf::DW_TAG_file_type:
+  case dwarf::DW_TAG_packed_type:
+  case dwarf::DW_TAG_thrown_type:
+  case dwarf::DW_TAG_volatile_type:
+  case dwarf::DW_TAG_dwarf_procedure:
+  case dwarf::DW_TAG_restrict_type:
+  case dwarf::DW_TAG_interface_type:
+  case dwarf::DW_TAG_namespace:
+  case dwarf::DW_TAG_unspecified_type:
+  case dwarf::DW_TAG_shared_type:
+  case dwarf::DW_TAG_rvalue_reference_type:
+  case dwarf::DW_TAG_coarray_type:
+  case dwarf::DW_TAG_dynamic_type:
+  case dwarf::DW_TAG_atomic_type:
+  case dwarf::DW_TAG_immutable_type:
+  case dwarf::DW_TAG_function_template:
+  case dwarf::DW_TAG_class_template:
+    return true;
+  }
+}
+
 bool DependencyTracker::maybeAddReferencedRoots(
-    const RootEntryTy &RootItem, CompileUnit &CU,
-    const DWARFDebugInfoEntry *Entry) {
-  const auto *Abbrev = Entry->getAbbreviationDeclarationPtr();
+    LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
+    const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
+    std::atomic<bool> &HasNewInterconnectedCUs) {
+  const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
   if (Abbrev == nullptr)
     return true;
 
-  DWARFUnit &Unit = CU.getOrigUnit();
+  DWARFUnit &Unit = Entry.CU->getOrigUnit();
   DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
-  uint64_t Offset = Entry->getOffset() + getULEB128Size(Abbrev->getCode());
+  uint64_t Offset =
+      Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
 
   // For each DIE attribute...
   for (const auto &AttrSpec : Abbrev->attributes()) {
@@ -220,132 +631,157 @@ bool DependencyTracker::maybeAddReferencedRoots(
     Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
 
     // Resolve reference.
-    std::optional<std::pair<CompileUnit *, uint32_t>> RefDie =
-        CU.resolveDIEReference(
-            Val, Context.InterCUProcessingStarted
-                     ? ResolveInterCUReferencesMode::Resolve
-                     : ResolveInterCUReferencesMode::AvoidResolving);
+    std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
+        Val, InterCUProcessingStarted
+                 ? ResolveInterCUReferencesMode::Resolve
+                 : ResolveInterCUReferencesMode::AvoidResolving);
     if (!RefDie) {
-      CU.warn("cann't find referenced DIE", Entry);
+      Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
       continue;
     }
 
-    if (RefDie->second == 0) {
+    if (!RefDie->DieEntry) {
       // Delay resolving reference.
-      RefDie->first->setInterconnectedCU();
-      CU.setInterconnectedCU();
-      Context.HasNewInterconnectedCUs = true;
+      RefDie->CU->setInterconnectedCU();
+      Entry.CU->setInterconnectedCU();
+      HasNewInterconnectedCUs = true;
       return false;
     }
 
-    assert(CU.getUniqueID() == RefDie->first->getUniqueID() ||
-           Context.InterCUProcessingStarted);
+    assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
+            InterCUProcessingStarted) &&
+           "Inter-CU reference while inter-CU processing is not started");
+
+    CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
+    if (!RefInfo.getODRAvailable())
+      Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
+    else if (RefInfo.getODRAvailable() &&
+             llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
+      // Note: getODRAttributes does not include DW_AT_containing_type.
+      // It should be OK as we do getRootForSpecifiedEntry(). So any containing
+      // type would be found as the root for the entry.
+      Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
+    else if (isLiveAction(Action))
+      Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
+    else
+      Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
+
+    if (AttrSpec.Attr == dwarf::DW_AT_import) {
+      if (isNamespaceLikeEntry(RefDie->DieEntry)) {
+        addActionToRootEntriesWorkList(
+            isTypeAction(Action)
+                ? LiveRootWorklistActionTy::MarkSingleTypeEntry
+                : LiveRootWorklistActionTy::MarkSingleLiveEntry,
+            *RefDie, RootEntry);
+        continue;
+      }
 
-    addItemToWorklist(*RefDie->first,
-                      RefDie->first->getDebugInfoEntry(RefDie->second));
+      addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
+      continue;
+    }
+
+    UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
+    addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
   }
 
   return true;
 }
 
-// Returns true if the specified DIE type allows removing children.
-static bool childrenCanBeRemoved(uint32_t Tag) {
-  switch (Tag) {
-  default:
-    return true;
-  case dwarf::DW_TAG_class_type:
-  case dwarf::DW_TAG_common_block:
-  case dwarf::DW_TAG_lexical_block:
-  case dwarf::DW_TAG_structure_type:
-  case dwarf::DW_TAG_subprogram:
-  case dwarf::DW_TAG_subroutine_type:
-  case dwarf::DW_TAG_union_type:
-  case dwarf::DW_TAG_array_type:
-    return false;
-  }
-  llvm_unreachable("Invalid Tag");
-}
-
-void DependencyTracker::addItemToWorklist(CompileUnit &CU,
-                                          const DWARFDebugInfoEntry *Entry) {
-  if (Entry->getAbbreviationDeclarationPtr() == nullptr)
-    return;
+UnitEntryPairTy
+DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {
+  UnitEntryPairTy Result = Entry;
+
+  do {
+    switch (Entry.DieEntry->getTag()) {
+    case dwarf::DW_TAG_subprogram:
+    case dwarf::DW_TAG_label:
+    case dwarf::DW_TAG_variable:
+    case dwarf::DW_TAG_constant: {
+      return Result;
+    } break;
+
+    default: {
+      // Nothing to do.
+    }
+    }
 
-  const DWARFDebugInfoEntry *EntryToAdd = Entry;
+    std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
+    if (!ParentIdx)
+      return Result;
 
-  // If parent does not allow children removing then use that parent as a root
-  // DIE.
-  std::optional<uint32_t> ParentIdx = Entry->getParentIdx();
-  while (ParentIdx) {
-    const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx);
-    if (childrenCanBeRemoved(ParentEntry->getTag()))
+    const DWARFDebugInfoEntry *ParentEntry =
+        Result.CU->getDebugInfoEntry(*ParentIdx);
+    if (isNamespaceLikeEntry(ParentEntry))
       break;
-    EntryToAdd = ParentEntry;
-    ParentIdx = ParentEntry->getParentIdx();
-  }
+    Result.DieEntry = ParentEntry;
+  } while (true);
 
-  // Check if the DIE entry is already kept.
-  if (CU.getDIEInfo(EntryToAdd).getKeep())
-    return;
-
-  RootEntriesWorkList.emplace_back(CU, EntryToAdd);
+  return Result;
 }
 
-bool DependencyTracker::isLiveVariableEntry(CompileUnit &CU,
-                                            const DWARFDebugInfoEntry *Entry) {
-  DWARFDie DIE = CU.getDIE(Entry);
-  CompileUnit::DIEInfo &Info = CU.getDIEInfo(DIE);
+bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,
+                                            bool IsLiveParent) {
+  DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
+  CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
 
-  if (TrackLiveness) {
+  if (Info.getTrackLiveness()) {
     const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
 
-    // Global variables with constant value can always be kept.
     if (!Info.getIsInFunctionScope() &&
-        Abbrev->findAttributeIndex(dwarf::DW_AT_const_value))
-      return true;
-
-    // See if there is a relocation to a valid debug map entry inside this
-    // variable's location. The order is important here. We want to always check
-    // if the variable has a location expression address.
-    // However, we don't want a static variable in a function to force us to
-    // keep the enclosing function, unless requested explicitly.
-    std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
-        CU.getContaingFile().Addresses->getVariableRelocAdjustment(DIE);
-
-    if (!LocExprAddrAndRelocAdjustment.second)
-      return false;
+        Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
+      // Global variables with constant value can always be kept.
+    } else {
+      // See if there is a relocation to a valid debug map entry inside this
+      // variable's location. The order is important here. We want to always
+      // check if the variable has a location expression address. However, we
+      // don't want a static variable in a function to force us to keep the
+      // enclosing function, unless requested explicitly.
+      std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
+          Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
+              DIE);
+
+      if (LocExprAddrAndRelocAdjustment.first)
+        Info.setHasAnAddress();
+
+      if (!LocExprAddrAndRelocAdjustment.second)
+        return false;
 
-    if ((Info.getIsInFunctionScope()) &&
-        !LLVM_UNLIKELY(CU.getGlobalData().getOptions().KeepFunctionForStatic))
-      return false;
+      if (!IsLiveParent && Info.getIsInFunctionScope() &&
+          !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
+        return false;
+    }
   }
+  Info.setHasAnAddress();
 
-  if (CU.getGlobalData().getOptions().Verbose) {
+  if (Entry.CU->getGlobalData().getOptions().Verbose) {
     outs() << "Keeping variable DIE:";
     DIDumpOptions DumpOpts;
     DumpOpts.ChildRecurseDepth = 0;
-    DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose;
+    DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
     DIE.dump(outs(), 8 /* Indent */, DumpOpts);
   }
 
   return true;
 }
 
-bool DependencyTracker::isLiveSubprogramEntry(
-    CompileUnit &CU, const DWARFDebugInfoEntry *Entry) {
-  DWARFDie DIE = CU.getDIE(Entry);
+bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {
+  DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
+  CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
+  std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
 
   std::optional<uint64_t> LowPc;
   std::optional<uint64_t> HighPc;
   std::optional<int64_t> RelocAdjustment;
-
-  if (TrackLiveness) {
-    LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc));
+  if (Info.getTrackLiveness()) {
+    LowPc = dwarf::toAddress(LowPCVal);
     if (!LowPc)
       return false;
 
+    Info.setHasAnAddress();
+
     RelocAdjustment =
-        CU.getContaingFile().Addresses->getSubprogramRelocAdjustment(DIE);
+        Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
+            DIE);
     if (!RelocAdjustment)
       return false;
 
@@ -354,16 +790,18 @@ bool DependencyTracker::isLiveSubprogramEntry(
 
       HighPc = DIE.getHighPC(*LowPc);
       if (!HighPc) {
-        CU.warn("function without high_pc. Range will be discarded.", &DIE);
+        Entry.CU->warn("function without high_pc. Range will be discarded.",
+                       &DIE);
         return false;
       }
 
       if (*LowPc > *HighPc) {
-        CU.warn("low_pc greater than high_pc. Range will be discarded.", &DIE);
+        Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
+                       &DIE);
         return false;
       }
-    } else if (DIE.getTag() == dwarf::DW_TAG_variable) {
-      if (CU.hasLabelAt(*LowPc))
+    } else if (DIE.getTag() == dwarf::DW_TAG_label) {
+      if (Entry.CU->hasLabelAt(*LowPc))
         return false;
 
       // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
@@ -371,33 +809,29 @@ bool DependencyTracker::isLiveSubprogramEntry(
       // info generation bugs aside, this is really wrong in the case of labels,
       // where a label marking the end of a function will have a PC == CU's
       // high_pc.
-      if (dwarf::toAddress(
-              CU.getOrigUnit().getUnitDIE().find(dwarf::DW_AT_high_pc))
+      if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
               .value_or(UINT64_MAX) <= LowPc)
         return false;
 
-      CU.addLabelLowPc(*LowPc, *RelocAdjustment);
+      Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
     }
-  }
+  } else
+    Info.setHasAnAddress();
 
-  if (CU.getGlobalData().getOptions().Verbose) {
+  if (Entry.CU->getGlobalData().getOptions().Verbose) {
     outs() << "Keeping subprogram DIE:";
     DIDumpOptions DumpOpts;
     DumpOpts.ChildRecurseDepth = 0;
-    DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose;
+    DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
     DIE.dump(outs(), 8 /* Indent */, DumpOpts);
   }
 
-  if (!TrackLiveness || DIE.getTag() == dwarf::DW_TAG_label)
+  if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
     return true;
 
-  CU.addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
+  Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
   return true;
 }
 
-void DependencyTracker::setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info) {
-  Info.setPlacement(CompileUnit::PlainDwarf);
-}
-
 } // end of namespace dwarflinker_parallel
 } // namespace llvm

diff  --git a/llvm/lib/DWARFLinkerParallel/DependencyTracker.h b/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
index 69e57bc3ea4d264..abd5371471eb95a 100644
--- a/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
+++ b/llvm/lib/DWARFLinkerParallel/DependencyTracker.h
@@ -10,7 +10,7 @@
 #define LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H
 
 #include "DWARFLinkerCompileUnit.h"
-#include "DWARFLinkerImpl.h"
+#include "llvm/ADT/PointerIntPair.h"
 #include "llvm/ADT/SmallVector.h"
 
 namespace llvm {
@@ -19,10 +19,12 @@ class DWARFDie;
 
 namespace dwarflinker_parallel {
 
-/// This class discovers DIEs dependencies and marks "live" DIEs.
+/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE
+/// locations (whether DIE should be cloned as regular DIE or it should be put
+/// into the artificial type unit).
 class DependencyTracker {
 public:
-  DependencyTracker(DWARFLinkerImpl::LinkContext &Context) : Context(Context) {}
+  DependencyTracker(CompileUnit &CU) : CU(CU) {}
 
   /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
   /// information in \p CU's DIEInfo.
@@ -30,70 +32,223 @@ class DependencyTracker {
   /// This function is the entry point of the DIE selection algorithm. It is
   /// expected to walk the DIE tree and(through the mediation of
   /// Context.File.Addresses) ask for relocation adjustment value on each
-  /// DIE that might be a 'root DIE'.
+  /// DIE that might be a 'root DIE'(f.e. subprograms, variables).
   ///
   /// Returns true if all dependencies are correctly discovered. Inter-CU
   /// dependencies cannot be discovered if referenced CU is not analyzed yet.
   /// If that is the case this method returns false.
-  bool resolveDependenciesAndMarkLiveness(CompileUnit &CU);
+  bool resolveDependenciesAndMarkLiveness(
+      bool InterCUProcessingStarted,
+      std::atomic<bool> &HasNewInterconnectedCUs);
 
-  /// Recursively walk the \p DIE tree and check "keepness" information.
-  /// It is an error if parent node does not have "keep" flag, while
-  /// child have one. This function dump error at stderr in that case.
-#ifndef NDEBUG
-  static void verifyKeepChain(CompileUnit &CU);
-#endif
+  /// Check if dependencies have incompatible placement.
+  /// If that is the case modify placement to be compatible.
+  /// \returns true if any placement was updated, otherwise returns false.
+  /// This method should be called as a followup processing after
+  /// resolveDependenciesAndMarkLiveness().
+  bool updateDependenciesCompleteness();
+
+  /// Recursively walk the \p DIE tree and check "keepness" and "placement"
+  /// information. It is an error if parent node does not have "keep" flag,
+  /// while child has one. It is an error if parent node has "TypeTable"
+  /// placement while child has "PlainDwarf" placement. This function dump error
+  /// at stderr in that case.
+  void verifyKeepChain();
 
 protected:
-  struct RootEntryTy {
-    RootEntryTy(CompileUnit &CU, const DWARFDebugInfoEntry *RootEntry)
-        : CU(CU), RootEntry(RootEntry) {}
+  enum class LiveRootWorklistActionTy : uint8_t {
+    /// Mark current item as live entry.
+    MarkSingleLiveEntry = 0,
+
+    /// Mark current item as type entry.
+    MarkSingleTypeEntry,
+
+    /// Mark current item and all its children as live entry.
+    MarkLiveEntryRec,
+
+    /// Mark current item and all its children as type entry.
+    MarkTypeEntryRec,
+
+    /// Mark all children of current item as live entry.
+    MarkLiveChildrenRec,
+
+    /// Mark all children of current item as type entry.
+    MarkTypeChildrenRec,
+  };
+
+  /// \returns true if the specified action is for the "PlainDwarf".
+  bool isLiveAction(LiveRootWorklistActionTy Action) {
+    switch (Action) {
+    default:
+      return false;
+
+    case LiveRootWorklistActionTy::MarkSingleLiveEntry:
+    case LiveRootWorklistActionTy::MarkLiveEntryRec:
+    case LiveRootWorklistActionTy::MarkLiveChildrenRec:
+      return true;
+    }
+  }
+
+  /// \returns true if the specified action is for the "TypeTable".
+  bool isTypeAction(LiveRootWorklistActionTy Action) {
+    switch (Action) {
+    default:
+      return false;
+
+    case LiveRootWorklistActionTy::MarkSingleTypeEntry:
+    case LiveRootWorklistActionTy::MarkTypeEntryRec:
+    case LiveRootWorklistActionTy::MarkTypeChildrenRec:
+      return true;
+    }
+  }
+
+  /// \returns true if the specified action affects only Root entry
+  /// itself and does not affect it`s children.
+  bool isSingleAction(LiveRootWorklistActionTy Action) {
+    switch (Action) {
+    default:
+      return false;
+
+    case LiveRootWorklistActionTy::MarkSingleLiveEntry:
+    case LiveRootWorklistActionTy::MarkSingleTypeEntry:
+      return true;
+    }
+  }
 
-    // Compile unit keeping root entry.
-    CompileUnit &CU;
+  /// \returns true if the specified action affects only Root entry
+  /// itself and does not affect it`s children.
+  bool isChildrenAction(LiveRootWorklistActionTy Action) {
+    switch (Action) {
+    default:
+      return false;
 
-    // Root entry.
-    const DWARFDebugInfoEntry *RootEntry;
+    case LiveRootWorklistActionTy::MarkLiveChildrenRec:
+    case LiveRootWorklistActionTy::MarkTypeChildrenRec:
+      return true;
+    }
+  }
+
+  /// Class keeping live worklist item data.
+  class LiveRootWorklistItemTy {
+  public:
+    LiveRootWorklistItemTy() = default;
+    LiveRootWorklistItemTy(const LiveRootWorklistItemTy &) = default;
+    LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
+                           UnitEntryPairTy RootEntry) {
+      RootCU.setInt(static_cast<uint8_t>(Action));
+      RootCU.setPointer(RootEntry.CU);
+
+      RootDieEntry = RootEntry.DieEntry;
+    }
+    LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
+                           UnitEntryPairTy RootEntry,
+                           UnitEntryPairTy ReferencedBy) {
+      RootCU.setPointer(RootEntry.CU);
+      RootCU.setInt(static_cast<uint8_t>(Action));
+      RootDieEntry = RootEntry.DieEntry;
+
+      ReferencedByCU = ReferencedBy.CU;
+      ReferencedByDieEntry = ReferencedBy.DieEntry;
+    }
+
+    UnitEntryPairTy getRootEntry() const {
+      return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry};
+    }
+
+    CompileUnit::DieOutputPlacement getPlacement() const {
+      return static_cast<CompileUnit::DieOutputPlacement>(RootCU.getInt());
+    }
+
+    bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; }
+
+    UnitEntryPairTy getReferencedByEntry() const {
+      assert(ReferencedByCU);
+      assert(ReferencedByDieEntry);
+      return UnitEntryPairTy{ReferencedByCU, ReferencedByDieEntry};
+    }
+
+    LiveRootWorklistActionTy getAction() const {
+      return static_cast<LiveRootWorklistActionTy>(RootCU.getInt());
+    }
+
+  protected:
+    /// Root entry.
+    /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
+    /// Thus LiveRootWorklistActionTy should have no more eight elements.
+    PointerIntPair<CompileUnit *, 3> RootCU;
+    const DWARFDebugInfoEntry *RootDieEntry = nullptr;
+
+    /// Another root entry which references this RootDieEntry.
+    /// ReferencedByDieEntry is kept to update placement.
+    /// if RootDieEntry has placement incompatible with placement
+    /// of ReferencedByDieEntry then it should be updated.
+    CompileUnit *ReferencedByCU = nullptr;
+    const DWARFDebugInfoEntry *ReferencedByDieEntry = nullptr;
   };
 
-  using RootEntriesListTy = SmallVector<RootEntryTy>;
+  using RootEntriesListTy = SmallVector<LiveRootWorklistItemTy>;
 
   /// This function navigates DIEs tree starting from specified \p Entry.
-  /// It puts 'root DIE' into the worklist.
-  void collectRootsToKeep(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+  /// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries
+  /// instructs to collect either live roots(like subprograms having live
+  /// DW_AT_low_pc) or otherwise roots which is not live(they need to be
+  /// collected if they are imported f.e. by DW_TAG_imported_module).
+  void collectRootsToKeep(const UnitEntryPairTy &Entry,
+                          std::optional<UnitEntryPairTy> ReferencedBy,
+                          bool IsLiveParent);
 
   /// Returns true if specified variable references live code section.
-  bool isLiveVariableEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+  static bool isLiveVariableEntry(const UnitEntryPairTy &Entry,
+                                  bool IsLiveParent);
 
   /// Returns true if specified subprogram references live code section.
-  bool isLiveSubprogramEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+  static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry);
 
-  /// Examine worklist and mark all 'root DIE's as kept.
-  bool markLiveRootsAsKept();
+  /// Examine worklist and mark all 'root DIE's as kept and set "Placement"
+  /// property.
+  bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,
+                                    std::atomic<bool> &HasNewInterconnectedCUs);
 
   /// Mark whole DIE tree as kept recursively.
-  bool markDIEEntryAsKeptRec(const RootEntryTy &RootItem, CompileUnit &CU,
-                             const DWARFDebugInfoEntry *Entry);
+  bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,
+                             const UnitEntryPairTy &RootEntry,
+                             const UnitEntryPairTy &Entry,
+                             bool InterCUProcessingStarted,
+                             std::atomic<bool> &HasNewInterconnectedCUs);
+
+  /// Mark parents as keeping children.
+  void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry);
+
+  /// Mark whole DIE tree as placed in "PlainDwarf".
+  void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry);
+
+  /// Check referenced DIEs and add them into the worklist.
+  bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action,
+                               const UnitEntryPairTy &RootEntry,
+                               const UnitEntryPairTy &Entry,
+                               bool InterCUProcessingStarted,
+                               std::atomic<bool> &HasNewInterconnectedCUs);
 
-  /// Check referenced DIEs and add them into the worklist if neccessary.
-  bool maybeAddReferencedRoots(const RootEntryTy &RootItem, CompileUnit &CU,
-                               const DWARFDebugInfoEntry *Entry);
+  /// \returns true if \p DIEEntry can possibly be put into the artificial type
+  /// unit.
+  bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry);
 
-  /// Add 'root DIE' into the worklist.
-  void addItemToWorklist(CompileUnit &CU, const DWARFDebugInfoEntry *Entry);
+  /// \returns root for the specified \p Entry.
+  UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry);
 
-  /// Set kind of placement(whether it goes into type table, plain dwarf or
-  /// both) for the specified die \p DieIdx.
-  void setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info);
+  /// Add action item to the work list.
+  void
+  addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,
+                                 const UnitEntryPairTy &Entry,
+                                 std::optional<UnitEntryPairTy> ReferencedBy);
 
-  /// Flag indicating whether liveness information should be examined.
-  bool TrackLiveness = false;
+  CompileUnit &CU;
 
-  /// List of CU, Entry pairs which are 'root DIE's.
+  /// List of entries which are 'root DIE's.
   RootEntriesListTy RootEntriesWorkList;
 
-  /// Link context for the analyzed CU.
-  DWARFLinkerImpl::LinkContext &Context;
+  /// List of entries dependencies.
+  RootEntriesListTy Dependencies;
 };
 
 } // end namespace dwarflinker_parallel

diff  --git a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp
index 8e7caa7bb407425..9c3e3ebd220aaf4 100644
--- a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp
+++ b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp
@@ -8,6 +8,7 @@
 
 #include "OutputSections.h"
 #include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerTypeUnit.h"
 #include "llvm/ADT/StringSwitch.h"
 
 namespace llvm {
@@ -92,6 +93,33 @@ DebugULEB128DieRefPatch::DebugULEB128DieRefPatch(uint64_t PatchOffset,
       RefCU(RefCU, SrcCU->getUniqueID() == RefCU->getUniqueID()),
       RefDieIdxOrClonedOffset(RefIdx) {}
 
+DebugDieTypeRefPatch::DebugDieTypeRefPatch(uint64_t PatchOffset,
+                                           TypeEntry *RefTypeName)
+    : SectionPatch({PatchOffset}), RefTypeName(RefTypeName) {}
+
+DebugType2TypeDieRefPatch::DebugType2TypeDieRefPatch(uint64_t PatchOffset,
+                                                     DIE *Die,
+                                                     TypeEntry *TypeName,
+                                                     TypeEntry *RefTypeName)
+    : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+      RefTypeName(RefTypeName) {}
+
+DebugTypeStrPatch::DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die,
+                                     TypeEntry *TypeName, StringEntry *String)
+    : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+      String(String) {}
+
+DebugTypeLineStrPatch::DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die,
+                                             TypeEntry *TypeName,
+                                             StringEntry *String)
+    : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+      String(String) {}
+
+DebugTypeDeclFilePatch::DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName,
+                                               StringEntry *Directory,
+                                               StringEntry *FilePath)
+    : Die(Die), TypeName(TypeName), Directory(Directory), FilePath(FilePath) {}
+
 void SectionDescriptor::clearAllSectionData() {
   StartOffset = 0;
   clearSectionContent();
@@ -102,6 +130,10 @@ void SectionDescriptor::clearAllSectionData() {
   ListDebugDieRefPatch.erase();
   ListDebugULEB128DieRefPatch.erase();
   ListDebugOffsetPatch.erase();
+  ListDebugType2TypeDieRefPatch.erase();
+  ListDebugTypeDeclFilePatch.erase();
+  ListDebugTypeLineStrPatch.erase();
+  ListDebugTypeStrPatch.erase();
 }
 
 void SectionDescriptor::clearSectionContent() { Contents = OutSectionDataTy(); }
@@ -144,6 +176,30 @@ void SectionDescriptor::setSizesForSectionCreatedByAsmPrinter() {
   }
 }
 
+void SectionDescriptor::emitString(dwarf::Form StringForm,
+                                   const char *StringVal) {
+  assert(StringVal != nullptr);
+
+  switch (StringForm) {
+  case dwarf::DW_FORM_string: {
+    emitInplaceString(StringVal);
+  } break;
+  case dwarf::DW_FORM_strp: {
+    notePatch(DebugStrPatch{
+        {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
+    emitStringPlaceholder();
+  } break;
+  case dwarf::DW_FORM_line_strp: {
+    notePatch(DebugLineStrPatch{
+        {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
+    emitStringPlaceholder();
+  } break;
+  default:
+    llvm_unreachable("Unsupported string form");
+    break;
+  };
+}
+
 void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) {
   switch (Size) {
   case 1: {
@@ -171,30 +227,6 @@ void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) {
   }
 }
 
-void SectionDescriptor::emitString(dwarf::Form StringForm,
-                                   const char *StringVal) {
-  assert(StringVal != nullptr);
-
-  switch (StringForm) {
-  case dwarf::DW_FORM_string: {
-    emitInplaceString(StringVal);
-  } break;
-  case dwarf::DW_FORM_strp: {
-    notePatch(DebugStrPatch{
-        {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
-    emitStringPlaceholder();
-  } break;
-  case dwarf::DW_FORM_line_strp: {
-    notePatch(DebugLineStrPatch{
-        {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
-    emitStringPlaceholder();
-  } break;
-  default:
-    llvm_unreachable("Unsupported string form");
-    break;
-  };
-}
-
 void SectionDescriptor::apply(uint64_t PatchOffset, dwarf::Form AttrForm,
                               uint64_t Val) {
   switch (AttrForm) {
@@ -330,8 +362,8 @@ void SectionDescriptor::applySLEB128(uint64_t PatchOffset, uint64_t Val) {
 void OutputSections::applyPatches(
     SectionDescriptor &Section,
     StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
-    StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings) {
-
+    StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
+    TypeUnit *TypeUnitPtr) {
   Section.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {
     DwarfStringPoolEntryWithExtString *Entry =
         DebugStrStrings.getExistingEntry(Patch.String);
@@ -339,6 +371,26 @@ void OutputSections::applyPatches(
 
     Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
   });
+  Section.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) {
+    assert(TypeUnitPtr != nullptr);
+    TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+    assert(TypeEntry &&
+           formatv("No data for type {0}", Patch.TypeName->getKey())
+               .str()
+               .c_str());
+
+    if (&TypeEntry->getFinalDie() != Patch.Die)
+      return;
+
+    DwarfStringPoolEntryWithExtString *Entry =
+        DebugStrStrings.getExistingEntry(Patch.String);
+    assert(Entry != nullptr);
+
+    Patch.PatchOffset +=
+        Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber());
+
+    Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
+  });
 
   Section.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {
     DwarfStringPoolEntryWithExtString *Entry =
@@ -347,6 +399,26 @@ void OutputSections::applyPatches(
 
     Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
   });
+  Section.ListDebugTypeLineStrPatch.forEach([&](DebugTypeLineStrPatch &Patch) {
+    assert(TypeUnitPtr != nullptr);
+    TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+    assert(TypeEntry &&
+           formatv("No data for type {0}", Patch.TypeName->getKey())
+               .str()
+               .c_str());
+
+    if (&TypeEntry->getFinalDie() != Patch.Die)
+      return;
+
+    DwarfStringPoolEntryWithExtString *Entry =
+        DebugLineStrStrings.getExistingEntry(Patch.String);
+    assert(Entry != nullptr);
+
+    Patch.PatchOffset +=
+        Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber());
+
+    Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
+  });
 
   std::optional<SectionDescriptor *> RangeSection;
   if (Format.Version >= 5)
@@ -404,6 +476,46 @@ void OutputSections::applyPatches(
                       Patch.RefDieIdxOrClonedOffset);
       });
 
+  Section.ListDebugDieTypeRefPatch.forEach([&](DebugDieTypeRefPatch &Patch) {
+    assert(TypeUnitPtr != nullptr);
+    assert(Patch.RefTypeName != nullptr);
+
+    TypeEntryBody *TypeEntry = Patch.RefTypeName->getValue().load();
+    assert(TypeEntry &&
+           formatv("No data for type {0}", Patch.RefTypeName->getKey())
+               .str()
+               .c_str());
+
+    Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref_addr,
+                  TypeEntry->getFinalDie().getOffset());
+  });
+
+  Section.ListDebugType2TypeDieRefPatch.forEach(
+      [&](DebugType2TypeDieRefPatch &Patch) {
+        assert(TypeUnitPtr != nullptr);
+        TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+        assert(TypeEntry &&
+               formatv("No data for type {0}", Patch.TypeName->getKey())
+                   .str()
+                   .c_str());
+
+        if (&TypeEntry->getFinalDie() != Patch.Die)
+          return;
+
+        Patch.PatchOffset += Patch.Die->getOffset() +
+                             getULEB128Size(Patch.Die->getAbbrevNumber());
+
+        assert(Patch.RefTypeName != nullptr);
+        TypeEntryBody *RefTypeEntry = Patch.RefTypeName->getValue().load();
+        assert(TypeEntry &&
+               formatv("No data for type {0}", Patch.RefTypeName->getKey())
+                   .str()
+                   .c_str());
+
+        Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref4,
+                      RefTypeEntry->getFinalDie().getOffset());
+      });
+
   Section.ListDebugOffsetPatch.forEach([&](DebugOffsetPatch &Patch) {
     uint64_t FinalValue = Patch.SectionPtr.getPointer()->StartOffset;
 

diff  --git a/llvm/lib/DWARFLinkerParallel/OutputSections.h b/llvm/lib/DWARFLinkerParallel/OutputSections.h
index b101ac61935c5cf..f23b2efb869da8e 100644
--- a/llvm/lib/DWARFLinkerParallel/OutputSections.h
+++ b/llvm/lib/DWARFLinkerParallel/OutputSections.h
@@ -31,6 +31,8 @@
 namespace llvm {
 namespace dwarflinker_parallel {
 
+class TypeUnit;
+
 /// List of tracked debug tables.
 enum class DebugSectionKind : uint8_t {
   DebugInfo = 0,
@@ -113,7 +115,7 @@ struct DebugDieRefPatch : SectionPatch {
                    uint32_t RefIdx);
 
   PointerIntPair<CompileUnit *, 1> RefCU;
-  uint64_t RefDieIdxOrClonedOffset;
+  uint64_t RefDieIdxOrClonedOffset = 0;
 };
 
 /// This structure is used to update reference to the DIE of ULEB128 form.
@@ -122,7 +124,53 @@ struct DebugULEB128DieRefPatch : SectionPatch {
                           CompileUnit *RefCU, uint32_t RefIdx);
 
   PointerIntPair<CompileUnit *, 1> RefCU;
-  uint64_t RefDieIdxOrClonedOffset;
+  uint64_t RefDieIdxOrClonedOffset = 0;
+};
+
+/// This structure is used to update reference to the type DIE.
+struct DebugDieTypeRefPatch : SectionPatch {
+  DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName);
+
+  TypeEntry *RefTypeName = nullptr;
+};
+
+/// This structure is used to update reference to the type DIE.
+struct DebugType2TypeDieRefPatch : SectionPatch {
+  DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+                            TypeEntry *RefTypeName);
+
+  DIE *Die = nullptr;
+  TypeEntry *TypeName = nullptr;
+  TypeEntry *RefTypeName = nullptr;
+};
+
+struct DebugTypeStrPatch : SectionPatch {
+  DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+                    StringEntry *String);
+
+  DIE *Die = nullptr;
+  TypeEntry *TypeName = nullptr;
+  StringEntry *String = nullptr;
+};
+
+struct DebugTypeLineStrPatch : SectionPatch {
+  DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,
+                        StringEntry *String);
+
+  DIE *Die = nullptr;
+  TypeEntry *TypeName = nullptr;
+  StringEntry *String = nullptr;
+};
+
+struct DebugTypeDeclFilePatch {
+  DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory,
+                         StringEntry *FilePath);
+
+  DIE *Die = nullptr;
+  TypeEntry *TypeName = nullptr;
+  StringEntry *Directory = nullptr;
+  StringEntry *FilePath = nullptr;
+  uint32_t FileID = 0;
 };
 
 /// Type for section data.
@@ -140,16 +188,20 @@ struct SectionDescriptor {
 
   SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,
                     dwarf::FormParams Format, llvm::endianness Endianess)
-      : OS(Contents), GlobalData(GlobalData), SectionKind(SectionKind),
-        Format(Format), Endianess(Endianess) {
-    ListDebugStrPatch.setAllocator(&GlobalData.getAllocator());
-    ListDebugLineStrPatch.setAllocator(&GlobalData.getAllocator());
-    ListDebugRangePatch.setAllocator(&GlobalData.getAllocator());
-    ListDebugLocPatch.setAllocator(&GlobalData.getAllocator());
-    ListDebugDieRefPatch.setAllocator(&GlobalData.getAllocator());
-    ListDebugULEB128DieRefPatch.setAllocator(&GlobalData.getAllocator());
-    ListDebugOffsetPatch.setAllocator(&GlobalData.getAllocator());
-  }
+      : OS(Contents), ListDebugStrPatch(&GlobalData.getAllocator()),
+        ListDebugLineStrPatch(&GlobalData.getAllocator()),
+        ListDebugRangePatch(&GlobalData.getAllocator()),
+        ListDebugLocPatch(&GlobalData.getAllocator()),
+        ListDebugDieRefPatch(&GlobalData.getAllocator()),
+        ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()),
+        ListDebugOffsetPatch(&GlobalData.getAllocator()),
+        ListDebugDieTypeRefPatch(&GlobalData.getAllocator()),
+        ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()),
+        ListDebugTypeStrPatch(&GlobalData.getAllocator()),
+        ListDebugTypeLineStrPatch(&GlobalData.getAllocator()),
+        ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()),
+        GlobalData(GlobalData), SectionKind(SectionKind), Format(Format),
+        Endianess(Endianess) {}
 
   /// Erase whole section contents(data bits, list of patches).
   void clearAllSectionData();
@@ -178,9 +230,16 @@ struct SectionDescriptor {
   ADD_PATCHES_LIST(DebugDieRefPatch)
   ADD_PATCHES_LIST(DebugULEB128DieRefPatch)
   ADD_PATCHES_LIST(DebugOffsetPatch)
-
-  /// Offsets to some fields are not known at the moment of noting patch.
-  /// In that case we remember pointers to patch offset to update them later.
+  ADD_PATCHES_LIST(DebugDieTypeRefPatch)
+  ADD_PATCHES_LIST(DebugType2TypeDieRefPatch)
+  ADD_PATCHES_LIST(DebugTypeStrPatch)
+  ADD_PATCHES_LIST(DebugTypeLineStrPatch)
+  ADD_PATCHES_LIST(DebugTypeDeclFilePatch)
+
+  /// While creating patches, offsets to attributes may be partially
+  /// unknown(because size of abbreviation number is unknown). In such case we
+  /// remember patch itself and pointer to patch application offset to add size
+  /// of abbreviation number later.
   template <typename T>
   void notePatchWithOffsetUpdate(const T &Patch,
                                  OffsetsPtrVector &PatchesOffsetsList) {
@@ -222,7 +281,6 @@ struct SectionDescriptor {
   /// Emit specified integer value into the current section contents.
   void emitIntVal(uint64_t Val, unsigned Size);
 
-  /// Emit specified string value into the current section contents.
   void emitString(dwarf::Form StringForm, const char *StringVal);
 
   /// Emit specified inplace string value into the current section contents.
@@ -395,7 +453,8 @@ class OutputSections {
   /// Enumerate all sections, for each section apply all section patches.
   void applyPatches(SectionDescriptor &Section,
                     StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
-                    StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings);
+                    StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
+                    TypeUnit *TypeUnitPtr);
 
   /// Endiannes for the sections.
   llvm::endianness getEndianness() const { return Endianness; }

diff  --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
new file mode 100644
index 000000000000000..e0900f7a8e3d3eb
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp
@@ -0,0 +1,767 @@
+//===- SyntheticTypeNameBuilder.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SyntheticTypeNameBuilder.h"
+#include "DWARFLinkerCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+Error SyntheticTypeNameBuilder::assignName(
+    UnitEntryPairTy InputUnitEntryPair,
+    std::optional<std::pair<size_t, size_t>> ChildIndex) {
+  [[maybe_unused]] const CompileUnit::DIEInfo &Info =
+      InputUnitEntryPair.CU->getDIEInfo(InputUnitEntryPair.DieEntry);
+  assert(Info.needToPlaceInTypeTable() &&
+         "Cann't assign name for non-type DIE");
+
+  if (InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry) !=
+      nullptr)
+    return Error::success();
+
+  SyntheticName.resize(0);
+  RecursionDepth = 0;
+  return addDIETypeName(InputUnitEntryPair, ChildIndex, true);
+}
+
+void SyntheticTypeNameBuilder::addArrayDimension(
+    UnitEntryPairTy InputUnitEntryPair) {
+  for (const DWARFDebugInfoEntry *CurChild =
+           InputUnitEntryPair.CU->getFirstChildEntry(
+               InputUnitEntryPair.DieEntry);
+       CurChild && CurChild->getAbbreviationDeclarationPtr();
+       CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) {
+    if (CurChild->getTag() == dwarf::DW_TAG_subrange_type ||
+        CurChild->getTag() == dwarf::DW_TAG_generic_subrange) {
+      SyntheticName += "[";
+      if (std::optional<DWARFFormValue> Val =
+              InputUnitEntryPair.CU->find(CurChild, dwarf::DW_AT_count)) {
+        if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant()) {
+          SyntheticName += std::to_string(*ConstVal);
+        } else if (std::optional<int64_t> ConstVal =
+                       Val->getAsSignedConstant()) {
+          SyntheticName += std::to_string(*ConstVal);
+        }
+      }
+
+      SyntheticName += "]";
+    }
+  }
+}
+
+static dwarf::Attribute TypeAttr[] = {dwarf::DW_AT_type};
+Error SyntheticTypeNameBuilder::addSignature(UnitEntryPairTy InputUnitEntryPair,
+                                             bool addTemplateParameters) {
+  // Add entry type.
+  if (Error Err = addReferencedODRDies(InputUnitEntryPair, false, TypeAttr))
+    return Err;
+  SyntheticName += ':';
+
+  SmallVector<const DWARFDebugInfoEntry *, 10> TemplateParameters;
+  SmallVector<const DWARFDebugInfoEntry *, 20> FunctionParameters;
+  for (const DWARFDebugInfoEntry *CurChild =
+           InputUnitEntryPair.CU->getFirstChildEntry(
+               InputUnitEntryPair.DieEntry);
+       CurChild && CurChild->getAbbreviationDeclarationPtr();
+       CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) {
+    dwarf::Tag ChildTag = CurChild->getTag();
+    if (addTemplateParameters &&
+        (ChildTag == dwarf::DW_TAG_template_type_parameter ||
+         ChildTag == dwarf::DW_TAG_template_value_parameter))
+      TemplateParameters.push_back(CurChild);
+    else if (ChildTag == dwarf::DW_TAG_formal_parameter ||
+             ChildTag == dwarf::DW_TAG_unspecified_parameters)
+      FunctionParameters.push_back(CurChild);
+    else if (addTemplateParameters &&
+             ChildTag == dwarf::DW_TAG_GNU_template_parameter_pack) {
+      for (const DWARFDebugInfoEntry *CurGNUChild =
+               InputUnitEntryPair.CU->getFirstChildEntry(CurChild);
+           CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr();
+           CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild))
+        TemplateParameters.push_back(CurGNUChild);
+    } else if (ChildTag == dwarf::DW_TAG_GNU_formal_parameter_pack) {
+      for (const DWARFDebugInfoEntry *CurGNUChild =
+               InputUnitEntryPair.CU->getFirstChildEntry(CurChild);
+           CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr();
+           CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild))
+        FunctionParameters.push_back(CurGNUChild);
+    }
+  }
+
+  // Add parameters.
+  if (Error Err = addParamNames(*InputUnitEntryPair.CU, FunctionParameters))
+    return Err;
+
+  // Add template parameters.
+  if (Error Err =
+          addTemplateParamNames(*InputUnitEntryPair.CU, TemplateParameters))
+    return Err;
+
+  return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addParamNames(
+    CompileUnit &CU,
+    SmallVector<const DWARFDebugInfoEntry *, 20> &FunctionParameters) {
+  SyntheticName += '(';
+  for (const DWARFDebugInfoEntry *FunctionParameter : FunctionParameters) {
+    if (SyntheticName.back() != '(')
+      SyntheticName += ", ";
+    if (dwarf::toUnsigned(CU.find(FunctionParameter, dwarf::DW_AT_artificial),
+                          0))
+      SyntheticName += "^";
+    if (Error Err = addReferencedODRDies(
+            UnitEntryPairTy{&CU, FunctionParameter}, false, TypeAttr))
+      return Err;
+  }
+  SyntheticName += ')';
+  return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addTemplateParamNames(
+    CompileUnit &CU,
+    SmallVector<const DWARFDebugInfoEntry *, 10> &TemplateParameters) {
+  if (!TemplateParameters.empty()) {
+    SyntheticName += '<';
+    for (const DWARFDebugInfoEntry *Parameter : TemplateParameters) {
+      if (SyntheticName.back() != '<')
+        SyntheticName += ", ";
+
+      if (Parameter->getTag() == dwarf::DW_TAG_template_value_parameter) {
+        if (std::optional<DWARFFormValue> Val =
+                CU.find(Parameter, dwarf::DW_AT_const_value)) {
+          if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant())
+            SyntheticName += std::to_string(*ConstVal);
+          else if (std::optional<int64_t> ConstVal = Val->getAsSignedConstant())
+            SyntheticName += std::to_string(*ConstVal);
+        }
+      }
+
+      if (Error Err = addReferencedODRDies(UnitEntryPairTy{&CU, Parameter},
+                                           false, TypeAttr))
+        return Err;
+    }
+    SyntheticName += '>';
+  }
+  return Error::success();
+}
+
+void SyntheticTypeNameBuilder::addOrderedName(
+    std::pair<size_t, size_t> ChildIdx) {
+  std::string Name;
+  llvm::raw_string_ostream stream(Name);
+  stream << format_hex_no_prefix(ChildIdx.first, ChildIdx.second);
+  SyntheticName += Name;
+}
+
+// Examine DIE and return type deduplication candidate: some DIEs could not be
+// deduplicated, namespace may refer to another namespace.
+static std::optional<UnitEntryPairTy>
+getTypeDeduplicationCandidate(UnitEntryPairTy UnitEntryPair) {
+  switch (UnitEntryPair.DieEntry->getTag()) {
+  case dwarf::DW_TAG_null:
+  case dwarf::DW_TAG_compile_unit:
+  case dwarf::DW_TAG_partial_unit:
+  case dwarf::DW_TAG_type_unit:
+  case dwarf::DW_TAG_skeleton_unit: {
+    return std::nullopt;
+  }
+  case dwarf::DW_TAG_namespace: {
+    // Check if current namespace refers another.
+    if (UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_extension))
+      UnitEntryPair = UnitEntryPair.getNamespaceOrigin();
+
+    // Content of anonimous namespaces should not be deduplicated.
+    if (!UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_name))
+      llvm_unreachable("Cann't deduplicate anonimous namespace");
+
+    return UnitEntryPair;
+  }
+  default:
+    return UnitEntryPair;
+  }
+}
+
+Error SyntheticTypeNameBuilder::addParentName(
+    UnitEntryPairTy &InputUnitEntryPair) {
+  std::optional<UnitEntryPairTy> UnitEntryPair = InputUnitEntryPair.getParent();
+  if (!UnitEntryPair)
+    return Error::success();
+
+  UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair);
+  if (!UnitEntryPair)
+    return Error::success();
+
+  if (TypeEntry *ImmediateParentName =
+          UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry)) {
+    SyntheticName += ImmediateParentName->getKey();
+    SyntheticName += ".";
+    return Error::success();
+  }
+
+  // Collect parent entries.
+  SmallVector<UnitEntryPairTy, 10> Parents;
+  do {
+    Parents.push_back(*UnitEntryPair);
+
+    UnitEntryPair = UnitEntryPair->getParent();
+    if (!UnitEntryPair)
+      break;
+
+    UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair);
+    if (!UnitEntryPair)
+      break;
+
+  } while (!UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry));
+
+  // Assign name for each parent entry.
+  size_t NameStart = SyntheticName.size();
+  for (UnitEntryPairTy Parent : reverse(Parents)) {
+    SyntheticName.resize(NameStart);
+    if (Error Err = addDIETypeName(Parent, std::nullopt, true))
+      return Err;
+  }
+
+  // Add parents delimiter.
+  SyntheticName += ".";
+  return Error::success();
+}
+
+void SyntheticTypeNameBuilder::addDieNameFromDeclFileAndDeclLine(
+    UnitEntryPairTy &InputUnitEntryPair, bool &HasDeclFileName) {
+  if (std::optional<DWARFFormValue> DeclFileVal = InputUnitEntryPair.CU->find(
+          InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_file)) {
+    if (std::optional<DWARFFormValue> DeclLineVal = InputUnitEntryPair.CU->find(
+            InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_line)) {
+      if (std::optional<std::pair<StringRef, StringRef>> DirAndFilename =
+              InputUnitEntryPair.CU->getDirAndFilenameFromLineTable(
+                  *DeclFileVal)) {
+        SyntheticName += DirAndFilename->first;
+        SyntheticName += DirAndFilename->second;
+
+        if (std::optional<uint64_t> DeclLineIntVal =
+                dwarf::toUnsigned(*DeclLineVal)) {
+          SyntheticName += " ";
+          SyntheticName += utohexstr(*DeclLineIntVal);
+        }
+
+        HasDeclFileName = true;
+      }
+    }
+  }
+}
+
+void SyntheticTypeNameBuilder::addValueName(UnitEntryPairTy InputUnitEntryPair,
+                                            dwarf::Attribute Attr) {
+  if (std::optional<DWARFFormValue> Val =
+          InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) {
+    if (std::optional<uint64_t> ConstVal = Val->getAsUnsignedConstant()) {
+      SyntheticName += " ";
+      SyntheticName += std::to_string(*ConstVal);
+    } else if (std::optional<int64_t> ConstVal = Val->getAsSignedConstant()) {
+      SyntheticName += " ";
+      SyntheticName += std::to_string(*ConstVal);
+    }
+  }
+}
+
+Error SyntheticTypeNameBuilder::addReferencedODRDies(
+    UnitEntryPairTy InputUnitEntryPair, bool AssignNameToTypeDescriptor,
+    ArrayRef<dwarf::Attribute> ODRAttrs) {
+  bool FirstIteration = true;
+  for (dwarf::Attribute Attr : ODRAttrs) {
+    if (std::optional<DWARFFormValue> AttrValue =
+            InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) {
+      std::optional<UnitEntryPairTy> RefDie =
+          InputUnitEntryPair.CU->resolveDIEReference(
+              *AttrValue, ResolveInterCUReferencesMode::Resolve);
+
+      if (!RefDie)
+        continue;
+
+      if (!RefDie->DieEntry)
+        return createStringError(std::errc::invalid_argument,
+                                 "Cann't resolve DIE reference");
+
+      if (!FirstIteration)
+        SyntheticName += ",";
+
+      RecursionDepth++;
+      if (RecursionDepth > 1000)
+        return createStringError(
+            std::errc::invalid_argument,
+            "Cann't parse input DWARF. Recursive dependence.");
+
+      if (Error Err =
+              addDIETypeName(*RefDie, std::nullopt, AssignNameToTypeDescriptor))
+        return Err;
+      RecursionDepth--;
+      FirstIteration = false;
+    }
+  }
+
+  return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addTypeName(UnitEntryPairTy InputUnitEntryPair,
+                                            bool AddParentNames) {
+  bool HasLinkageName = false;
+  bool HasShortName = false;
+  bool HasTemplatesInShortName = false;
+  bool HasDeclFileName = false;
+
+  // Try to get name from the DIE.
+  if (std::optional<DWARFFormValue> Val = InputUnitEntryPair.CU->find(
+          InputUnitEntryPair.DieEntry,
+          {dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_AT_linkage_name})) {
+    // Firstly check for linkage name.
+    SyntheticName += dwarf::toStringRef(Val);
+    HasLinkageName = true;
+  } else if (std::optional<DWARFFormValue> Val = InputUnitEntryPair.CU->find(
+                 InputUnitEntryPair.DieEntry, dwarf::DW_AT_name)) {
+    // Then check for short name.
+    StringRef Name = dwarf::toStringRef(Val);
+    SyntheticName += Name;
+
+    HasShortName = true;
+    HasTemplatesInShortName =
+        Name.endswith(">") && Name.count("<") != 0 && !Name.endswith("<=>");
+  } else {
+    // Finally check for declaration attributes.
+    addDieNameFromDeclFileAndDeclLine(InputUnitEntryPair, HasDeclFileName);
+  }
+
+  // Add additional name parts for some DIEs.
+  switch (InputUnitEntryPair.DieEntry->getTag()) {
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_interface_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_subroutine_type:
+  case dwarf::DW_TAG_subprogram: {
+    if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry,
+                                    dwarf::DW_AT_artificial))
+      SyntheticName += "^";
+
+    // No need to add signature information for linkage name,
+    // also no need to add template parameters name if short name already
+    // includes them.
+    if (!HasLinkageName)
+      if (Error Err =
+              addSignature(InputUnitEntryPair, !HasTemplatesInShortName))
+        return Err;
+  } break;
+  case dwarf::DW_TAG_coarray_type:
+  case dwarf::DW_TAG_array_type: {
+    addArrayDimension(InputUnitEntryPair);
+  } break;
+  case dwarf::DW_TAG_subrange_type: {
+    addValueName(InputUnitEntryPair, dwarf::DW_AT_count);
+  } break;
+  case dwarf::DW_TAG_template_value_parameter: {
+    if (!HasTemplatesInShortName) {
+      // TODO add support for DW_AT_location
+      addValueName(InputUnitEntryPair, dwarf::DW_AT_const_value);
+    }
+  } break;
+  default: {
+    // Nothing to do.
+  } break;
+  }
+
+  // If name for the DIE is not determined yet add referenced types to the name.
+  if (!HasLinkageName && !HasShortName && !HasDeclFileName) {
+    if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry,
+                                    getODRAttributes()))
+      if (Error Err = addReferencedODRDies(InputUnitEntryPair, AddParentNames,
+                                           getODRAttributes()))
+        return Err;
+  }
+
+  return Error::success();
+}
+
+Error SyntheticTypeNameBuilder::addDIETypeName(
+    UnitEntryPairTy InputUnitEntryPair,
+    std::optional<std::pair<size_t, size_t>> ChildIndex,
+    bool AssignNameToTypeDescriptor) {
+  std::optional<UnitEntryPairTy> UnitEntryPair =
+      getTypeDeduplicationCandidate(InputUnitEntryPair);
+  if (!UnitEntryPair)
+    return Error::success();
+
+  TypeEntry *TypeEntryPtr =
+      InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry);
+  // Check if DIE already has a name.
+  if (!TypeEntryPtr) {
+    size_t NameStart = SyntheticName.size();
+    if (AssignNameToTypeDescriptor) {
+      if (Error Err = addParentName(*UnitEntryPair))
+        return Err;
+    }
+    addTypePrefix(UnitEntryPair->DieEntry);
+
+    if (ChildIndex) {
+      addOrderedName(*ChildIndex);
+    } else {
+      if (Error Err = addTypeName(*UnitEntryPair, AssignNameToTypeDescriptor))
+        return Err;
+    }
+
+    if (AssignNameToTypeDescriptor) {
+      // Add built name to the DIE.
+      TypeEntryPtr = TypePoolRef.insert(SyntheticName.substr(NameStart));
+      InputUnitEntryPair.CU->setDieTypeEntry(InputUnitEntryPair.DieEntry,
+                                             TypeEntryPtr);
+    }
+  } else
+    SyntheticName += TypeEntryPtr->getKey();
+
+  return Error::success();
+}
+
+void SyntheticTypeNameBuilder::addTypePrefix(
+    const DWARFDebugInfoEntry *DieEntry) {
+  switch (DieEntry->getTag()) {
+  case dwarf::DW_TAG_base_type: {
+    SyntheticName += "{0}";
+  } break;
+  case dwarf::DW_TAG_namespace: {
+    SyntheticName += "{1}";
+  } break;
+  case dwarf::DW_TAG_formal_parameter: {
+    SyntheticName += "{2}";
+  } break;
+  // dwarf::DW_TAG_unspecified_parameters have the same prefix as before.
+  case dwarf::DW_TAG_unspecified_parameters: {
+    SyntheticName += "{2}";
+  } break;
+  case dwarf::DW_TAG_template_type_parameter: {
+    SyntheticName += "{3}";
+  } break;
+  // dwarf::DW_TAG_template_value_parameter have the same prefix as before.
+  case dwarf::DW_TAG_template_value_parameter: {
+    SyntheticName += "{3}";
+  } break;
+  case dwarf::DW_TAG_GNU_formal_parameter_pack: {
+    SyntheticName += "{4}";
+  } break;
+  case dwarf::DW_TAG_GNU_template_parameter_pack: {
+    SyntheticName += "{5}";
+  } break;
+  case dwarf::DW_TAG_inheritance: {
+    SyntheticName += "{6}";
+  } break;
+  case dwarf::DW_TAG_array_type: {
+    SyntheticName += "{7}";
+  } break;
+  case dwarf::DW_TAG_class_type: {
+    SyntheticName += "{8}";
+  } break;
+  case dwarf::DW_TAG_enumeration_type: {
+    SyntheticName += "{9}";
+  } break;
+  case dwarf::DW_TAG_imported_declaration: {
+    SyntheticName += "{A}";
+  } break;
+  case dwarf::DW_TAG_member: {
+    SyntheticName += "{B}";
+  } break;
+  case dwarf::DW_TAG_pointer_type: {
+    SyntheticName += "{C}";
+  } break;
+  case dwarf::DW_TAG_reference_type: {
+    SyntheticName += "{D}";
+  } break;
+  case dwarf::DW_TAG_string_type: {
+    SyntheticName += "{E}";
+  } break;
+  case dwarf::DW_TAG_structure_type: {
+    SyntheticName += "{F}";
+  } break;
+  case dwarf::DW_TAG_subroutine_type: {
+    SyntheticName += "{G}";
+  } break;
+  case dwarf::DW_TAG_typedef: {
+    SyntheticName += "{H}";
+  } break;
+  case dwarf::DW_TAG_union_type: {
+    SyntheticName += "{I}";
+  } break;
+  case dwarf::DW_TAG_variant: {
+    SyntheticName += "{J}";
+  } break;
+  case dwarf::DW_TAG_inlined_subroutine: {
+    SyntheticName += "{K}";
+  } break;
+  case dwarf::DW_TAG_module: {
+    SyntheticName += "{L}";
+  } break;
+  case dwarf::DW_TAG_ptr_to_member_type: {
+    SyntheticName += "{M}";
+  } break;
+  case dwarf::DW_TAG_set_type: {
+    SyntheticName += "{N}";
+  } break;
+  case dwarf::DW_TAG_subrange_type: {
+    SyntheticName += "{O}";
+  } break;
+  case dwarf::DW_TAG_with_stmt: {
+    SyntheticName += "{P}";
+  } break;
+  case dwarf::DW_TAG_access_declaration: {
+    SyntheticName += "{Q}";
+  } break;
+  case dwarf::DW_TAG_catch_block: {
+    SyntheticName += "{R}";
+  } break;
+  case dwarf::DW_TAG_const_type: {
+    SyntheticName += "{S}";
+  } break;
+  case dwarf::DW_TAG_constant: {
+    SyntheticName += "{T}";
+  } break;
+  case dwarf::DW_TAG_enumerator: {
+    SyntheticName += "{U}";
+  } break;
+  case dwarf::DW_TAG_file_type: {
+    SyntheticName += "{V}";
+  } break;
+  case dwarf::DW_TAG_friend: {
+    SyntheticName += "{W}";
+  } break;
+  case dwarf::DW_TAG_namelist: {
+    SyntheticName += "{X}";
+  } break;
+  case dwarf::DW_TAG_namelist_item: {
+    SyntheticName += "{Y}";
+  } break;
+  case dwarf::DW_TAG_packed_type: {
+    SyntheticName += "{Z}";
+  } break;
+  case dwarf::DW_TAG_subprogram: {
+    SyntheticName += "{a}";
+  } break;
+  case dwarf::DW_TAG_thrown_type: {
+    SyntheticName += "{b}";
+  } break;
+  case dwarf::DW_TAG_variant_part: {
+    SyntheticName += "{c}";
+  } break;
+  case dwarf::DW_TAG_variable: {
+    SyntheticName += "{d}";
+  } break;
+  case dwarf::DW_TAG_volatile_type: {
+    SyntheticName += "{e}";
+  } break;
+  case dwarf::DW_TAG_dwarf_procedure: {
+    SyntheticName += "{f}";
+  } break;
+  case dwarf::DW_TAG_restrict_type: {
+    SyntheticName += "{g}";
+  } break;
+  case dwarf::DW_TAG_interface_type: {
+    SyntheticName += "{h}";
+  } break;
+  case dwarf::DW_TAG_imported_module: {
+    SyntheticName += "{i}";
+  } break;
+  case dwarf::DW_TAG_unspecified_type: {
+    SyntheticName += "{j}";
+  } break;
+  case dwarf::DW_TAG_imported_unit: {
+    SyntheticName += "{k}";
+  } break;
+  case dwarf::DW_TAG_condition: {
+    SyntheticName += "{l}";
+  } break;
+  case dwarf::DW_TAG_shared_type: {
+    SyntheticName += "{m}";
+  } break;
+  case dwarf::DW_TAG_rvalue_reference_type: {
+    SyntheticName += "{n}";
+  } break;
+  case dwarf::DW_TAG_template_alias: {
+    SyntheticName += "{o}";
+  } break;
+  case dwarf::DW_TAG_coarray_type: {
+    SyntheticName += "{p}";
+  } break;
+  case dwarf::DW_TAG_generic_subrange: {
+    SyntheticName += "{q}";
+  } break;
+  case dwarf::DW_TAG_dynamic_type: {
+    SyntheticName += "{r}";
+  } break;
+  case dwarf::DW_TAG_atomic_type: {
+    SyntheticName += "{s}";
+  } break;
+  case dwarf::DW_TAG_call_site: {
+    SyntheticName += "{t}";
+  } break;
+  case dwarf::DW_TAG_call_site_parameter: {
+    SyntheticName += "{u}";
+  } break;
+  case dwarf::DW_TAG_immutable_type: {
+    SyntheticName += "{v}";
+  } break;
+  case dwarf::DW_TAG_entry_point: {
+    SyntheticName += "{w}";
+  } break;
+  case dwarf::DW_TAG_label: {
+    SyntheticName += "{x}";
+  } break;
+  case dwarf::DW_TAG_lexical_block: {
+    SyntheticName += "{y}";
+  } break;
+  case dwarf::DW_TAG_common_block: {
+    SyntheticName += "{z}";
+  } break;
+  case dwarf::DW_TAG_common_inclusion: {
+    SyntheticName += "{|}";
+  } break;
+  case dwarf::DW_TAG_try_block: {
+    SyntheticName += "{~}";
+  } break;
+
+  case dwarf::DW_TAG_null: {
+    llvm_unreachable("No type prefix for DW_TAG_null");
+  } break;
+  case dwarf::DW_TAG_compile_unit: {
+    llvm_unreachable("No type prefix for DW_TAG_compile_unit");
+  } break;
+  case dwarf::DW_TAG_partial_unit: {
+    llvm_unreachable("No type prefix for DW_TAG_partial_unit");
+  } break;
+  case dwarf::DW_TAG_type_unit: {
+    llvm_unreachable("No type prefix for DW_TAG_type_unit");
+  } break;
+  case dwarf::DW_TAG_skeleton_unit: {
+    llvm_unreachable("No type prefix for DW_TAG_skeleton_unit");
+  } break;
+
+  default: {
+    SyntheticName += "{~~";
+    SyntheticName += utohexstr(DieEntry->getTag());
+    SyntheticName += "}";
+  } break;
+  }
+}
+
+OrderedChildrenIndexAssigner::OrderedChildrenIndexAssigner(
+    CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) {
+  switch (DieEntry->getTag()) {
+  case dwarf::DW_TAG_array_type:
+  case dwarf::DW_TAG_coarray_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_common_block:
+  case dwarf::DW_TAG_lexical_block:
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_subprogram:
+  case dwarf::DW_TAG_subroutine_type:
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_GNU_template_template_param:
+  case dwarf::DW_TAG_GNU_formal_parameter_pack: {
+    NeedCountChildren = true;
+  } break;
+  case dwarf::DW_TAG_enumeration_type: {
+    // TODO : do we need to add condition
+    NeedCountChildren = true;
+  } break;
+  default: {
+    // Nothing to do.
+  }
+  }
+
+  // Calculate maximal index value
+  if (NeedCountChildren) {
+    for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(DieEntry);
+         CurChild && CurChild->getAbbreviationDeclarationPtr();
+         CurChild = CU.getSiblingEntry(CurChild)) {
+      std::optional<size_t> ArrayIndex = tagToArrayIndex(CU, CurChild);
+      if (!ArrayIndex)
+        continue;
+
+      assert((*ArrayIndex < ChildIndexesWidth.size()) &&
+             "Wrong index for ChildIndexesWidth");
+      ChildIndexesWidth[*ArrayIndex]++;
+    }
+
+    // Calculate index field width(number of digits in hexadecimal
+    // representation).
+    for (size_t &Width : ChildIndexesWidth) {
+      size_t digitsCounter = 1;
+      size_t NumToCompare = 15;
+
+      while (NumToCompare < Width) {
+        NumToCompare <<= 4;
+        digitsCounter++;
+      }
+
+      Width = digitsCounter;
+    }
+  }
+}
+
+std::optional<size_t> OrderedChildrenIndexAssigner::tagToArrayIndex(
+    CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) {
+  if (!NeedCountChildren)
+    return std::nullopt;
+
+  switch (DieEntry->getTag()) {
+  case dwarf::DW_TAG_unspecified_parameters:
+  case dwarf::DW_TAG_formal_parameter:
+    return 0;
+  case dwarf::DW_TAG_template_value_parameter:
+  case dwarf::DW_TAG_template_type_parameter:
+    return 1;
+  case dwarf::DW_TAG_enumeration_type:
+    if (std::optional<uint32_t> ParentIdx = DieEntry->getParentIdx()) {
+      if (*ParentIdx && CU.getDebugInfoEntry(*ParentIdx)->getTag() ==
+                            dwarf::DW_TAG_array_type)
+        return 2;
+    }
+    return std::nullopt;
+  case dwarf::DW_TAG_subrange_type:
+    return 3;
+  case dwarf::DW_TAG_generic_subrange:
+    return 4;
+  case dwarf::DW_TAG_enumerator:
+    return 5;
+  case dwarf::DW_TAG_namelist_item:
+    return 6;
+  case dwarf::DW_TAG_member:
+    return 7;
+  default:
+    return std::nullopt;
+  };
+}
+
+std::optional<std::pair<size_t, size_t>>
+OrderedChildrenIndexAssigner::getChildIndex(
+    CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry) {
+  std::optional<size_t> ArrayIndex = tagToArrayIndex(CU, ChildDieEntry);
+  if (!ArrayIndex)
+    return std::nullopt;
+
+  assert((*ArrayIndex < OrderedChildIdxs.size()) &&
+         "Wrong index for ChildIndexesWidth");
+  assert(ChildIndexesWidth[*ArrayIndex] < 16 &&
+         "Index width exceeds 16 digits.");
+
+  std::pair<size_t, size_t> Result = std::make_pair(
+      OrderedChildIdxs[*ArrayIndex], ChildIndexesWidth[*ArrayIndex]);
+  OrderedChildIdxs[*ArrayIndex]++;
+  return Result;
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm

diff  --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
new file mode 100644
index 000000000000000..c9dce4e94fb0dc3
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h
@@ -0,0 +1,155 @@
+//===- SyntheticTypeNameBuilder.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===/
+
+#ifndef LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H
+#define LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H
+
+#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerGlobalData.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+class DWARFDebugInfoEntry;
+
+namespace dwarflinker_parallel {
+struct LinkContext;
+class TypeTableUnit;
+class CompileUnit;
+
+/// The helper class to build type name based on DIE properties.
+/// It builds synthetic name based on explicit attributes: DW_AT_name,
+/// DW_AT_linkage_name or based on implicit attributes(DW_AT_decl*).
+/// Names for specific DIEs(like subprograms, template classes...) include
+/// additional attributes: subprogram parameters, template parameters,
+/// array ranges. Examples of built name:
+///
+/// class A {  }                    : {8}A
+///
+/// namspace llvm { class A {  } }  : {1}llvm{8}A
+///
+/// template <int> structure B { }  : {F}B<{0}int>
+///
+/// void foo ( int p1, float p3 )   : {a}void foo({0}int, {0}int)
+///
+/// int *ptr;                       : {c}ptr {0}int
+///
+/// int var;                        : {d}var
+///
+/// These names is used to refer DIEs describing types.
+class SyntheticTypeNameBuilder {
+public:
+  SyntheticTypeNameBuilder(TypePool &TypePoolRef) : TypePoolRef(TypePoolRef) {}
+
+  /// Create synthetic name for the specified DIE \p InputUnitEntryPair
+  /// and assign created name to the DIE type info. \p ChildIndex is used
+  /// to create name for ordered DIEs(function arguments f.e.).
+  Error assignName(UnitEntryPairTy InputUnitEntryPair,
+                   std::optional<std::pair<size_t, size_t>> ChildIndex);
+
+protected:
+  /// Add array type dimension.
+  void addArrayDimension(UnitEntryPairTy InputUnitEntryPair);
+
+  /// Add signature( entry type plus type of parameters plus type of template
+  /// parameters(if \p addTemplateParameters is true).
+  Error addSignature(UnitEntryPairTy InputUnitEntryPair,
+                     bool addTemplateParameters);
+
+  /// Add specified \p FunctionParameters to the built name.
+  Error addParamNames(
+      CompileUnit &CU,
+      SmallVector<const DWARFDebugInfoEntry *, 20> &FunctionParameters);
+
+  /// Add specified \p TemplateParameters to the built name.
+  Error addTemplateParamNames(
+      CompileUnit &CU,
+      SmallVector<const DWARFDebugInfoEntry *, 10> &TemplateParameters);
+
+  /// Add ordered name to the built name.
+  void addOrderedName(CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry);
+
+  /// Analyze \p InputUnitEntryPair's ODR attributes and put names
+  /// of the referenced type dies to the built name.
+  Error addReferencedODRDies(UnitEntryPairTy InputUnitEntryPair,
+                             bool AssignNameToTypeDescriptor,
+                             ArrayRef<dwarf::Attribute> ODRAttrs);
+
+  /// Add names of parent dies to the built name.
+  Error addParentName(UnitEntryPairTy &InputUnitEntryPair);
+
+  /// \returns synthetic name of the specified \p DieEntry.
+  /// The name is constructed from the dwarf::DW_AT_decl_file
+  /// and dwarf::DW_AT_decl_line attributes.
+  void addDieNameFromDeclFileAndDeclLine(UnitEntryPairTy &InputUnitEntryPair,
+                                         bool &HasDeclFileName);
+
+  /// Add type prefix to the built name.
+  void addTypePrefix(const DWARFDebugInfoEntry *DieEntry);
+
+  /// Add type name to the built name.
+  Error addTypeName(UnitEntryPairTy InputUnitEntryPair, bool AddParentNames);
+
+  /// Analyze \p InputUnitEntryPair for the type name and possibly assign
+  /// built type name to the DIE's type info.
+  /// NOTE: while analyzing types we may create 
diff erent kind of names
+  /// for the same type depending on whether the type is part of another type.
+  /// f.e. DW_TAG_formal_parameter would receive "{02}01" name when
+  /// examined alone. Or "{0}int" name when it is a part of a function name:
+  /// {a}void foo({0}int). The \p AssignNameToTypeDescriptor tells whether
+  /// the type name is part of another type name and then should not be assigned
+  /// to DIE type descriptor.
+  Error addDIETypeName(UnitEntryPairTy InputUnitEntryPair,
+                       std::optional<std::pair<size_t, size_t>> ChildIndex,
+                       bool AssignNameToTypeDescriptor);
+
+  /// Add ordered name to the built name.
+  void addOrderedName(std::pair<size_t, size_t> ChildIdx);
+
+  /// Add value name to the built name.
+  void addValueName(UnitEntryPairTy InputUnitEntryPair, dwarf::Attribute Attr);
+
+  /// Buffer keeping bult name.
+  SmallString<1000> SyntheticName;
+
+  /// Recursion counter
+  size_t RecursionDepth = 0;
+
+  /// Type pool
+  TypePool &TypePoolRef;
+};
+
+/// This class helps to assign indexes for DIE children.
+/// Indexes are used to create type name for children which
+/// should be presented in the original order(function parameters,
+/// array dimensions, enumeration members, class/structure members).
+class OrderedChildrenIndexAssigner {
+public:
+  OrderedChildrenIndexAssigner(CompileUnit &CU,
+                               const DWARFDebugInfoEntry *DieEntry);
+
+  /// Returns index of the specified child and width of hexadecimal
+  /// representation.
+  std::optional<std::pair<size_t, size_t>>
+  getChildIndex(CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry);
+
+protected:
+  using OrderedChildrenIndexesArrayTy = std::array<size_t, 8>;
+
+  std::optional<size_t> tagToArrayIndex(CompileUnit &CU,
+                                        const DWARFDebugInfoEntry *DieEntry);
+
+  bool NeedCountChildren = false;
+  OrderedChildrenIndexesArrayTy OrderedChildIdxs = {0};
+  OrderedChildrenIndexesArrayTy ChildIndexesWidth = {0};
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H

diff  --git a/llvm/lib/DWARFLinkerParallel/TypePool.h b/llvm/lib/DWARFLinkerParallel/TypePool.h
new file mode 100644
index 000000000000000..bbb3261027ce894
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/TypePool.h
@@ -0,0 +1,177 @@
+//===- TypePool.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H
+#define LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H
+
+#include "ArrayList.h"
+#include "llvm/ADT/ConcurrentHashtable.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/Support/Allocator.h"
+#include <atomic>
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+class TypePool;
+class CompileUnit;
+class TypeEntryBody;
+
+using TypeEntry = StringMapEntry<std::atomic<TypeEntryBody *>>;
+
+/// Keeps cloned data for the type DIE.
+class TypeEntryBody {
+public:
+  /// Returns copy of type DIE which should be emitted into resulting file.
+  DIE &getFinalDie() const {
+    if (Die)
+      return *Die;
+
+    assert(DeclarationDie);
+    return *DeclarationDie;
+  }
+
+  /// Returns true if type die entry has only declaration die.
+  bool hasOnlyDeclaration() const { return Die == nullptr; }
+
+  /// Creates type DIE for the specified name.
+  static TypeEntryBody *create(parallel::PerThreadBumpPtrAllocator &Allocator) {
+    TypeEntryBody *Result = Allocator.Allocate<TypeEntryBody>();
+    new (Result) TypeEntryBody(Allocator);
+    return Result;
+  }
+
+  /// TypeEntryBody keeps partially cloned DIEs corresponding to this type.
+  /// The two kinds of DIE can be kept: declaration and definition.
+  /// If definition DIE was met while parsing input DWARF then this DIE would
+  /// be used as a final DIE for this type. If definition DIE is not met then
+  /// declaration DIE would be used as a final DIE.
+
+  // Keeps definition die.
+  std::atomic<DIE *> Die = {nullptr};
+
+  // Keeps declaration die.
+  std::atomic<DIE *> DeclarationDie = {nullptr};
+
+  // True if parent type die is declaration.
+  std::atomic<bool> ParentIsDeclaration = {true};
+
+  /// Children for current type.
+  ArrayList<TypeEntry *, 5> Children;
+
+protected:
+  TypeEntryBody() = delete;
+  TypeEntryBody(const TypeEntryBody &RHS) = delete;
+  TypeEntryBody(TypeEntryBody &&RHS) = delete;
+  TypeEntryBody &operator=(const TypeEntryBody &RHS) = delete;
+  TypeEntryBody &operator=(const TypeEntryBody &&RHS) = delete;
+
+  TypeEntryBody(parallel::PerThreadBumpPtrAllocator &Allocator)
+      : Children(&Allocator) {}
+};
+
+class TypeEntryInfo {
+public:
+  /// \returns Hash value for the specified \p Key.
+  static inline uint64_t getHashValue(const StringRef &Key) {
+    return xxh3_64bits(Key);
+  }
+
+  /// \returns true if both \p LHS and \p RHS are equal.
+  static inline bool isEqual(const StringRef &LHS, const StringRef &RHS) {
+    return LHS == RHS;
+  }
+
+  /// \returns key for the specified \p KeyData.
+  static inline StringRef getKey(const TypeEntry &KeyData) {
+    return KeyData.getKey();
+  }
+
+  /// \returns newly created object of KeyDataTy type.
+  static inline TypeEntry *
+  create(const StringRef &Key, parallel::PerThreadBumpPtrAllocator &Allocator) {
+    return TypeEntry::create(Key, Allocator);
+  }
+};
+
+/// TypePool keeps type descriptors which contain partially cloned DIE
+/// correspinding to each type. Types are identified by names.
+class TypePool : ConcurrentHashTableByPtr<StringRef, TypeEntry,
+                                          parallel::PerThreadBumpPtrAllocator,
+                                          TypeEntryInfo> {
+public:
+  TypePool()
+      : ConcurrentHashTableByPtr<StringRef, TypeEntry,
+                                 parallel::PerThreadBumpPtrAllocator,
+                                 TypeEntryInfo>(Allocator) {
+    Root = TypeEntry::create("", Allocator);
+    Root->getValue().store(TypeEntryBody::create(Allocator));
+  }
+
+  TypeEntry *insert(StringRef Name) {
+    return ConcurrentHashTableByPtr<StringRef, TypeEntry,
+                                    parallel::PerThreadBumpPtrAllocator,
+                                    TypeEntryInfo>::insert(Name)
+        .first;
+  }
+
+  /// Create or return existing type entry body for the specified \p Entry.
+  /// Link that entry as child for the specified \p ParentEntry.
+  /// \returns The existing or created type entry body.
+  TypeEntryBody *getOrCreateTypeEntryBody(TypeEntry *Entry,
+                                          TypeEntry *ParentEntry) {
+    TypeEntryBody *DIE = Entry->getValue().load();
+    if (DIE)
+      return DIE;
+
+    TypeEntryBody *NewDIE = TypeEntryBody::create(Allocator);
+    if (Entry->getValue().compare_exchange_weak(DIE, NewDIE)) {
+      ParentEntry->getValue().load()->Children.add(Entry);
+      return NewDIE;
+    }
+
+    return DIE;
+  }
+
+  /// Sort children for each kept type entry.
+  void sortTypes() {
+    std::function<void(TypeEntry * Entry)> SortChildrenRec =
+        [&](TypeEntry *Entry) {
+          Entry->getValue().load()->Children.sort(TypesComparator);
+          Entry->getValue().load()->Children.forEach(SortChildrenRec);
+        };
+
+    SortChildrenRec(getRoot());
+  }
+
+  /// Return root for all type entries.
+  TypeEntry *getRoot() const { return Root; }
+
+  /// Return thread local allocator used by pool.
+  BumpPtrAllocator &getThreadLocalAllocator() {
+    return Allocator.getThreadLocalAllocator();
+  }
+
+protected:
+  std::function<bool(const TypeEntry *LHS, const TypeEntry *RHS)>
+      TypesComparator = [](const TypeEntry *LHS, const TypeEntry *RHS) -> bool {
+    return LHS->getKey() < RHS->getKey();
+  };
+
+  // Root of all type entries.
+  TypeEntry *Root = nullptr;
+
+private:
+  parallel::PerThreadBumpPtrAllocator Allocator;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H

diff  --git a/llvm/lib/DWARFLinkerParallel/Utils.h b/llvm/lib/DWARFLinkerParallel/Utils.h
new file mode 100644
index 000000000000000..91f9dca46a82b1c
--- /dev/null
+++ b/llvm/lib/DWARFLinkerParallel/Utils.h
@@ -0,0 +1,40 @@
+//===- Utils.h --------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// This function calls \p Iteration() until it returns false.
+/// If number of iterations exceeds \p MaxCounter then an Error is returned.
+/// This function should be used for loops which assumed to have number of
+/// iterations significantly smaller than \p MaxCounter to avoid infinite
+/// looping in error cases.
+inline Error finiteLoop(function_ref<Expected<bool>()> Iteration,
+                        size_t MaxCounter = 100000) {
+  size_t iterationsCounter = 0;
+  while (iterationsCounter++ < MaxCounter) {
+    Expected<bool> IterationResultOrError = Iteration();
+    if (!IterationResultOrError)
+      return IterationResultOrError.takeError();
+
+    if (!IterationResultOrError.get())
+      return Error::success();
+  }
+
+  return createStringError(std::errc::invalid_argument, "Infinite recursion");
+}
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H

diff  --git a/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
new file mode 100644
index 000000000000000..3f75991cdc471e1
--- /dev/null
+++ b/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test
@@ -0,0 +1,80 @@
+RUN: dsymutil --linker llvm -accelerator=Dwarf \
+RUN:   -oso-prepend-path=%p/../../Inputs \
+RUN:   %p/../../Inputs/accel-imported-declaration.macho-arm64 -o %t.dwarf.dSYM
+RUN: dsymutil --linker llvm -accelerator=Apple \
+RUN:   -oso-prepend-path=%p/../../Inputs \
+RUN:   %p/../../Inputs/accel-imported-declaration.macho-arm64 -o %t.apple.dSYM
+
+RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON
+RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON
+
+COMMON: .debug_info contents
+COMMON: DW_TAG_compile_unit
+COMMON: DW_AT_name{{.*}}"__artificial_type_unit"
+COMMON: DW_TAG_base_type
+COMMON: DW_AT_name{{.*}}"int"
+COMMON: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"A"
+COMMON: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"B"
+COMMON: 0x[[NAMESPACE_C_1:[0-9a-f]*]]: DW_TAG_namespace
+COMMON: DW_AT_name{{.*}}"C"
+COMMON-NOT: DW_TAG_variable
+COMMON: 0x[[NAMESPACE_C_2:[0-9a-f]*]]: DW_TAG_imported_declaration
+COMMON: DW_AT_import{{.*}}[[NAMESPACE_C_1]]
+COMMON: DW_AT_name{{.*}}"C"
+COMMON: DW_TAG_imported_module
+COMMON: DW_AT_import{{.*}}[[NAMESPACE_C_1]]
+
+
+COMMON: DW_TAG_compile_unit
+COMMON: {{.*}}DW_TAG_namespace
+COMMON:   DW_AT_name{{.*}}"A"
+COMMON: {{.*}}DW_TAG_namespace
+COMMON:   DW_AT_name{{.*}}"B"
+COMMON: 0x[[NAMESPACE_C_3:[0-9a-f]*]]: DW_TAG_namespace
+COMMON:   DW_AT_name{{.*}}"C"
+COMMON: 0x[[VAR_A:[0-9a-f]*]]: DW_TAG_variable
+COMMON: DW_TAG_imported_declaration
+COMMON:   DW_AT_import{{.*}}[[VAR_A]]
+
+DWARF:      .debug_names contents:
+DWARF:      Bucket 0 [
+DWARF-NEXT:   Name {{.*}} {
+DWARF-NEXT:     Hash: {{.*}}
+DWARF-NEXT:     String: {{.*}} "C"
+DWARF-NEXT:     Entry {{.*}} {
+DWARF-NEXT:       Abbrev: {{.*}}
+DWARF-NEXT:       Tag: DW_TAG_namespace
+DWARF:       DW_IDX_die_offset: 0x0000002f
+DWARF-NEXT:     }
+DWARF-NEXT:     Entry {{.*}} {
+DWARF-NEXT:       Abbrev: {{.*}}
+DWARF:       Tag: DW_TAG_imported_declaration
+DWARF:       DW_IDX_die_offset: 0x00000035
+DWARF-NEXT:     }
+DWARF-NEXT:     Entry {{.*}} {
+DWARF-NEXT:       Abbrev: {{.*}}
+DWARF-NEXT:       Tag: DW_TAG_namespace
+DWARF:       DW_IDX_die_offset: 0x0000003c
+DWARF-NEXT:     }
+
+DWARF-NEXT:   }
+
+APPLE:      .apple_namespaces contents:
+APPLE:      Bucket 1 [
+APPLE-NEXT:   Hash {{.*}} [
+APPLE-NEXT:     Name@{{.*}} {
+APPLE-NEXT:       String: {{.*}} "C"
+APPLE-NEXT:       Data 0 [
+APPLE-NEXT:         Atom[0]: 0x[[NAMESPACE_C_1]]
+APPLE-NEXT:       ]
+APPLE-NEXT:       Data 1 [
+APPLE-NEXT:         Atom[0]: 0x[[NAMESPACE_C_2]]
+APPLE-NEXT:       ]
+APPLE-NEXT:       Data 2 [
+APPLE-NEXT:         Atom[0]: 0x[[NAMESPACE_C_3]]
+APPLE-NEXT:       ]
+APPLE:          }
+APPLE-NEXT:   ]
+APPLE-NEXT: ]

diff  --git a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
index f1680ced6e5b4f0..057e89d060b1d27 100644
--- a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
+++ b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test
@@ -4,14 +4,6 @@ RUN: dsymutil -accelerator=Apple -oso-prepend-path=%p/../Inputs %p/../Inputs/acc
 RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON
 RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON
 
-RUN: dsymutil --linker llvm -accelerator=Dwarf -oso-prepend-path=%p/../Inputs \
-RUN:   %p/../Inputs/accel-imported-declaration.macho-arm64 -o %t.dwarf.dSYM
-RUN: dsymutil --linker llvm -accelerator=Apple -oso-prepend-path=%p/../Inputs \
-RUN:   %p/../Inputs/accel-imported-declaration.macho-arm64 -o %t.apple.dSYM
-
-RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON
-RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON
-
 COMMON: .debug_info contents
 COMMON: {{.*}}DW_TAG_namespace
 COMMON:   DW_AT_name{{.*}}"A"
@@ -19,7 +11,7 @@ COMMON: {{.*}}DW_TAG_namespace
 COMMON:   DW_AT_name{{.*}}"B"
 COMMON: [[NAMESPACE:0x[0-9a-f]*]]:{{.*}}DW_TAG_namespace
 COMMON:   DW_AT_name{{.*}}"C"
-COMMON: [[IMPORTED:0x[0-9a-f]*]]:{{.*}}DW_TAG_imported_declaration
+COMMON: 0x0000005c:{{.*}}DW_TAG_imported_declaration
 COMMON:   DW_AT_name{{.*}}"C"
 
 DWARF:      .debug_names contents:
@@ -30,12 +22,12 @@ DWARF-NEXT:     String: {{.*}} "C"
 DWARF-NEXT:     Entry {{.*}} {
 DWARF-NEXT:       Abbrev: {{.*}}
 DWARF-NEXT:       Tag: DW_TAG_namespace
-DWARF-NEXT:       DW_IDX_die_offset: [[NAMESPACE]]
+DWARF:       DW_IDX_die_offset: [[NAMESPACE]]
 DWARF-NEXT:     }
 DWARF-NEXT:     Entry {{.*}} {
 DWARF-NEXT:       Abbrev: {{.*}}
-DWARF-NEXT:       Tag: DW_TAG_imported_declaration
-DWARF-NEXT:       DW_IDX_die_offset: [[IMPORTED]]
+DWARF:       Tag: DW_TAG_imported_declaration
+DWARF:       DW_IDX_die_offset: 0x0000005c
 DWARF-NEXT:     }
 DWARF-NEXT:   }
 
@@ -48,8 +40,8 @@ APPLE-NEXT:       Data 0 [
 APPLE-NEXT:         Atom[0]: [[NAMESPACE]]
 APPLE-NEXT:       ]
 APPLE-NEXT:       Data 1 [
-APPLE-NEXT:         Atom[0]: [[IMPORTED]]
+APPLE-NEXT:         Atom[0]: {{0x0000005c|0x0000006f}}
 APPLE-NEXT:       ]
-APPLE-NEXT:     }
+APPLE:          }
 APPLE-NEXT:   ]
 APPLE-NEXT: ]

diff  --git a/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test b/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
index 00dcde718e36225..ca4a951e770ba2a 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test
@@ -50,15 +50,30 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA
 RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
 
 RUN: rm -rf %t.dir && mkdir -p %t.dir
-RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \
 RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
 RUN:   -o %t.dir/dwarf5-addr-base.dSYM
 RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s
 
+RUN: rm -rf %t.dir && mkdir -p %t.dir
+RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN:   -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN:   FileCheck %s --check-prefixes=CHECK,CHECK-LLVM
+
+
 RUN: rm -rf %t.dir && mkdir -p %t.dir
 RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
 RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefix=UPD
 
+RUN: rm -rf %t.dir && mkdir -p %t.dir
+RUN: dsymutil --linker llvm --no-odr --update -y %p/dummy-debug-map-amr64.map \
+RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN:   -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN:   FileCheck %s --check-prefix=UPD
+
 RUN: rm -rf %t.dir && mkdir -p %t.dir
 RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \
 RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
@@ -66,30 +81,36 @@ RUN:   -o %t.dir/dwarf5-addr-base.dSYM
 RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
 RUN:   FileCheck %s --check-prefix=UPD
 
+
 CHECK: .debug_info contents:
-CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08
 
-CHECK: 0x0000000c: DW_TAG_compile_unit [1] *
-CHECK:               DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000008)
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+
+CHECK: DW_TAG_compile_unit
+CHECK:   DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000008)
 
-CHECK: 0x0000002c:   DW_TAG_subprogram [2] * (0x0000000c)
+CHECK:   DW_TAG_subprogram
 CHECK-NEXT:                DW_AT_low_pc [DW_FORM_addrx]    (indexed (00000000) address = 0x[[ADDR1:[0-9a-f]+]])
 
 
-CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 
-CHECK: 0x0000005a: DW_TAG_compile_unit [1] *
+CHECK: DW_TAG_compile_unit
 CHECK:              DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000018)
 
-CHECK: 0x0000007a:   DW_TAG_subprogram [2] * (0x0000005a)
+CHECK: DW_TAG_subprogram
 CHECK-NEXT:                 DW_AT_low_pc [DW_FORM_addrx]    (indexed (00000000) address = 0x[[ADDR2:[0-9a-f]+]])
 
-CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08
+CHECK: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 
-CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} *
+CHECK: DW_TAG_compile_unit
 CHECK: DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000028)
 
-CHECK: 0x000000c1:   DW_TAG_subprogram [2] * (0x000000a8)
+CHECK:   DW_TAG_subprogram
 CHECK-NEXT:                 DW_AT_low_pc [DW_FORM_addrx]    (indexed (00000000) address = 0x[[ADDR3:[0-9a-f]+]])
 
 CHECK: .debug_addr contents:

diff  --git a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
index 324a156484119f8..0199bf28681bc4f 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test
@@ -34,17 +34,31 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA
 RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM -a --verbose | FileCheck %s
 
 RUN: rm -rf %t.dir && mkdir -p %t.dir
-RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: dsymutil --no-odr --linker llvm -y %p/dummy-debug-map-amr64.map \
 RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \
 RUN:   -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
 RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \
 RUN:   -a --verbose | FileCheck %s
 
+### Uncomment following when llvm-dwarfdump will dump address ranges
+### correctly for severall compile units case.
+COM: rm -rf %t.dir && mkdir -p %t.dir
+COM: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+COM:   -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \
+COM:   -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM
+COM: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \
+COM:   -a --verbose | FileCheck %s --check-prefixes=CHECK,CHECK-LLVM
+
+
 CHECK:.debug_abbrev contents:
 CHECK-NEXT: Abbrev table for offset: 0x00000000
 
 CHECK: .debug_info contents:
-CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 
+CHECK-LLVM: Compile Unit: length = 0x0000001f,  format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 CHECK: DW_AT_producer [DW_FORM_strx]     (indexed (00000000) string = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)")
 CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp")
 CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
@@ -54,17 +68,17 @@ CHECK: DW_AT_comp_dir [DW_FORM_strx]     (indexed (00000004) string = "/Users/sh
 CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]]
 CHECK-NEXT:                  [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]]))
 CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000008)
-CHECK: 0x0000002c:   DW_TAG_subprogram [2] * (0x0000000c)
+CHECK:   DW_TAG_subprogram
 CHECK-NEXT:  DW_AT_low_pc [DW_FORM_addrx]     (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]])
 CHECK: DW_AT_linkage_name [DW_FORM_strx]       (indexed (00000005) string = "_Z4foo2i")
 CHECK: DW_AT_name [DW_FORM_strx]       (indexed (00000006) string = "foo2")
-CHECK: 0x0000003c:     DW_TAG_formal_parameter [3]   (0x0000002c)
+CHECK:     DW_TAG_formal_parameter
 CHECK-NEXT:                   DW_AT_location [DW_FORM_sec_offset]   (0x[[LOCLIST_OFFSET:[0-9a-f]+]]: 
 CHECK-NEXT:                      [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]]
 CHECK-NEXT:                      [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]])
 CHECK: DW_AT_name [DW_FORM_strx]     (indexed (00000007) string = "a")
 
-CHECK: 0x0000004e: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 
+CHECK: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = {{.*}}, addr_size = 0x08
 CHECK: DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)")
 CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000e0] = "b.cpp")
 CHECK: DW_AT_LLVM_sysroot [DW_FORM_strp] ( .debug_str[0x00000039] = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")
@@ -74,11 +88,11 @@ CHECK: DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x000000a3] = "/Users/shub
 CHECK:              DW_AT_low_pc [DW_FORM_addr]       (0x[[#%.16x,RANGE_LOWPC:]])
 CHECK-NEXT:              DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
 CHECK-NEXT:                 [0x[[#%.16x,RANGE_START:]], 0x[[#%.16x,RANGE_END:]]))
-CHECK: 0x00000080:   DW_TAG_subprogram {{.*}} * (0x00000059)
+CHECK:   DW_TAG_subprogram
 CHECK-NEXT:                DW_AT_low_pc [DW_FORM_addr]     (0x[[#%.16x,LOC_LOWPC:]])
 CHECK: DW_AT_linkage_name [DW_FORM_strp]       ( .debug_str[0x000000e6] = "_Z3bari")
 CHECK: DW_AT_name [DW_FORM_strp]       ( .debug_str[0x000000ee] = "bar")
-CHECK: 0x0000009d:     DW_TAG_formal_parameter {{.*}}   (0x00000080)
+CHECK:     DW_TAG_formal_parameter
 CHECK-NEXT:                  DW_AT_location [DW_FORM_sec_offset]   (0x[[LOC_OFFSET:[0-9a-f]+]]: 
 CHECK-NEXT:                     [0x[[#%.16x,LOC_PAIR_START:]], 0x[[#%.16x,LOC_PAIR_END:]]): [[LOC_EXPR:.*]]
 CHECK-NEXT:                     [0x[[#%.16x,LOC_PAIR_START2:]], 0x[[#%.16x,LOC_PAIR_END2:]]): [[LOC_EXPR2:.*]])

diff  --git a/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
index 3008db9a0d63c21..13409b2a07a31f6 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test
@@ -22,21 +22,33 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA
 RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s
 
 RUN: rm -rf %t.dir && mkdir -p %t.dir
-RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \
 RUN:   -oso-prepend-path=%p/../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM
 RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s
 
+### Uncomment following when llvm-dwarfdump will print resolved address ranges
+### for the case mutiplue compile units.
+COM: rm -rf %t.dir && mkdir -p %t.dir
+COM: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
+COM:   -oso-prepend-path=%p/../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM
+COM: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s \
+COM: --check-prefixes=CHECK,CHECK-LLVM
+
+
 CHECK:.debug_abbrev contents:
 CHECK-NEXT: Abbrev table for offset: 0x00000000
 
 CHECK: .debug_info contents:
-CHECK-NEXT: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]]
 CHECK-NEXT:                  [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]]))
 CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset]      (0x00000008)
-CHECK: 0x0000002c:   DW_TAG_subprogram [2] * (0x0000000c)
+CHECK:   DW_TAG_subprogram
 CHECK-NEXT:  DW_AT_low_pc [DW_FORM_addrx]     (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]])
-CHECK: 0x0000003c:     DW_TAG_formal_parameter [3]   (0x0000002c)
+CHECK:     DW_TAG_formal_parameter
 CHECK-NEXT:                   DW_AT_location [DW_FORM_sec_offset]   (0x[[LOC_OFFSET:[0-9a-f]+]]: 
 CHECK-NEXT:                      [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]]
 CHECK-NEXT:                      [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]])

diff  --git a/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test b/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
index ac813fc6203708d..73decc497ea36ee 100644
--- a/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
+++ b/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test
@@ -56,21 +56,40 @@ RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --c
 RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM
 RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,GLOBALUPD
 
+RUN: rm -rf %t.dir && mkdir -p %t.dir
+RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \
+RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN:   -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN:   FileCheck %s --check-prefixes=CHECK,LOCAL
+
 RUN: rm -rf %t.dir && mkdir -p %t.dir
 RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \
 RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
 RUN:   -o %t.dir/dwarf5-addr-base.dSYM
-RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=CHECK,LOCAL
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN:   FileCheck %s --check-prefixes=CHECK,LOCAL,CHECK-LLVM
+
+RUN: dsymutil --linker llvm --no-odr --update -y %p/dummy-debug-map-amr64.map \
+RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
+RUN:   -o %t.dir/dwarf5-addr-base.dSYM
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN:   FileCheck %s --check-prefixes=UPD,LOCALUPD
 
 RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \
 RUN:   -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \
 RUN:   -o %t.dir/dwarf5-addr-base.dSYM
-RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,LOCALUPD
+RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \
+RUN:   FileCheck %s --check-prefixes=UPD,LOCALUPD
+
 
 CHECK: .debug_info contents:
-CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000004e)
+CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
+CHECK-LLVM: DW_TAG_compile_unit
+CHECK-LLVM: DW_TAG_base_type
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 
-CHECK: 0x0000000c: DW_TAG_compile_unit [1] *
+CHECK: DW_TAG_compile_unit
 CHECK:               DW_AT_producer [DW_FORM_strx]     (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
 CHECK:               DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp")
 CHECK:               DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
@@ -78,24 +97,24 @@ CHECK:               DW_AT_APPLE_sdk [DW_FORM_strx]    (indexed (00000003) strin
 CHECK:               DW_AT_str_offsets_base [DW_FORM_sec_offset]       (0x00000008)
 CHECK:               DW_AT_comp_dir [DW_FORM_strx]     (indexed (00000004) string = "/Users/shubham/Development/test109275485")
 
-CHECK: 0x0000002c:   DW_TAG_subprogram [2] * (0x0000000c)
+CHECK:   DW_TAG_subprogram
 CHECK:                 DW_AT_low_pc [DW_FORM_addrx]    (indexed (00000000) address = 0x0000000000010000)
 CHECK:                 DW_AT_linkage_name [DW_FORM_strx]       (indexed (00000005) string = "_Z4foo2i")
 CHECK:                 DW_AT_name [DW_FORM_strx]       (indexed (00000006) string = "foo2")
 
-CHECK: 0x0000003c:     DW_TAG_formal_parameter [3]   (0x0000002c)
+CHECK:     DW_TAG_formal_parameter
 CHECK:                   DW_AT_name [DW_FORM_strx]     (indexed (00000007) string = "a")
 
-CHECK: 0x00000048:     NULL
+CHECK:     NULL
 
-CHECK: 0x00000049:   DW_TAG_base_type [4]   (0x0000000c)
+CHECK:   DW_TAG_base_type
 CHECK:                 DW_AT_name [DW_FORM_strx]       (indexed (00000008) string = "int")
 
-CHECK: 0x0000004d:   NULL
+CHECK: NULL
 
-CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 (next unit at 0x0000009c)
+CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 
-CHECK: 0x0000005a: DW_TAG_compile_unit [1] *
+CHECK: DW_TAG_compile_unit
 CHECK:               DW_AT_producer [DW_FORM_strx]     (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
 CHECK:               DW_AT_name [DW_FORM_strx] (indexed (0000000{{9|1}}) string = "b.cpp")
 CHECK:               DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
@@ -103,23 +122,23 @@ CHECK:               DW_AT_APPLE_sdk [DW_FORM_strx]    (indexed (00000003) strin
 CHECK:               DW_AT_str_offsets_base [DW_FORM_sec_offset]       (0x000000{{08|34}})
 CHECK:               DW_AT_comp_dir [DW_FORM_strx]     (indexed (00000004) string = "/Users/shubham/Development/test109275485")
 
-CHECK: 0x0000007a:   DW_TAG_subprogram [2] * (0x0000005a)
+CHECK:   DW_TAG_subprogram
 CHECK:                 DW_AT_linkage_name [DW_FORM_strx]       (indexed (0000000{{a|5}}) string = "_Z4bar2i")
 CHECK:                 DW_AT_name [DW_FORM_strx]       (indexed (0000000{{b|6}}) string = "bar2")
 
-CHECK: 0x0000008a:     DW_TAG_formal_parameter [3]   (0x0000007a)
+CHECK:     DW_TAG_formal_parameter
 CHECK:                   DW_AT_name [DW_FORM_strx]     (indexed (00000007) string = "a")
 
-CHECK: 0x00000096:     NULL
+CHECK:     NULL
 
-CHECK: 0x00000097:   DW_TAG_base_type [4]   (0x0000005a)
+CHECK:   DW_TAG_base_type
 CHECK:                 DW_AT_name [DW_FORM_strx]       (indexed (00000008) string = "int")
 
-CHECK: 0x0000009b:   NULL
+CHECK:   NULL
 
-CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08 (next unit at 0x000000e3)
+CHECK: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08
 
-CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} *
+CHECK: DW_TAG_compile_unit
 CHECK:               DW_AT_producer [DW_FORM_strx]     (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)")
 CHECK:               DW_AT_name [DW_FORM_strx] (indexed (0000000{{c|1}}) string = "c.cpp")
 CHECK:               DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk")
@@ -127,19 +146,19 @@ CHECK:               DW_AT_APPLE_sdk [DW_FORM_strx]    (indexed (00000003) strin
 CHECK:               DW_AT_str_offsets_base [DW_FORM_sec_offset]       (0x000000{{08|60}})
 CHECK:               DW_AT_comp_dir [DW_FORM_strx]     (indexed (00000004) string = "/Users/shubham/Development/test109275485")
 
-CHECK: 0x000000c1:   DW_TAG_subprogram [2] * (0x000000a8)
+CHECK:   DW_TAG_subprogram
 CHECK:                 DW_AT_linkage_name [DW_FORM_strx]       (indexed (0000000{{d|5}}) string = "_Z3bazi")
 CHECK:                 DW_AT_name [DW_FORM_strx]       (indexed (0000000{{e|6}}) string = "baz")
 
-CHECK: 0x000000d1:     DW_TAG_formal_parameter [3]   (0x000000c1)
+CHECK:     DW_TAG_formal_parameter
 CHECK:                   DW_AT_name [DW_FORM_strx]     (indexed (0000000{{f|7}}) string = "x")
 
-CHECK: 0x000000dd:     NULL
+CHECK:     NULL
 
-CHECK: 0x000000de:   DW_TAG_base_type [4]   (0x000000a8)
+CHECK:   DW_TAG_base_type
 CHECK:                 DW_AT_name [DW_FORM_strx]       (indexed (00000008) string = "int")
 
-CHECK: 0x000000e2:   NULL
+CHECK:    NULL
 
 CHECK: .debug_str contents:
 CHECK-NEXT: 0x00000000: ""

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
new file mode 100644
index 000000000000000..a94d06f2ab64d27
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp
@@ -0,0 +1,67 @@
+// RUN: dsymutil --linker llvm --no-odr -f -y %p/../dummy-debug-map.map -oso-prepend-path \
+// RUN: %p/../../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
+// RUN: FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
+//
+// RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path \
+// RUN: %p/../../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
+// RUN: FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN: --check-prefixes=CHECK-LLVM
+
+// The test was compiled with:
+// clang++ -O2 -g -c dead-strip.cpp -o 1.o
+
+// The goal of the test is to exercise dsymutil's behavior in presence of
+// functions/variables that have been dead-stripped by the linker but
+// that are still present in the linked debug info (in this case because
+// they have been DW_TAG_import'd in another namespace).
+
+// CHECK-LLVM: DW_TAG_compile_unit
+// CHECK-LLVM: DW_AT_name{{.*}}"__artificial_type_unit"
+// CHECK-LLVM: DW_TAG_namespace
+// CHECK-LLVM: DW_AT_name{{.*}}"N"
+// CHECK-LLVM: NULL
+//
+// CHECK-LLVM: DW_TAG_compile_unit
+// CHECK-LLVM:   DW_AT_low_pc
+// CHECK-LLVM:   DW_AT_high_pc
+// CHECK-LLVM: DW_TAG_base_type
+// CHECK-LLVM: DW_TAG_imported_module
+// CHECK-LLVM: DW_TAG_subprogram
+// CHECK-LLVM:   DW_AT_low_pc
+// CHECK-LLVM:   DW_AT_high_pc
+// CHECK-LLVM: DW_TAG_base_type
+// CHECK-LLVM: NULL
+
+// Everything in the N namespace below doesn't have a debug map entry, and
+// thus is considered dead (::foo() has a debug map entry, otherwise dsymutil
+// would just drop the CU altogether).
+
+// CHECK: DW_TAG_compile_unit
+// CHECK:   DW_AT_low_pc
+// CHECK:   DW_AT_high_pc
+// CHECK:   DW_TAG_namespace
+namespace N {
+int blah = 42;
+
+__attribute__((always_inline)) int foo() { return blah; }
+
+int bar(unsigned i) {
+	int val = foo();
+	if (i)
+		return val + bar(i-1);
+	return foo();
+}
+}
+// CHECK: DW_TAG_base_type
+// CHECK: DW_TAG_imported_module
+// CHECK: DW_TAG_subprogram
+// CHECK:   DW_AT_low_pc
+// CHECK:   DW_AT_high_pc
+// CHECK: DW_TAG_base_type
+// CHECK: NULL
+
+using namespace N;
+
+void foo() {}

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
new file mode 100644
index 000000000000000..b2d178cee0282cc
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test
@@ -0,0 +1,5 @@
+RUN: llvm-mc %p/../../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o
+RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
+
+CHECK: .debug_info contents:
+CHECK-NOT: DW_TAG_compile_unit

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
new file mode 100644
index 000000000000000..97d7e630e7c6722
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp
@@ -0,0 +1,74 @@
+// RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path \
+// RUN:   %p/../../Inputs/inlined-static-variable -o - -keep-function-for-static | \
+// RUN:   llvm-dwarfdump - | FileCheck %s --implicit-check-not \
+// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN: --check-prefixes=CHECK
+
+// clang -g -c inlined-static-variable.cpp -o 4.o
+
+// The functions removed and not_removed are not in the debug map and are
+// considered dead, but they are also inlined into the function foo which is
+// in the debug map. Those function-local globals are alive and thus should
+// have locations in the debug info even if their functions do not.
+
+inline __attribute__((always_inline)) int removed() {
+  static int a = 0;
+  return ++a;
+}
+
+__attribute__((always_inline)) int not_removed() {
+  static int b = 0;
+  return ++b;
+}
+
+int unused() {
+  static int c = 0;
+  return ++c;
+}
+
+int foo() {
+  return removed() + not_removed();
+}
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+// CHECK: DW_TAG_base_type
+// CHECK:   DW_AT_name{{.*}}"int"
+// CHECK: DW_TAG_subprogram
+// CHECK:   DW_AT_name{{.*}}"not_removed"
+// CHECK: DW_TAG_subprogram
+// CHECK:   DW_AT_name{{.*}}"removed"
+// CHECK: NULL
+
+// CHECK: DW_TAG_compile_unit
+// CHECK:   DW_AT_low_pc
+// CHECK:   DW_AT_high_pc
+// CHECK:   DW_TAG_subprogram
+// CHECK:   DW_AT_name{{.*}}"removed"
+// CHECK-NOT: DW_AT_low_pc
+// CHECK-NOT: DW_AT_low_pc
+// CHECK:   DW_TAG_variable
+// CHECK:   DW_AT_name{{.*}}"a"
+// CHECK:   {{.*}}DW_OP_addr
+// CHECK:   NULL
+// CHECK:   DW_TAG_base_type
+// CHECK:   DW_TAG_subprogram
+// CHECK:   DW_AT_name{{.*}}"not_removed"
+// CHECK-NOT: DW_AT_low_pc
+// CHECK-NOT: DW_AT_low_pc
+// CHECK:   DW_TAG_variable
+// CHECK:   DW_AT_name{{.*}}"b"
+// CHECK:   {{.*}}DW_OP_addr
+// CHECK:   NULL
+// CHECK:   DW_TAG_subprogram
+// CHECK:     DW_AT_low_pc
+// CHECK:     DW_AT_high_pc
+// CHECK:     DW_AT_name	("foo")
+// CHECK:     DW_TAG_inlined_subroutine
+// CHECK:       DW_AT_low_pc
+// CHECK:       DW_AT_high_pc
+// CHECK:     DW_TAG_inlined_subroutine
+// CHECK:       DW_AT_low_pc
+// CHECK:       DW_AT_high_pc
+// CHECK:     NULL
+// CHECK:   NULL

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
new file mode 100644
index 000000000000000..6d8757391d6c68d
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test
@@ -0,0 +1,36 @@
+$ cat main.cpp
+#include <stdio.h>
+
+static void Foo(void)
+{
+  typedef struct {
+    int x1;
+    int x2;
+  } FOO_VAR_TYPE;
+  static FOO_VAR_TYPE MyDummyVar __attribute__((aligned(4), used, section("TAD_VIRTUAL, TAD_DUMMY_DATA"), nocommon));
+  printf("Foo called");
+}
+
+int main()
+{
+  Foo();
+  return 1;
+}
+
+$ clang++ -O2 -g main.cpp -c -o main.o
+$ clang++ main.o -o main.out
+
+RUN: dsymutil --linker llvm -oso-prepend-path %p/../../Inputs %p/../../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM
+RUN: dsymutil --linker llvm -oso-prepend-path %p/../../Inputs %p/../../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static
+RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
+RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
+
+KEEP:     DW_AT_name	("x1")
+KEEP:     DW_AT_name	("x2")
+KEEP:     DW_AT_name    ("FOO_VAR_TYPE")
+KEEP:     DW_AT_name    ("MyDummyVar")
+
+OMIT-NOT: DW_AT_name	("MyDummyVar")
+OMIT-NOT: DW_AT_name	("FOO_VAR_TYPE")
+OMIT-NOT: DW_AT_name	("x1")
+OMIT-NOT: DW_AT_name	("x2")

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
new file mode 100644
index 000000000000000..16aacd57517bd2e
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp
@@ -0,0 +1,68 @@
+/* Compile with:
+   for FILE in `seq 2`; do
+     clang -g -c  odr-anon-namespace.cpp -DFILE$FILE -o odr-anon-namespace/$FILE.o
+   done
+ */
+
+// RUN: dsymutil --linker llvm -f \
+// RUN:   -oso-prepend-path=%p/../../Inputs/odr-anon-namespace \
+// RUN:   -y %p/../dummy-debug-map.map -o - | \
+// RUN:   llvm-dwarfdump -debug-info - | FileCheck %s
+
+#ifdef FILE1
+// Currently dsymutil will unique the contents of anonymous
+// namespaces if they are from the same file/line. Force this
+// namespace to appear 
diff erent eventhough it's the same (this
+// uniquing is actually a bug kept for backward compatibility, see the
+// comments in DeclContextTree::getChildDeclContext()).
+#line 42
+#endif
+namespace {
+class C {};
+}
+
+void foo() {
+  C c;
+}
+
+// Keep the ifdef guards for FILE1 and FILE2 even if all the code is
+// above to clearly show what the CHECK lines are testing.
+#ifdef FILE1
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-anon-namespace.cpp"
+
+// CHECK: DW_TAG_variable
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name {{.*}}"c"
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_type {{.*}}0x[[C_FILE1:[0-9a-f]*]]
+
+// CHECK: DW_TAG_namespace
+// CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}}
+// CHECK: 0x[[C_FILE1]]:{{.*}}DW_TAG_class_type
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name{{.*}}"C"
+
+#elif defined(FILE2)
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-anon-namespace.cpp"
+
+// CHECK: DW_TAG_variable
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name {{.*}}"c"
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_type {{.*}}0x[[C_FILE2:[0-9a-f]*]]
+
+// CHECK: DW_TAG_namespace
+// CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}}
+// CHECK: 0x[[C_FILE2]]:{{.*}}DW_TAG_class_type
+// CHECK-NOT: DW_TAG
+// CHECK: DW_AT_name{{.*}}"C"
+
+#else
+#error "You must define which file you generate"
+#endif

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
new file mode 100644
index 000000000000000..3e8d8557689e36d
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test
@@ -0,0 +1,101 @@
+/* Compile with:
+   for FILE in `seq 3`; do
+     clang -g -c  X86/odr-fwd-declaration.cpp -DFILE$FILE -o
+       Inputs/odr-fwd-declaration/$FILE.o done
+*/
+
+// RUN: dsymutil --linker=llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-fwd-declaration \
+// RUN: -y %p/../dummy-debug-map.map -o %t1.out
+// RUN: llvm-dwarfdump -v -debug-info %t1.out | FileCheck %s
+
+#ifdef FILE1
+# 1 "Header.h" 1
+typedef struct S *Sptr;
+typedef Sptr *Sptrptr;
+# 3 "Source1.cpp" 2
+void foo() { Sptrptr ptr1 = 0; }
+
+// First we confirm that types are in type table.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+// CHECK: DW_TAG_base_type
+
+// CHECK: 0x[[PTR_S:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[STRUCT_S:[a-f0-9]*]]} "S"
+
+// CHECK: 0x[[PTR_PTR_S:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[TYPEDEF_PTR_S:[a-f0-9]*]]} "Sptr"
+
+// CHECK: 0x[[STRUCT_S]]: DW_TAG_structure_type
+// CHECK-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: DW_AT_name{{.*}}"field"
+
+// CHECK: 0x[[TYPEDEF_PTR_S]]: DW_TAG_typedef
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[PTR_S]]} "S *"
+// CHECK-NEXT: DW_AT_name{{.*}}"Sptr"
+
+// CHECK: 0x[[TYPEDEF_PTR_PTR_S:[a-f0-9]*]]: DW_TAG_typedef
+// CHECK-NEXT: DW_AT_type{{.*}}{0x[[PTR_PTR_S]]} "Sptr *"
+// CHECK-NEXT: DW_AT_name{{.*}}"Sptrptr"
+
+// First we confirm that first compile unit properly references type.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp"
+//
+// CHECK: TAG_variable
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}} "ptr1"
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]]
+
+#elif defined(FILE2)
+# 1 "Header.h" 1
+typedef struct S *Sptr;
+typedef Sptr *Sptrptr;
+# 3 "Source2.cpp" 2
+struct S {
+  int field;
+};
+void bar() { Sptrptr ptr2 = 0; }
+
+// Next we confirm that the second compile unit properly references types.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp"
+//
+// CHECK: TAG_variable
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}} "ptr2"
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]]
+
+#elif defined(FILE3)
+# 1 "Header.h" 1
+typedef struct S *Sptr;
+typedef Sptr *Sptrptr;
+# 3 "Source1.cpp" 2
+void foo() { Sptrptr ptr1 = 0; }
+
+// Finally we confirm that third compile unit references types correctly.
+//
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp"
+//
+// CHECK: TAG_variable
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}} "ptr1"
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]]
+// CHECK-NOT: TAG_typedef
+// CHECK-NOT: TAG_pointer
+// CHECK-NOT: TAG_structure_type
+
+#else
+#error "You must define which file you generate"
+#endif

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
new file mode 100644
index 000000000000000..439b7d76bb69bf4
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test
@@ -0,0 +1,131 @@
+/* Compile with:
+   for FILE in `seq 3`; do
+     clang -g -c  X86/odr-fwd-declaration2.cpp -DFILE$FILE -o
+       Inputs/odr-fwd-declaration2/$FILE.o done
+*/
+
+// RUN: dsymutil --linker=llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-fwd-declaration2 \
+// RUN: -y %p/../dummy-debug-map.map -o %t1.out
+// RUN: llvm-dwarfdump -v %t1.out -debug-info | FileCheck %s
+
+#ifdef FILE1
+# 1 "Header.h" 1
+struct A {
+  struct B;
+  B *bPtr;
+  B &bRef;
+  int B::*bPtrToField;
+};
+# 3 "Source1.cpp" 2
+void foo() { A *ptr1 = 0; }
+
+// First we check that types are in type table unit.
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"__artificial_type_unit"
+
+// CHECK: 0x[[INT_BASE:[a-f0-9]*]]: DW_TAG_base_type
+// CHECK: AT_name{{.*}}"int"
+
+// CHECK: 0x[[PTR_A:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4]   {{.*}}0x[[STRUCT_A:[a-f0-9]*]]} "A")
+
+// CHECK: 0x[[PTR_B:[a-f0-9]*]]: DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4]   {{.*}}0x[[STRUCT_B:[a-f0-9]*]]} "A::B")
+
+// CHECK: 0x[[REF_B:[a-f0-9]*]]: DW_TAG_reference_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4]   {{.*}}0x[[STRUCT_B]]} "A::B")
+
+// CHECK: 0x[[STRUCT_A]]: DW_TAG_structure_type
+// CHECK: AT_name{{.*}}"A"
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: AT_name{{.*}}"bPtr"
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[PTR_B]]} "A::B *")
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: AT_name{{.*}}"bRef"
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[REF_B]]} "A::B &"
+
+// CHECK: DW_TAG_member
+// CHECK-NEXT: AT_name{{.*}}"bPtrToField"
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[PTR_TO_FIELD:[a-f0-9]*]]} "int A::B::*"
+
+// CHECK: 0x[[STRUCT_B]]: DW_TAG_structure_type
+// CHECK: AT_name{{.*}}"B"
+
+// CHECK: DW_TAG_member
+// CHECK: AT_name{{.*}}"x"
+
+// CHECK: 0x[[PTR_TO_FIELD]]: DW_TAG_ptr_to_member_type
+// CHECK-NEXT: DW_AT_type [DW_FORM_ref4]   {{.*}}{0x[[INT_BASE]]} "int"
+// CHECK-NEXT: DW_AT_containing_type [DW_FORM_ref4] {{.*}}{0x[[STRUCT_B]]} "A::B")
+
+// Next we check that second compile unit references type from type table unit.
+//
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp"
+
+// CHECK: DW_TAG_subprogram
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"ptr1"
+// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *"
+
+#elif defined(FILE2)
+# 1 "Header.h" 1
+struct A {
+  struct B;
+  B *bPtr;
+  B &bRef;
+  int B::*bPtrToField;
+};
+# 3 "Source2.cpp" 2
+struct A::B {
+  int x;
+};
+void bar() { A *ptr2 = 0; }
+
+// Next we check that thrid compile unit references type from type table unit.
+//
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp"
+
+// CHECK: DW_TAG_subprogram
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"ptr2"
+// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *"
+
+#elif defined(FILE3)
+# 1 "Header.h" 1
+struct A {
+  struct B;
+  B *bPtr;
+  B &bRef;
+  int B::*bPtrToField;
+};
+# 3 "Source2.cpp" 2
+struct A::B {
+  int x;
+};
+void bar() { A *ptr2 = 0; }
+
+// Next we check that fourth compile unit references type from type table unit.
+//
+
+// CHECK: DW_TAG_compile_unit
+// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp"
+
+// CHECK: DW_TAG_subprogram
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"ptr2"
+// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *"
+
+#else
+#error "You must define which file you generate"
+#endif

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
new file mode 100644
index 000000000000000..9758e4ad4213033
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test
@@ -0,0 +1,381 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks debug info for the case when one compilation unit
+## contains forward declaration of the type and another compilation unit
+## contains definition for that type. The result should have type table
+## containing definition for that type and corresponding variables should
+## properly reference that type.
+
+## CU1:
+##
+## class class1;
+## template<int> class class2;
+##
+## class1 *var1;
+## class2<int> *var2;
+##
+## CU2:
+##
+## class class1 {
+##   char member1;
+##   float member2;
+## };
+##
+## template<int> class class2 {
+##   char member1;
+## };
+##
+## class1 *var1;
+## class2<int> *var2;
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"char"
+
+# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"float"
+
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[CHAR]] "char"
+# CHECK: DW_AT_name{{.*}}"member1"
+
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[FLOAT]] "float"
+# CHECK: DW_AT_name{{.*}}"member2"
+
+# CHECK: 0x[[CLASS2:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class2"
+# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[CHAR]] "char"
+# CHECK: DW_AT_name{{.*}}"member1"
+
+# CHECK: 0x[[PTR_CLASS1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CLASS1]] "class1"
+
+# CHECK: 0x[[PTR_CLASS2:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CLASS2]] "class2<int>"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS1]] "class1 *"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS2]] "class2<int> *"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS1]] "class1 *"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS2]] "class2<int> *"
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x9c
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0xed
+        offset:    0x0000041c
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x000001FC
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          false
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           1
+    stroff:          0x710
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_template_type_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_template_type_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+        - AbbrCode: 4
+          Values:
+            - CStr: class1
+        - AbbrCode: 5
+          Values:
+            - CStr: class2
+        - AbbrCode: 6
+          Values:
+            - Value:  0x00000030
+        - AbbrCode: 0
+        - AbbrCode: 7
+          Values:
+            - CStr: int
+        - AbbrCode: 8
+          Values:
+            - Value:  0x0000001a
+        - AbbrCode: 8
+          Values:
+            - Value:  0x00000022
+        - AbbrCode: 9
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x00000035
+        - AbbrCode: 9
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x0000003a
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU2
+        - AbbrCode: 2
+          Values:
+            - CStr: class1
+        - AbbrCode: 3
+          Values:
+            - Value:  0x000000b9
+            - CStr: member1
+        - AbbrCode: 3
+          Values:
+            - Value:  0x000000bf
+            - CStr: member2
+        - AbbrCode: 0
+        - AbbrCode: 2
+          Values:
+            - CStr: class2
+        - AbbrCode: 6
+          Values:
+            - Value:  0x000000b4
+        - AbbrCode: 3
+          Values:
+            - Value:  0x000000b9
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 7
+          Values:
+            - CStr: int
+        - AbbrCode: 7
+          Values:
+            - CStr: char
+        - AbbrCode: 7
+          Values:
+            - CStr: float
+        - AbbrCode: 8
+          Values:
+            - Value:  0x00000076
+        - AbbrCode: 8
+          Values:
+            - Value:  0x00000099
+        - AbbrCode: 9
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x000000c6
+        - AbbrCode: 9
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x000000cb
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
new file mode 100644
index 000000000000000..7135c46630e13a9
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp
@@ -0,0 +1,192 @@
+/* Compile with:
+   for FILE in `seq 3`; do
+     clang -g -c  odr-member-functions.cpp -DFILE$FILE -o
+   odr-member-functions/$FILE.o done
+ */
+
+// RUN: dsymutil --linker=llvm -f \
+// RUN: -oso-prepend-path=%p/../../Inputs/odr-member-functions \
+// RUN: -y %p/../dummy-debug-map.map -o %t1.out
+// RUN: llvm-dwarfdump -debug-info %t1.out | FileCheck %s
+
+struct S {
+  __attribute__((always_inline)) void foo() { bar(); }
+  __attribute__((always_inline)) void foo(int i) {
+    if (i)
+      bar();
+  }
+  void bar();
+
+  template <typename T> void baz(T t) {}
+};
+
+#ifdef FILE1
+void foo() { S s; }
+
+// First chack that types are moved into the type table unit.
+
+// CHECK: TAG_compile_unit
+// CHECK: AT_name{{.*}}"__artificial_type_unit"
+
+// CHECK: 0x[[INT_BASE:[0-9a-f]*]]: DW_TAG_base_type
+// CHECK-NEXT: DW_AT_name{{.*}}"int"
+
+// CHECK: 0x[[PTR_S:[0-9a-f]*]]:{{.*}}DW_TAG_pointer_type
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[STRUCT_S:[0-9a-f]*]] "S")
+
+// CHECK: 0x[[STRUCT_S]]:{{.*}}DW_TAG_structure_type
+// CHECK-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3barEv"
+// CHECK: DW_AT_name{{.*}}"bar"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// CHECK: 0x[[BAZ_SUBPROGRAM:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3bazIiEEvT_"
+// CHECK: DW_AT_name{{.*}}"baz<int>"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int"
+
+// CHECK: DW_TAG_template_type_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int"
+// CHECK-NEXT: DW_AT_name{{.*}}"T"
+
+// CHECK: 0x[[FOO_Ei:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEi"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int"
+
+// CHECK: 0x[[FOO_Ev:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEv"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *"
+
+// For the second unit check that it references structure "S"
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: {{DW_TAG|NULL}}
+// CHECK: AT_name{{.*}}"odr-member-functions.cpp"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK-NEXT: AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"s"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S"
+
+#elif defined(FILE2)
+void foo() {
+  S s;
+  // Check that the overloaded member functions are resolved correctly
+  s.foo();
+  s.foo(1);
+}
+
+// For the third unit check that it references member functions of structure S.
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-member-functions.cpp"
+
+// CHECK: 0x[[ABASE_FOO_Ev:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK-NEXT: DW_AT_specification {{.*}}(0x00000000[[FOO_Ev]] "_ZN1S3fooEv"
+// CHECK-NEXT: DW_AT_inline    (DW_INL_inlined)
+// CHECK-NEXT: DW_AT_object_pointer {{.*}}(0x[[ABASE_FOO_Ev_PARAM1:[0-9a-f]*]]
+
+// CHECK: 0x[[ABASE_FOO_Ev_PARAM1]]:{{.*}}DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_name{{.*}}"this"
+// CHECK-NEXT: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *"
+
+// CHECK: 0x[[ABASE_FOO_Ei:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
+// CHECK-NEXT: DW_AT_specification {{.*}}(0x00000000[[FOO_Ei]] "_ZN1S3fooEi"
+// CHECK-NEXT: DW_AT_inline    (DW_INL_inlined)
+// CHECK-NEXT: DW_AT_object_pointer {{.*}}(0x[[ABASE_FOO_Ei_PARAM1:[0-9a-f]*]]
+
+// CHECK: 0x[[ABASE_FOO_Ei_PARAM1]]:{{.*}}DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_name{{.*}}"this"
+// CHECK-NEXT: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *"
+
+// CHECK: 0x[[ABASE_FOO_Ei_PARAM2:[0-9a-f]*]]:{{.*}}DW_TAG_formal_parameter
+// CHECK-NEXT: DW_AT_name{{.*}}"i"
+// CHECK: DW_AT_type    (0x00000000[[INT_BASE]] "int"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"s"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S"
+
+// CHECK: DW_TAG_inlined_subroutine
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ev]] "_ZN1S3fooEv"
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ev_PARAM1]] "this"
+
+// CHECK: DW_TAG_inlined_subroutine
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei]] "_ZN1S3fooEi"
+// CHECK: DW_AT_low_pc
+// CHECK: DW_AT_high_pc
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei_PARAM1]] "this"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei_PARAM2]] "i"
+
+#elif defined(FILE3)
+void foo() {
+  S s;
+  s.baz<int>(42);
+}
+
+// For the fourth unit check that it references member functions of structure S.
+
+// CHECK: TAG_compile_unit
+// CHECK-NOT: DW_TAG
+// CHECK: AT_name{{.*}}"odr-member-functions.cpp"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK: DW_AT_name{{.*}}"foo"
+
+// CHECK: DW_TAG_variable
+// CHECK: DW_AT_name{{.*}}"s"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S"
+
+// CHECK: DW_TAG_subprogram
+// CHECK: DW_AT_object_pointer{{.*}}(0x[[INST_PARAM2:[0-9a-f]*]]
+// CHECK: DW_AT_specification{{.*}}(0x00000000[[BAZ_SUBPROGRAM]] "_ZN1S3bazIiEEvT_"
+
+// CHECK: 0x[[INST_PARAM2]]:{{.*}}DW_TAG_formal_parameter
+// CHECK: DW_AT_name{{.*}}"this"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *"
+
+// CHECK: DW_TAG_formal_parameter
+// CHECK: DW_AT_name{{.*}}"t"
+// CHECK: DW_AT_type{{.*}}(0x00000000[[INT_BASE]] "int"
+
+// CHECK: DW_TAG_template_type_parameter
+// CHECK: DW_AT_type{{.*}}(0x00000000[[INT_BASE]] "int"
+// CHECK: DW_AT_name{{.*}}"T"
+
+#else
+#error "You must define which file you generate"
+#endif

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
new file mode 100644
index 000000000000000..6c31b48978e9828
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test
@@ -0,0 +1,157 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks that DW_TAG_namespace with DW_AT_extension
+## attribute is joined with referenced namespace.
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: 0x0000000b: DW_TAG_compile_unit
+# CHECK: DW_TAG_namespace
+# CHECK: DW_AT_name{{.*}}"parent_namespace"
+# CHECK-NOT: DW_TAG_namespace
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_type      (0x00000000[[INT]]
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x2A
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0x42
+        offset:    0x000003AA
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x000001FC
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          false
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           1
+    stroff:          0x710
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+      - Tag:      DW_TAG_namespace
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_namespace
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_extension
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+        - AbbrCode: 2
+          Values:
+            - CStr: parent_namespace
+        - AbbrCode: 3
+          Values:
+            - Value:  0x00000016
+        - AbbrCode: 4
+          Values:
+            - CStr: int
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: var
+            - Value:  0x000000FF
+            - Value:  0x0000002d
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
new file mode 100644
index 000000000000000..22a142ab97657c6
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test
@@ -0,0 +1,384 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks that nested structure containing field of anonymuos type
+## partially moved into the type table. Anonymous part of the structure should be
+## left in the original containg compile unit:
+##
+## CU1:
+##
+## struct s1 { struct s2; }
+##
+## namespace {
+##   struct s3 {};
+## }
+##
+## struct s1::s2 { s3 m; };
+##
+## struct s1::s2 *var1;
+## struct s1::s2::s3 *var2;
+##
+## CU2:
+##
+## struct s1 { struct s2; }
+##
+## struct s1::s2 *var3;
+##
+##
+## Final type table should contain:
+##
+## DW_TAG_compile_unit
+##   DW_AT_name        ("__type_table")
+##
+##   DW_TAG_structure_type
+##     DW_AT_name      ("s1")
+##
+##     DW_TAG_structure_type
+##       DW_AT_name    ("s2")
+##       DW_AT_declaration     (true)
+##
+## CU1 should contain:
+##
+## DW_TAG_compile_unit
+##   DW_AT_name        ("CU1")
+##
+##   DW_TAG_structure_type
+##     DW_AT_name      ("s1")
+##
+##     DW_TAG_structure_type
+##       DW_AT_name    ("s2")
+##
+##       DW_TAG_member
+##         DW_AT_name  ("m")
+##         DW_AT_type  ("(anonymous namespace)::s3")
+##
+##   DW_TAG_namespace
+##
+##     DW_TAG_structure_type
+##       DW_AT_name    ("s3")
+##
+##   DW_TAG_variable
+##     DW_AT_name      ("var1")
+##     DW_AT_type      ("s1::s2 *")
+##
+##   DW_TAG_variable
+##     DW_AT_name      ("var2")
+##     DW_AT_type      ("s1::s2::m *")
+##
+## CU2  should contain:
+##
+## DW_TAG_compile_unit
+##   DW_AT_name        ("CU2")
+##
+##  DW_TAG_variable
+##     DW_AT_name      ("var3")
+##     DW_AT_type      ("s1::s2 *")
+##
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2")
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s1"
+
+# CHECK: 0x[[INNER_STRUCT:[0-9a-f]*]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s2"
+# CHECK: DW_AT_declaration{{.*}}true
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s1"
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s2"
+
+# CHECK: 0x[[INNER_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"m"
+# CHECK: DW_AT_type{{.*}}0x[[ANON_STRUCT:[0-9a-f]*]] "(anonymous namespace)::s3"
+
+# CHECK: DW_TAG_namespace
+# CHECK: 0x[[ANON_STRUCT]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s3"
+
+# CHECK: 0x[[ANON_PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2")
+
+# CHECK: 0x[[PTR_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT_MEMBER]] "m"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x[[ANON_PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x[[PTR_STRUCT_MEMBER]] "m *"
+
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var3"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var4"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x76
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0xa7
+        offset:    0x000003f6
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x0
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           2
+    stroff:          0x720
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_namespace
+        Children: DW_CHILDREN_yes
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+        - AbbrCode: 2
+          Values:
+            - CStr: s1
+        - AbbrCode: 2
+          Values:
+            - CStr: s2
+        - AbbrCode: 4
+          Values:
+            - CStr: m
+            - Value:  0x0000002c
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 7
+        - AbbrCode: 3
+          Values:
+            - CStr: s3
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: int
+        - AbbrCode: 6
+          Values:
+            - Value:  0x0000001e
+        - AbbrCode: 6
+          Values:
+            - Value:  0x00000022
+        - AbbrCode: 8
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x00000036
+        - AbbrCode: 8
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x0000003b
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU2
+        - AbbrCode: 2
+          Values:
+            - CStr: s1
+        - AbbrCode: 3
+          Values:
+            - CStr: s2
+        - AbbrCode: 0
+        - AbbrCode: 4
+          Values:
+            - CStr: int
+        - AbbrCode: 5
+          Values:
+            - Value:  0x0000007b
+        - AbbrCode: 6
+          Values:
+            - CStr: var3
+            - Value:  0x00000000
+            - Value:  0x00000085
+        - AbbrCode: 6
+          Values:
+            - CStr: var4
+            - Value:  0x00000000
+            - Value:  0x00000085
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
new file mode 100644
index 000000000000000..35d3261e591cb3b
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test
@@ -0,0 +1,374 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+## This test checks that nested structure containing field of type from other namespace
+## fully moved into the type table.
+##
+## CU1:
+##
+## struct s1 { struct s2; }
+##
+## namespace namespace1 {
+##   struct s3 {};
+## }
+##
+## struct s1::s2 { s3 m; };
+##
+## struct s1::s2 *var1;
+## struct s1::s2::s3 *var2;
+##
+## CU2:
+##
+## struct s1 { struct s2; }
+##
+## struct s1::s2 *var3;
+##
+##
+## Final type table should contain:
+##
+## DW_TAG_compile_unit
+##   DW_AT_name        ("__type_table")
+##
+##   DW_TAG_namespace
+##     DW_AT_name      ("namespace1")
+##
+##     DW_TAG_structure_type
+##       DW_AT_name    ("s3")
+##
+##   DW_TAG_structure_type
+##     DW_AT_name      ("s1")
+##
+##     DW_TAG_structure_type
+##       DW_AT_name    ("s2")
+##
+##       DW_TAG_member
+##         DW_AT_name  ("m")
+##         DW_AT_type  ("namespace1::s3")
+##
+## CU1 should contain:
+##
+## DW_TAG_compile_unit
+##   DW_AT_name        ("CU1")
+##
+##   DW_TAG_variable
+##     DW_AT_name      ("var1")
+##     DW_AT_type      ("s1::s2 *")
+##
+##   DW_TAG_variable
+##     DW_AT_name      ("var2")
+##     DW_AT_type      ("s1::s2::m *")
+##
+## CU2 should contain:
+##
+## DW_TAG_compile_unit
+##   DW_AT_name        ("CU2")
+##
+##   DW_TAG_variable
+##     DW_AT_name      ("var1")
+##     DW_AT_type      ("s1::s2 *")
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: DW_TAG_namespace
+# CHECK: DW_AT_name{{.*}}"namespace1"
+# CHECK: 0x[[NAMESPACE_STRUCT:[0-9a-f]*]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s3"
+
+# CHECK: 0x[[PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2")
+
+# CHECK: 0x[[PTR_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT_MEMBER:[0-9a-f]*]] "m"
+
+# CHECK: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"s1"
+
+# CHECK: 0x[[INNER_STRUCT]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s2"
+# CHECK-NOT: DW_AT_declaration
+
+# CHECK: 0x[[INNER_STRUCT_MEMBER]]: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"m"
+# CHECK: DW_AT_type{{.*}}0x[[NAMESPACE_STRUCT]] "namespace1::s3"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_STRUCT_MEMBER]] "m *"
+
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var3"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var4"
+# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *"
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x78
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0xb2
+        offset:    0x000003F8
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x0
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           2
+    stroff:          0x720
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_namespace
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_declaration
+            Form:      DW_FORM_flag_present
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+        - AbbrCode: 2
+          Values:
+            - CStr: s1
+        - AbbrCode: 2
+          Values:
+            - CStr: s2
+        - AbbrCode: 4
+          Values:
+            - CStr: m
+            - Value:  0x00000037
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 7
+          Values:
+            - CStr: namespace1
+        - AbbrCode: 3
+          Values:
+            - CStr: s3
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: int
+        - AbbrCode: 6
+          Values:
+            - Value:  0x0000001e
+        - AbbrCode: 6
+          Values:
+            - Value:  0x00000022
+        - AbbrCode: 8
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x00000041
+        - AbbrCode: 8
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x00000046
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU2
+        - AbbrCode: 2
+          Values:
+            - CStr: s1
+        - AbbrCode: 3
+          Values:
+            - CStr: s2
+        - AbbrCode: 0
+        - AbbrCode: 4
+          Values:
+            - CStr: int
+        - AbbrCode: 5
+          Values:
+            - Value:  0x00000086
+        - AbbrCode: 6
+          Values:
+            - CStr: var3
+            - Value:  0x00000000
+            - Value:  0x00000090
+        - AbbrCode: 6
+          Values:
+            - CStr: var4
+            - Value:  0x00000000
+            - Value:  0x00000090
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
new file mode 100644
index 000000000000000..7c1c0d1b52e0eec
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test
@@ -0,0 +1,238 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+## This test checks debug info for the equally named structures from
+## 
diff erent namespaces. The result should contain two variables which
+## reference 
diff erent types("A::C1::I1 *const" and "B::C1::I1 *const")
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK: DW_TAG_namespace{{.*[[:space:]].*}}DW_AT_name{{.*}}"A"
+
+# CHECK: 0x[[A_C1:[0-9a-f]*]]: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"C1"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[INT]] "int"
+# CHECK: DW_AT_name{{.*}}"I1"
+
+# CHECK: DW_TAG_namespace{{.*[[:space:]].*}}DW_AT_name{{.*}}"B"
+
+# CHECK: 0x[[B_C1:[0-9a-f]*]]: DW_TAG_structure_type
+# CHECK: DW_AT_name{{.*}}"C1"
+# CHECK: DW_TAG_member
+# CHECK: DW_AT_type{{.*}}0x[[INT]] "int"
+# CHECK: DW_AT_name{{.*}}"I1"
+
+# CHECK: 0x[[PTR_A_C1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[A_C1:[0-9a-f]*]] "A::C1"
+
+# CHECK: 0x[[PTR_B_C1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[B_C1:[0-9a-f]*]] "B::C1"
+
+# CHECK: 0x[[CONST_A_C1:[0-9a-f]*]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[PTR_A_C1]] "A::C1 *"
+
+# CHECK: 0x[[CONST_B_C1:[0-9a-f]*]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[PTR_B_C1]] "B::C1 *"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONST_A_C1]] "A::C1 *const"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONST_B_C1]] "B::C1 *const"
+
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x41
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0x6e
+        offset:    0x000003C1
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x000001FC
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          false
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           1
+    stroff:          0x710
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+      - Tag:      DW_TAG_namespace
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_structure_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_const_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+        - AbbrCode: 2
+          Values:
+            - CStr: A
+        - AbbrCode: 3
+          Values:
+            - CStr: C1
+        - AbbrCode: 4
+          Values:
+            - Value:  0x00000038
+            - CStr: I1
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 2
+          Values:
+            - CStr: B
+        - AbbrCode: 3
+          Values:
+            - CStr: C1
+        - AbbrCode: 4
+          Values:
+            - Value:  0x00000038
+            - CStr: I1
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: int
+        - AbbrCode: 6
+          Values:
+            - Value:  0x00000019
+        - AbbrCode: 6
+          Values:
+            - Value:  0x0000002a
+        - AbbrCode: 7
+          Values:
+            - Value:  0x0000003D
+        - AbbrCode: 7
+          Values:
+            - Value:  0x00000042
+        - AbbrCode: 8
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x00000047
+        - AbbrCode: 8
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x0000004C
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
new file mode 100644
index 000000000000000..187a2ea9ecffdcd
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test
@@ -0,0 +1,117 @@
+# RUN: dsymutil --linker=llvm -f -o %t1.o -oso-prepend-path=%p/ -y %s
+# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 1 | llvm-dwarfdump -a - -o %t1
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 3 | llvm-dwarfdump -a - -o %t2
+# RUN: 
diff  %t1 %t2
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 4 | llvm-dwarfdump -a - -o %t3
+# RUN: 
diff  %t1 %t3
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s | llvm-dwarfdump -a - -o %t4
+# RUN: 
diff  %t1 %t4
+
+# This test checks that generated output does not 
diff er between runs.
+#
+# To recreate a test compile following example:
+#
+# main.cpp:
+#
+# include <string>
+#
+# void PrintSize ( const std::string& String );
+# void PrintNewString ( const std::string& String );
+# void PrintNewString2 ( const char* String );
+#
+# int main ( void ) {
+#
+#   PrintSize("hello");
+#   PrintNewString("hello");
+#   PrintNewString2("hello");
+#   printf("\n");
+#
+#   return 0;
+# }
+#
+# foo1.cpp:
+#
+# #include <string>
+#
+# void PrintSize ( const std::string& String ) {
+#   printf("\n String size %lu", String.size() );
+# };
+#
+# foo2.cpp:
+#
+# #include <string>
+#
+# void PrintNewString ( const std::string& String ) {
+#  std::string NewString(String);
+#  NewString += "++";
+#  printf("\n String %s", NewString.c_str());
+#};
+#
+# foo3.cpp:
+# #include <string>
+#
+# void PrintNewString2 ( const char* String ) {
+#   std::string NewString(String);
+#   NewString += "++";
+#   printf("\n String2 %s", NewString.c_str());
+# };
+#
+# with clang++ -O -fno-inline -g -std=c++11
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename:        'Inputs/String/foo1.o'
+    timestamp:       1638904719
+    symbols:
+      - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 }
+      - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 }
+      - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 }
+  - filename:        'Inputs/String/foo2.o'
+    timestamp:       1638904723
+    symbols:
+      - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 }
+      - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 }
+      - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 }
+      - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 }
+      - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 }
+  - filename:        'Inputs/String/foo3.o'
+    timestamp:       1638904727
+    symbols:
+      - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D50, size: 0x00000040 }
+      - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 }
+      - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D40, size: 0x00000010 }
+      - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 }
+      - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 }
+      - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 }
+      - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 }
+      - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 }
+      - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 }
+      - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 }
+  - filename:        'Inputs/String/main.o'
+    timestamp:       1638904734
+    symbols:
+      - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 }
+      - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 }
+...
+
+VERIFY: Verifying .debug_abbrev...
+VERIFY: Verifying .debug_info Unit Header Chain...
+VERIFY: Verifying .apple_names...
+VERIFY: Verifying .apple_types...
+VERIFY: Verifying .apple_namespaces...
+VERIFY: Verifying .apple_objc...
+VERIFY: No errors.

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
new file mode 100644
index 000000000000000..93925c61c46b8b4
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test
@@ -0,0 +1,120 @@
+# RUN: dsymutil --linker=llvm -f -o %t1.o -oso-prepend-path=%p/../ -y %s
+# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --linker=llvm -f -o %t2.o -oso-prepend-path=%p/../ -y %s
+# RUN: dsymutil --linker=llvm -f -o %t3.o -oso-prepend-path=%p/../ -y %s \
+# RUN:   --num-threads 1
+# RUN: dsymutil --linker=llvm -f -o %t4.o -oso-prepend-path=%p/../ -y %s \
+# RUN:   --num-threads 3
+# ### Following comparision will fail if files do not match
+# RUN: 
diff  %t1.o %t2.o
+# RUN: 
diff  %t1.o %t3.o
+# RUN: 
diff  %t1.o %t4.o
+
+# This test checks that generated output does not 
diff er between runs.
+#
+# To recreate a test compile following example:
+#
+# main.cpp:
+#
+# include <string>
+#
+# void PrintSize ( const std::string& String );
+# void PrintNewString ( const std::string& String );
+# void PrintNewString2 ( const char* String );
+#
+# int main ( void ) {
+#
+#   PrintSize("hello");
+#   PrintNewString("hello");
+#   PrintNewString2("hello");
+#   printf("\n");
+#
+#   return 0;
+# }
+#
+# foo1.cpp:
+#
+# #include <string>
+#
+# void PrintSize ( const std::string& String ) {
+#   printf("\n String size %lu", String.size() );
+# };
+#
+# foo2.cpp:
+#
+# #include <string>
+#
+# void PrintNewString ( const std::string& String ) {
+#  std::string NewString(String);
+#  NewString += "++";
+#  printf("\n String %s", NewString.c_str());
+#};
+#
+# foo3.cpp:
+# #include <string>
+#
+# void PrintNewString2 ( const char* String ) {
+#   std::string NewString(String);
+#   NewString += "++";
+#   printf("\n String2 %s", NewString.c_str());
+# };
+#
+# with clang++ -O -fno-inline -g -std=c++11
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename:        'Inputs/String/foo1.o'
+    timestamp:       1638904719
+    symbols:
+      - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 }
+      - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 }
+      - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 }
+  - filename:        'Inputs/String/foo2.o'
+    timestamp:       1638904723
+    symbols:
+      - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 }
+      - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 }
+      - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 }
+      - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 }
+      - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 }
+  - filename:        'Inputs/String/foo3.o'
+    timestamp:       1638904727
+    symbols:
+      - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D40, size: 0x00000040 }
+      - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 }
+      - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D50, size: 0x00000010 }
+      - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 }
+      - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 }
+      - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 }
+      - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 }
+      - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 }
+      - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 }
+      - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 }
+  - filename:        'Inputs/String/main.o'
+    timestamp:       1638904734
+    symbols:
+      - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 }
+      - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 }
+...
+
+VERIFY: Verifying .debug_abbrev...
+VERIFY: Verifying .debug_info Unit Header Chain...
+VERIFY: Verifying .debug_types Unit Header Chain...
+VERIFY: Verifying .apple_names...
+VERIFY: Verifying .apple_types...
+VERIFY: Verifying .apple_namespaces...
+VERIFY: Verifying .apple_objc...
+VERIFY: No errors.

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
new file mode 100644
index 000000000000000..619bc8c15b8229c
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test
@@ -0,0 +1,245 @@
+## This test checks output of dsymutil for the incorrect DWARF.
+## CU1 has a type which references type in CU2. This referenced
+## type references the same type in CU1 back. There is a recursive
+## dependence between these two types. dsymutil should report a error,
+## remove CU1 and CU2, put only CU3 into the output.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker llvm -y %t2.map --num-threads 1 -f -o %t1.out 2>&1 \
+# RUN:   | FileCheck --check-prefix ERROR %s
+# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s
+
+# ERROR: error: Cann't parse input DWARF. Recursive dependence.
+# ERROR: while processing CU1
+# ERROR: error: Cann't resolve DIE reference
+# ERROR: while processing CU2
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1"
+
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK-NOT: "CU1"
+# CHECK-NOT: "CU2"
+# CHECK: DW_AT_name{{.*}}"CU3"
+# CHECK-NOT: DW_TAG_class_type
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var3"
+# CHECK: DW_AT_const_value
+# CHECK: DW_AT_type (0x00000000[[CLASS1]]
+
+# CHECK-NOT: Compile Unit:
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x5a
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0x8d
+        offset:    0x00000410
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x1FC
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           2
+    stroff:          0x720
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+        - AbbrCode: 2
+          Values:
+            - Value:  0x48
+        - AbbrCode: 3
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x0000001a
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU2
+        - AbbrCode: 2
+          Values:
+            - Value: 0x1a
+        - AbbrCode: 3
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x0000001a
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU3
+        - AbbrCode: 2
+          Values:
+            - CStr: class1
+        - AbbrCode: 3
+          Values:
+            - CStr: var3
+            - Value:  0x00000000
+            - Value:  0x0000001a
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
new file mode 100644
index 000000000000000..a8fc3e82311ca50
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test
@@ -0,0 +1,180 @@
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/../ -y %s | llvm-dwarfdump --verify - | FileCheck -check-prefixes=VERIFY %s
+# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/../ -y %s | llvm-dwarfdump -a - | FileCheck %s
+
+# This test checks that types from several object files are
+# uniqued(moved into the artificial compile unit for types).
+# It also checks that information between 
diff erent debug
+# tables is consistent.
+#
+# To recreate a test compile following example:
+#
+# main.cpp:
+#
+# include <string>
+#
+# void PrintSize ( const std::string& String );
+# void PrintNewString ( const std::string& String );
+# void PrintNewString2 ( const char* String );
+#
+# int main ( void ) {
+#
+#   PrintSize("hello");
+#   PrintNewString("hello");
+#   PrintNewString2("hello");
+#   printf("\n");
+#
+#   return 0;
+# }
+#
+# foo1.cpp:
+#
+# #include <string>
+#
+# void PrintSize ( const std::string& String ) {
+#   printf("\n String size %lu", String.size() );
+# };
+#
+# foo2.cpp:
+#
+# #include <string>
+#
+# void PrintNewString ( const std::string& String ) {
+#  std::string NewString(String);
+#  NewString += "++";
+#  printf("\n String %s", NewString.c_str());
+#};
+#
+# foo3.cpp:
+# #include <string>
+#
+# void PrintNewString2 ( const char* String ) {
+#   std::string NewString(String);
+#   NewString += "++";
+#   printf("\n String2 %s", NewString.c_str());
+# };
+#
+# with clang++ -O -fno-inline -g -std=c++11
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename:        'Inputs/String/foo1.o'
+    timestamp:       1638904719
+    symbols:
+      - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 }
+      - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 }
+      - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 }
+  - filename:        'Inputs/String/foo2.o'
+    timestamp:       1638904723
+    symbols:
+      - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 }
+      - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 }
+      - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 }
+      - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 }
+      - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 }
+      - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 }
+  - filename:        'Inputs/String/foo3.o'
+    timestamp:       1638904727
+    symbols:
+      - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D40, size: 0x00000040 }
+      - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 }
+      - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D50, size: 0x00000010 }
+      - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 }
+      - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 }
+      - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 }
+      - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 }
+      - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 }
+      - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 }
+      - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 }
+      - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 }
+  - filename:        'Inputs/String/main.o'
+    timestamp:       1638904734
+    symbols:
+      - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 }
+      - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 }
+...
+
+VERIFY: Verifying .debug_abbrev...
+VERIFY: Verifying .debug_info Unit Header Chain...
+VERIFY: Verifying .debug_types Unit Header Chain...
+VERIFY: Verifying .apple_names...
+VERIFY: Verifying .apple_types...
+VERIFY: Verifying .apple_namespaces...
+VERIFY: Verifying .apple_objc...
+VERIFY: No errors.
+
+CHECK: .debug_info contents:
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+CHECK:DW_TAG_base_type
+
+CHECK: 0x[[BASE_INT:[0-9a-f]*]]: DW_TAG_base_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"int"
+
+CHECK:DW_TAG_class_type
+
+CHECK: 0x[[BASIC_STRING:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_calling_convention{{.*}}{{.*[[:space:]].*}}DW_AT_name{{.*}}"basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"
+
+CHECK:DW_TAG_typedef
+
+CHECK: 0x[[STRING:[0-9a-f]*]]: DW_TAG_typedef{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[BASIC_STRING]] "std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"){{.*[[:space:]].*}}DW_AT_name{{.*}}"string"
+
+CHECK:DW_TAG_reference_type
+
+CHECK: 0x[[CONST_STR_REF:[0-9a-f]*]]: DW_TAG_reference_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CONST_STRING:[0-9a-f]*]] "const string"
+
+CHECK:DW_TAG_const_type
+
+CHECK: 0x[[CONST_STRING]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[STRING]] "string"
+
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"foo1.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"PrintSize"
+CHECK: DW_TAG_formal_parameter
+CHECK: DW_AT_name{{.*}}"String"
+CHECK: DW_AT_type{{.*}}0x00000000[[CONST_STR_REF]] "const string &"
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"foo2.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"PrintNewString"
+CHECK: DW_TAG_formal_parameter
+CHECK: DW_AT_name{{.*}}"String"
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"foo3.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"PrintNewString2"
+CHECK: DW_TAG_formal_parameter
+CHECK: DW_AT_name{{.*}}"String"
+
+CHECK: Compile Unit:
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name{{.*}}"main.cpp"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_low_pc
+CHECK: DW_AT_high_pc
+CHECK: DW_AT_name{{.*}}"main"
+CHECK: DW_AT_type{{.*}}0x00000000[[BASE_INT]] "int"

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
new file mode 100644
index 000000000000000..67b5616ebd5922e
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test
@@ -0,0 +1,201 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+## This test checks debug info for the template parameters of the class.
+## (i.e. number of the parameters is correct, names of the parameters
+## are correct, types of the parameters are correct)
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: 0x0000000b: DW_TAG_compile_unit
+# CHECK: DW_AT_producer{{.*}}"llvm DWARFLinkerParallel library version
+# CHECK: DW_AT_language{{.*}}DW_LANG_C_plus_plus
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"char"
+# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"float"
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+# CHECK: 0x[[CLASS:[0-9a-f]*]]: DW_TAG_class_type
+# CHECK: DW_AT_name{{.*}}"parametrized-class"
+# CHECK: DW_TAG_template_type_parameter
+# CHECK: DW_AT_type{{.*}}(0x[[INT]] "int"
+# CHECK: DW_AT_name{{.*}}"Type1"
+# CHECK: DW_AT_type{{.*}}(0x[[CHAR]] "char"
+# CHECK: DW_AT_name{{.*}}"Type2"
+# CHECK: DW_AT_type{{.*}}(0x[[FLOAT]] "float"
+# CHECK: DW_AT_name{{.*}}"Type3"
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_type      (0x00000000[[CLASS]]
+
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x37
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0x7B
+        offset:    0x000003B7
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x000001FC
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          false
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           1
+    stroff:          0x710
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_template_type_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_template_value_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+        - AbbrCode: 2
+          Values:
+            - CStr: parametrized-class
+        - AbbrCode: 3
+          Values:
+            - Value:  0x0000005B
+            - CStr: Type1
+        - AbbrCode: 3
+          Values:
+            - Value:  0x00000060
+            - CStr: Type2
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000005B
+            - CStr: Type1
+            - Value:  0x0FE
+        - AbbrCode: 3
+          Values:
+            - Value:  0x00000066
+            - CStr: Type3
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: int
+        - AbbrCode: 5
+          Values:
+            - CStr: char
+        - AbbrCode: 5
+          Values:
+            - CStr: float
+        - AbbrCode: 6
+          Values:
+            - CStr: var
+            - Value:  0x000000FF
+            - Value:  0x00000016
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
new file mode 100644
index 000000000000000..5bc034b54df8300
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test
@@ -0,0 +1,205 @@
+## This test checks debug info for the types located into the
+## 
diff erent compilation units from the single object file.
+## Type definition for the "class1" should be moved to the
+## artificial type unit from the first and second compilation unit.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1"
+
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+# CHECK-NOT: DW_TAG_class_type
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_const_value
+# CHECK: DW_AT_type (0x00000000[[CLASS1]]
+
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+# CHECK-NOT: DW_TAG_class_type
+# CHECK-NOT: "class1"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_const_value
+# CHECK: DW_AT_type (0x00000000[[CLASS1]]
+
+
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x3c
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0x62
+        offset:    0x00000410
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x1FC
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           2
+    stroff:          0x720
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+        - AbbrCode: 2
+          Values:
+            - CStr: class1
+        - AbbrCode: 3
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x0000001a
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU2
+        - AbbrCode: 2
+          Values:
+            - CStr: class1
+        - AbbrCode: 3
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x0000001a
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
new file mode 100644
index 000000000000000..1af38080c705fb7
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test
@@ -0,0 +1,431 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: echo '---' > %t2.map
+# RUN: echo "triple:          'x86_64-apple-darwin'" >> %t2.map
+# RUN: echo 'objects:'  >> %t2.map
+# RUN: echo " -  filename: '%t.o'" >> %t2.map
+# RUN: echo '    symbols:' >> %t2.map
+# RUN: echo '      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map
+# RUN: echo '...' >> %t2.map
+# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s
+
+## This test checks debug info for the types located into the subprograms.
+## Subprogram "float foo(int)" contains type "clas1". First compile unit
+## contains partially defined class "Container" which has parametrized
+## subprogram "ParametrizedFunc" which template parameter is the type
+## "clas1" defined in the subprogram "foo". The second compilation unit
+## contains partially defined class "Container" which has parametrized
+## subprogram "ParametrizedFunc" which template parameter is the type
+## "int". The type table in the final debug info should contain class
+## "Container" which has two "ParametrizedFunc"(one has template parameter
+## "clas1" and another has template parameter "int").
+
+## class Container {
+##   template<T> void ParametrizedFunc ();
+## };
+##
+## CU1:
+##
+## int foo (float) {
+##   class clas1 {
+##     char first;
+##     float second;
+##   } clas1;
+## };
+##
+## class Container {
+##   template<foo:clas1> void ParametrizedFunc ();
+## };
+##
+## CU2:
+##
+## class Container {
+##   template<int> void ParametrizedFunc ();
+## };
+##
+##
+## The final type table :
+##
+## class Container {
+##   template<int> void ParametrizedFunc ();
+## };
+##
+## CU1:
+##
+## int foo (float) {
+##   class clas1 {
+##     char first;
+##     float second;
+##   } clas1;
+## };
+##
+## class Container {
+##   template<foo:clas1> void ParametrizedFunc ();
+## };
+##
+##
+
+
+# CHECK: file format Mach-O 64-bit x86-64
+# CHECK: .debug_info contents:
+# CHECK: Compile Unit:
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"__artificial_type_unit"
+
+# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"char"
+
+# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"float"
+
+# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK: 0x[[CONTAINER:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"Container"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"ParametrizedFunc"
+# CHECK: DW_AT_type{{.*}}[[INT]] "int"
+# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"ParametrizedFunc"
+# CHECK: DW_AT_type{{.*}}[[INT]] "int"
+# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_CLASS:[0-9a-f]*]] "clas1"
+
+# CHECK: 0x[[GLOBAL_CLASS:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"clas1"
+
+# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"first"
+
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"foo"
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+# CHECK: DW_TAG_formal_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int"
+
+# CHECK: 0x[[INNER_CLASS]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"clas1"
+# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"first"
+# CHECK: DW_AT_type{{.*}}[[CHAR]] "char"
+# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"second"
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU1"
+
+# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"foo"
+# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float"
+# CHECK: DW_AT_low_pc
+# CHECK: DW_AT_high_pc
+# CHECK: DW_TAG_formal_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}[[INT]] "int"
+
+# CHECK-NOT: DW_TAG_class_type
+# CHECK-NOT: DW_TAG_member
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[GLOBAL_CLASS]] "clas1"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var2"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONTAINER]] "Container"
+
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name{{.*}}"CU2"
+
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name{{.*}}"var1"
+# CHECK: DW_AT_type{{.*}}0x00000000[[CONTAINER]] "Container"
+
+
+--- !mach-o
+FileHeader:
+  magic:      0xFEEDFACF
+  cputype:    0x01000007
+  cpusubtype: 0x00000003
+  filetype:   0x00000001
+  ncmds:      2
+  sizeofcmds: 376
+  flags:      0x00002000
+  reserved:   0x00000000
+LoadCommands:
+  - cmd:      LC_SEGMENT_64
+    cmdsize:  232
+    segname:  ''
+    vmaddr:   0x00
+    vmsize:   0x300
+    fileoff:  0x300
+    filesize: 0x300
+    maxprot:  7
+    initprot: 7
+    nsects:   2
+    flags:    0
+    Sections:
+      - sectname:  __debug_abbrev
+        segname:   __DWARF
+        addr:      0x000000000000000F
+        size:      0x90
+        offset:    0x00000380
+        align:     0
+        reloff:    0x00000000
+        nreloc:    0
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+      - sectname:  __debug_info
+        segname:   __DWARF
+        addr:      0x000000000000100
+        size:      0x124
+        offset:    0x00000410
+        align:     0
+        reloff:    0x00000600
+        nreloc:    1
+        flags:     0x02000000
+        reserved1: 0x00000000
+        reserved2: 0x00000000
+        reserved3: 0x00000000
+        relocations:
+          - address:         0x2C
+            symbolnum:       1
+            pcrel:           true
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0x700
+    nsyms:           2
+    stroff:          0x720
+    strsize:         10
+LinkEditData:
+  NameList:
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0x0F
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - '__Z3foov'
+    - ''
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_linkage_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data4
+      - Tag:      DW_TAG_formal_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_member
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_template_type_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_pointer_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_class_type
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_template_type_parameter
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_data4
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref_addr
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+        - AbbrCode: 2
+          Values:
+            - CStr: foo
+            - CStr: __Z3foov
+            - Value:  0x000000a3
+            - Value:  0x00010000
+            - Value:  0x00000010
+        - AbbrCode: 3
+          Values:
+            - Value:  0x00000098
+        - AbbrCode: 4
+          Values:
+            - CStr: clas1
+        - AbbrCode: 5
+          Values:
+            - CStr: first
+            - Value:  0x0000009d
+        - AbbrCode: 5
+          Values:
+            - CStr: second
+            - Value:  0x000000a3
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 4
+          Values:
+            - CStr: clas1
+        - AbbrCode: 5
+          Values:
+            - CStr: first
+            - Value:  0x000000a3
+        - AbbrCode: 0
+        - AbbrCode: 4
+          Values:
+            - CStr: Container
+        - AbbrCode: 6
+          Values:
+            - CStr: ParametrizedFunc
+            - Value:  0x00000098
+        - AbbrCode: 7
+          Values:
+            - Value:  0x0000003d
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 8
+          Values:
+            - CStr: int
+        - AbbrCode: 8
+          Values:
+            - CStr: char
+        - AbbrCode: 8
+          Values:
+            - CStr: float
+        - AbbrCode: 10
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x0000005d
+        - AbbrCode: 10
+          Values:
+            - CStr: var2
+            - Value:  0x00000000
+            - Value:  0x00000070
+        - AbbrCode: 0
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU2
+        - AbbrCode: 2
+          Values:
+            - CStr: Container
+        - AbbrCode: 3
+          Values:
+            - CStr: ParametrizedFunc
+            - Value:  0x00000109
+        - AbbrCode: 4
+          Values:
+            - Value:  0x00000109
+        - AbbrCode: 0
+        - AbbrCode: 0
+        - AbbrCode: 5
+          Values:
+            - CStr: int
+        - AbbrCode: 5
+          Values:
+            - CStr: float
+        - AbbrCode: 6
+          Values:
+            - CStr: var1
+            - Value:  0x00000000
+            - Value:  0x000000e1
+        - AbbrCode: 0
+...

diff  --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
new file mode 100644
index 000000000000000..c7cb663d42febb9
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp
@@ -0,0 +1,475 @@
+/* Compile with:
+   clang -g -c  odr-uniquing.cpp -o odr-uniquing/1.o
+   cp odr-uniquing/1.o odr-uniquing/2.o
+   The aim of these test is to check that all the 'type types' that
+   should be uniqued through the ODR really are.
+
+   The resulting object file is linked against itself using a fake
+   debug map. The end result is:
+    - with ODR uniquing: all types in second and third CUs should point back
+   to the types of the first CU(except types from anonymous namespace).
+    - without ODR uniquing: all types are re-emited in the second CU.
+ */
+
+/* Check by llvm-dwarfdump --verify */
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -o - | llvm-dwarfdump --verify - | \
+// RUN: FileCheck -check-prefixes=VERIFY %s
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -no-odr -o - | llvm-dwarfdump --verify - | \
+// RUN: FileCheck -check-prefixes=VERIFY %s
+
+/* Check for llvm-dwarfdump -a output */
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -o - | llvm-dwarfdump -v -a - | \
+// RUN: FileCheck -check-prefixes=CHECK %s
+// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \
+// RUN: -y %p/../dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -a - | \
+// RUN: FileCheck -check-prefixes=CHECK-NOODR %s
+
+struct S {
+  struct Nested {};
+};
+
+namespace N {
+class C {};
+} // namespace N
+
+union U {
+  class C {
+  } C;
+  struct S {
+  } S;
+};
+
+typedef S AliasForS;
+
+namespace {
+class AnonC {};
+} // namespace
+
+// This function is only here to hold objects that refer to the above types.
+void foo() {
+  AliasForS s;
+  S::Nested n;
+  N::C nc;
+  AnonC ac;
+  U u;
+}
+
+// VERIFY: Verifying .debug_abbrev...
+// VERIFY: Verifying .debug_info Unit Header Chain...
+// VERIFY: Verifying .debug_types Unit Header Chain...
+// VERIFY: Verifying .apple_names...
+// VERIFY: Verifying .apple_types...
+// VERIFY: Verifying .apple_namespaces...
+// VERIFY: Verifying .apple_objc...
+// VERIFY: No errors.
+
+// The first compile unit contains all the types:
+// CHECK: .debug_info contents
+// CHECK: DW_TAG_compile_unit
+// CHECK: DW_AT_language{{.*}} (DW_LANG_C_plus_plus)
+// CHECK: DW_AT_name{{.*}}"__artificial_type_unit")
+// CHECK: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF1:[0-9a-f]*]])
+
+// CHECK:0x[[N_NAMESPACE:[0-9a-f]*]]:{{.*}}DW_TAG_namespace
+// CHECK:DW_AT_name{{.*}}"N"
+
+// CHECK:0x[[C_CLASS:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"C"
+// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01)
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (35)
+
+// CHECK:0x[[S_STRUCTURE:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+// CHECK:DW_AT_name{{.*}}"S"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (22)
+
+// CHECK:0x[[S_STRUCTURE_NESTED:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+// CHECK:DW_AT_name{{.*}}"Nested"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp")
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1]       (23)
+
+// CHECK:0x[[TYPEDEF_ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef
+// CHECK:DW_AT_name{{.*}}"AliasForS"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (58)
+
+// CHECK:0x[[U_UNION:[0-9a-f]*]]:{{.*}}DW_TAG_union_type
+// CHECK:DW_AT_name{{.*}}"U"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (45)
+
+// CHECK:0x[[U_C_CLASS:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"C"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (46)
+
+// CHECK:0x[[U_C_MEMBER:[0-9a-f]*]]:{{.*}}DW_TAG_member
+// CHECK:DW_AT_name{{.*}}"C"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (46)
+
+// CHECK:0x[[U_S_MEMBER:[0-9a-f]*]]:{{.*}}DW_TAG_member
+// CHECK:DW_AT_name{{.*}}"S"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (47)
+
+// CHECK:0x[[U_S_STRUCT:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
+// CHECK:DW_AT_name{{.*}}"S"
+// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (47)
+
+// The second compile unit contains subprogram and its variables:
+// CHECK:DW_TAG_compile_unit
+// CHECK:DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF2:[0-9a-f]*]])
+
+// CHECK:DW_TAG_subprogram
+// CHECK:DW_AT_low_pc
+// CHECK:DW_AT_high_pc
+// CHECK:DW_AT_frame_base
+// CHECK:DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK:DW_AT_name{{.*}}"foo"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (74)
+// CHECK:DW_AT_external
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"s"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (75)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[TYPEDEF_ALIASFORS]] "AliasForS
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"n"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (76)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[S_STRUCTURE_NESTED]] "S::Neste
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"nc"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (77)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[C_CLASS]] "N::C"
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"ac"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (78)
+// CHECK:DW_AT_type [DW_FORM_ref4]{{.*}} {0x[[ANON_CLASS1:[0-9a-f]*]]} "(anonymous namespace)::AnonC")
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"u"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (79)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[U_UNION]] "U"
+
+// CHECK:0x[[ANON_NAMESPACE1:[0-9a-f]*]]:{{.*}}DW_TAG_namespace
+// CHECK-NEXT:DW_AT_decl_file{{.*}}"{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp"
+
+// CHECK:0x[[ANON_CLASS1]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"AnonC"
+// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01)
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (65)
+
+// The third compile unit contains subprogram and its variables:
+// CHECK:DW_TAG_compile_unit
+// CHECK:DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NEXT:DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF3:[0-9a-f]*]])
+
+// CHECK:DW_TAG_subprogram
+// CHECK:DW_AT_low_pc
+// CHECK:DW_AT_high_pc
+// CHECK:DW_AT_frame_base
+// CHECK:DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK:DW_AT_name{{.*}}"foo"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (74)
+// CHECK:DW_AT_external
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"s"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (75)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[TYPEDEF_ALIASFORS]] "AliasForS
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"n"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (76)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[S_STRUCTURE_NESTED]] "S::Neste
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"nc"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (77)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[C_CLASS]] "N::C"
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"ac"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (78)
+// CHECK:DW_AT_type [DW_FORM_ref4]{{.*}} {0x[[ANON_CLASS2:[0-9a-f]*]]} "(anonymous namespace)::AnonC")
+
+// CHECK:DW_TAG_variable
+// CHECK:DW_AT_name{{.*}}"u"
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (79)
+// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[U_UNION]] "U"
+
+// CHECK:0x[[ANON_NAMESPACE2:[0-9a-f]*]]:{{.*}}DW_TAG_namespace
+// CHECK-NEXT:DW_AT_decl_file{{.*}}"{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp"
+
+// CHECK:0x[[ANON_CLASS2]]:{{.*}}DW_TAG_class_type
+// CHECK:DW_AT_name{{.*}}"AnonC"
+// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01)
+// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp
+// CHECK:DW_AT_decl_line [DW_FORM_data1] (65)
+
+// CHECK:.debug_aranges contents
+
+// CHECK:debug_line[0x[[LINE_TABLE_OFF1]]]
+
+// CHECK:debug_line[0x[[LINE_TABLE_OFF2]]]
+
+// CHECK:debug_line[0x[[LINE_TABLE_OFF3]]]
+
+// CHECK:.debug_str contents:
+// CHECK:0x00000000: ""
+// CHECK:0x00000001: "clang version 3.8.0 (trunk 244290) (llvm/trunk 244270)"
+// CHECK:0x00000038: "odr-uniquing.cpp"
+// CHECK:0x00000049: "/tmp"
+// CHECK:0x0000004e: "_Z3foov"
+// CHECK:0x00000056: "foo"
+// CHECK:0x0000005a: "s"
+// CHECK:0x0000005c: "n"
+// CHECK:0x0000005e: "nc"
+// CHECK:0x00000061: "ac"
+// CHECK:0x00000064: "u"
+// CHECK:0x00000066: "AnonC"
+// CHECK:0x0000006c: "(anonymous namespace)"
+// CHECK:0x00000082: "llvm DWARFLinkerParallel library version "
+// CHECK:0x000000ac: "__artificial_type_unit"
+// CHECK:0x000000c3: ""
+// CHECK:0x000000c4: "AliasForS"
+// CHECK:0x000000ce: "C"
+// CHECK:0x000000d0: "N"
+// CHECK:0x000000d2: "Nested"
+// CHECK:0x000000d9: "S"
+// CHECK:0x000000db: "U"
+
+
+// CHECK:.apple_names
+// CHECK: Bucket count: 2
+// CHECK: String: {{.*}} "foo"
+// CHECK: String: {{.*}} "_Z3foov"
+
+// CHECK:.apple_types
+// CHECK: Bucket count: 6
+// CHECK: String: {{.*}} "AnonC"
+// CHECK: String: {{.*}} "Nested"
+// CHECK: String: {{.*}} "S"
+// CHECK: String: {{.*}} "C"
+// CHECK: String: {{.*}} "U"
+// CHECK: String: {{.*}} "AliasForS"
+
+// CHECK:.apple_namespaces
+// CHECK: Bucket count: 2
+// CHECK: String: {{.*}} "(anonymous namespace)"
+// CHECK: String: {{.*}} "N"
+
+// CHECK:.apple_objc
+// CHECK:Bucket count: 1
+
+// CHECK-NOODR: .debug_info contents
+
+// CHECK-NOODR: DW_TAG_compile_unit
+// CHECK-NOODR: DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NOODR-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF1:[0-9a-f]*]])
+// CHECK-NOODR: DW_AT_low_pc{{.*}}(0x{{0*}}[[LOW_PC1:[0-9a-f]*]])
+// CHECK-NOODR-NEXT: DW_AT_high_pc{{.*}}(0x{{0*}}[[HIGH_PC1:[0-9a-f]*]])
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"Nested"
+
+// CHECK-NOODR: DW_TAG_namespace
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"N"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_union_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_subprogram
+// CHECK-NOODR-NEXT: DW_AT_low_pc
+// CHECK-NOODR-NEXT: DW_AT_high_pc
+// CHECK-NOODR: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"foo"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"s"
+// CHECK-NOODR: DW_AT_type{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"n"
+// CHECK-NOODR: DW_AT_type{{.*}}"S::Nested"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"nc"
+// CHECK-NOODR: DW_AT_type{{.*}}"N::C"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"ac"
+// CHECK-NOODR: DW_AT_type{{.*}}"(anonymous namespace)::AnonC"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"u"
+// CHECK-NOODR: DW_AT_type{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_typedef
+// CHECK-NOODR: DW_AT_type{{.*}}"S"
+// CHECK-NOODR: DW_AT_name{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_namespace
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"AnonC"
+
+// CHECK-NOODR: DW_TAG_compile_unit
+// CHECK-NOODR: DW_AT_name{{.*}}"odr-uniquing.cpp"
+// CHECK-NOODR-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF2:[0-9a-f]*]])
+// CHECK-NOODR: DW_AT_low_pc
+// CHECK-NOODR: DW_AT_high_pc
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR: DW_AT_name{{.*}}"Nested"
+
+// CHECK-NOODR: DW_TAG_namespace
+// CHECK-NOODR: DW_AT_name{{.*}}"N"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_union_type
+// CHECK-NOODR: DW_AT_name{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR: DW_AT_name{{.*}}"C"
+// CHECK-NOODR: DW_AT_type{{.*}}"U::C"
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"C"
+
+// CHECK-NOODR: DW_TAG_member
+// CHECK-NOODR: DW_AT_name{{.*}}"S"
+// CHECK-NOODR: DW_AT_type{{.*}}"U::S"
+
+// CHECK-NOODR: DW_TAG_structure_type
+// CHECK-NOODR: DW_AT_name{{.*}}"S"
+
+// CHECK-NOODR: DW_TAG_subprogram
+// CHECK-NOODR: DW_AT_low_pc
+// CHECK-NOODR: DW_AT_high_pc
+// CHECK-NOODR: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov"
+// CHECK-NOODR: DW_AT_name{{.*}}"foo"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"s"
+// CHECK-NOODR: DW_AT_type{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"n"
+// CHECK-NOODR: DW_AT_type{{.*}}"S::Nested"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"nc"
+// CHECK-NOODR: DW_AT_type{{.*}} "N::C"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"ac"
+// CHECK-NOODR: DW_AT_type{{.*}}"(anonymous namespace)::AnonC"
+
+// CHECK-NOODR: DW_TAG_variable
+// CHECK-NOODR: DW_AT_name{{.*}}"u"
+// CHECK-NOODR: DW_AT_type{{.*}}"U"
+
+// CHECK-NOODR: DW_TAG_typedef
+// CHECK-NOODR: DW_AT_type{{.*}}"S"
+// CHECK-NOODR: DW_AT_name{{.*}}"AliasForS"
+
+// CHECK-NOODR: DW_TAG_namespace
+
+// CHECK-NOODR: DW_TAG_class_type
+// CHECK-NOODR: DW_AT_name{{.*}}"AnonC"
+
+// CHECK-NOODR:.debug_aranges contents
+
+// CHECK-NOODR:debug_line[0x[[LINE_TABLE_OFF1]]]
+
+// CHECK-NOODR:debug_line[0x[[LINE_TABLE_OFF2]]]
+
+// CHECK-NOODR:.debug_str contents:
+// CHECK-NOODR:0x00000000: ""
+// CHECK-NOODR:0x00000001: "clang version 3.8.0 (trunk 244290) (llvm/trunk 244270)"
+// CHECK-NOODR:0x00000038: "odr-uniquing.cpp"
+// CHECK-NOODR:0x00000049: "/tmp"
+// CHECK-NOODR:0x0000004e: "S"
+// CHECK-NOODR:0x00000050: "Nested"
+// CHECK-NOODR:0x00000057: "N"
+// CHECK-NOODR:0x00000059: "C"
+// CHECK-NOODR:0x0000005b: "U"
+// CHECK-NOODR:0x0000005d: "_Z3foov"
+// CHECK-NOODR:0x00000065: "foo"
+// CHECK-NOODR:0x00000069: "s"
+// CHECK-NOODR:0x0000006b: "n"
+// CHECK-NOODR:0x0000006d: "nc"
+// CHECK-NOODR:0x00000070: "ac"
+// CHECK-NOODR:0x00000073: "u"
+// CHECK-NOODR:0x00000075: "AliasForS"
+// CHECK-NOODR:0x0000007f: "AnonC"
+// CHECK-NOODR:0x00000085: "(anonymous namespace)"
+
+// CHECK-NOODR: .apple_names
+// CHECK-NOODR: Bucket count: 2
+// CHECK-NOODR: String: {{.*}} "foo"
+// CHECK-NOODR: String: {{.*}} "_Z3foov"
+
+// CHECK-NOODR: .apple_types
+// CHECK-NOODR: Bucket count: 6
+// CHECK-NOODR: String: {{.*}} "AnonC"
+// CHECK-NOODR: String: {{.*}} "Nested"
+// CHECK-NOODR: String: {{.*}} "S"
+// CHECK-NOODR: String: {{.*}} "C"
+// CHECK-NOODR: String: {{.*}} "U"
+// CHECK-NOODR: String: {{.*}} "AliasForS"
+
+// CHECK-NOODR: .apple_namespaces
+// CHECK-NOODR: Bucket count: 2
+// CHECK-NOODR: String: {{.*}} "(anonymous namespace)"
+// CHECK-NOODR: String: {{.*}} "N"
+
+// CHECK-NOODR: .apple_objc
+// CHECK-NOODR:Bucket count: 1

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o
new file mode 100644
index 000000000000000..a837de81a4f295d
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o
new file mode 100644
index 000000000000000..a0d093389d42409
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o
new file mode 100644
index 000000000000000..9b3a9acd4a6cd0a
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/Inputs/String/main.o b/llvm/test/tools/dsymutil/X86/Inputs/String/main.o
new file mode 100644
index 000000000000000..29716a88f5c0754
Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/main.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp
index 8a72aee6fb38fb8..6ea5ef22a65acbf 100644
--- a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp
+++ b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp
@@ -1,10 +1,5 @@
 // RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
 
-// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \
-// RUN: %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \
-// RUN: FileCheck %s --implicit-check-not \
-// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
-
 // The test was compiled with:
 // clang++ -O2 -g -c dead-strip.cpp -o 1.o
 

diff  --git a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map
index 95b1f726d4ff9e7..ec5d8e4f1503155 100644
--- a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map
+++ b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map
@@ -16,8 +16,8 @@ objects:
       - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x20000, size: 0x10 }
   - filename: 3.o
     symbols:
-      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x10 }
-      - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30010, size: 0x10 }
+      - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x20 }
+      - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30020, size: 0x10 }
   - filename: 4.o
     symbols:
       - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x40000, size: 0x10 }

diff  --git a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
index b6d2f4391c70e3c..651a874ff3ec4c9 100644
--- a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
+++ b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test
@@ -57,8 +57,8 @@
 #DWARF-CHECK: 0x00000000: range list header: length = 0x00000011, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
 #DWARF-CHECK: ranges:
 #DWARF-CHECK: 0x0000000c: [DW_RLE_base_addressx]:  0x0000000000000003
-#DWARF-CHECK: 0x0000000e: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x000000000000001d => [0x0000000100000f79, 0x0000000100000f96)
-#DWARF-CHECK: 0x00000011: [DW_RLE_offset_pair  ]:  0x0000000000000034, 0x000000000000003b => [0x0000000100000fad, 0x0000000100000fb4)
+#DWARF-CHECK: 0x0000000e: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x000000000000001d
+#DWARF-CHECK: 0x00000011: [DW_RLE_offset_pair  ]:  0x0000000000000034, 0x000000000000003b
 #DWARF-CHECK: 0x00000014: [DW_RLE_end_of_list  ]
 #
 #UPD-DWARF-CHECK: DW_TAG_compile_unit

diff  --git a/llvm/test/tools/dsymutil/X86/empty-CU.test b/llvm/test/tools/dsymutil/X86/empty-CU.test
index db9f70874971b3a..7b06607a74cbc0b 100644
--- a/llvm/test/tools/dsymutil/X86/empty-CU.test
+++ b/llvm/test/tools/dsymutil/X86/empty-CU.test
@@ -1,8 +1,6 @@
 RUN: llvm-mc %p/../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o
 RUN: dsymutil --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
 
-RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s
-
 CHECK: .debug_info contents:
 CHECK: 0x00000000: Compile Unit: length = 0x00000008, format = DWARF32, version = 0x0003, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x0000000c)
 

diff  --git a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
index e933be8fd9bdb09..928b14b62bc672e 100644
--- a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
+++ b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp
@@ -1,9 +1,15 @@
-// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
-
-// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \
-// RUN: %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | \
-// RUN: FileCheck %s --implicit-check-not \
-// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}"
+// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path \
+// RUN:   %p/../Inputs/inlined-static-variable -o - -keep-function-for-static \
+// RUN:   | llvm-dwarfdump - | FileCheck %s --implicit-check-not \
+// RUN:   "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN:   --check-prefixes=CHECK
+//
+// RUN: dsymutil --linker llvm --no-odr -f -y %p/dummy-debug-map.map \
+// RUN:   -oso-prepend-path %p/../Inputs/inlined-static-variable -o - \
+// RUN:   -keep-function-for-static | llvm-dwarfdump - | FileCheck %s \
+// RUN:   --implicit-check-not \
+// RUN:   "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \
+// RUN:   --check-prefixes=CHECK
 
 // clang -g -c inlined-static-variable.cpp -o 4.o
 

diff  --git a/llvm/test/tools/dsymutil/X86/keep-func.test b/llvm/test/tools/dsymutil/X86/keep-func.test
index f307f5ad89900dc..021c7212bd8319b 100644
--- a/llvm/test/tools/dsymutil/X86/keep-func.test
+++ b/llvm/test/tools/dsymutil/X86/keep-func.test
@@ -25,11 +25,6 @@ RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/
 RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
 RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
 
-RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM
-RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static
-RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT
-RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP
-
 KEEP:     DW_AT_name	("MyDummyVar")
 KEEP:     DW_AT_name	("FOO_VAR_TYPE")
 KEEP:     DW_AT_name	("x1")

diff  --git a/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test b/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test
new file mode 100644
index 000000000000000..627df30344d8b7c
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test
@@ -0,0 +1,65 @@
+Test binaries created with the following commands:
+
+$ cat container.cpp
+#include "container.h"
+#include <stdlib.h>
+
+struct Container_ivars {
+  // real definition here
+};
+
+ContainerPtr allocateContainer() {
+  Container *c = (Container *)malloc(sizeof(Container));
+  c->ivars = (Container_ivars *)malloc(sizeof(Container_ivars));
+  return c;
+}
+
+extern void doSomething(ContainerPtr);
+
+int main() {
+  ContainerPtr c = allocateContainer();
+  doSomething(c);
+  return 0;
+}
+
+$ cat container.h
+struct Container_ivars;
+
+struct Container {
+  union {
+    struct Container_ivars *ivars;
+  };
+};
+
+typedef Container *ContainerPtr;
+
+$ cat use.cpp
+#include "container.h"
+
+void doSomething(ContainerPtr c) {}
+
+
+$ clang++ -O0 -g container.cpp -c -o container.o
+$ clang++ -O0 -g use.cpp -c -o use.o
+$ clang++ use.o container.o -o a.out
+
+Note that the link order in the last command matters for this test.
+
+RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM
+RUN: llvm-dwarfdump --debug-info %t.dSYM | FileCheck %s
+
+CHECK:       DW_TAG_compile_unit
+CHECK-NEXT:    DW_AT_producer    ("llvm DWARFLinkerParallel library
+CHECK-NEXT:    DW_AT_language    (DW_LANG_C_plus_plus_14)
+CHECK-NEXT:    DW_AT_name        ("__artificial_type_unit")
+CHECK-NEXT:    DW_AT_stmt_list   (0x00000000)
+
+CHECK:       DW_TAG_structure_type
+CHECK:         DW_AT_calling_convention        (DW_CC_pass_by_value)
+CHECK:         DW_AT_name      ("Container_ivars")
+CHECK-NEXT:    DW_AT_byte_size (0x01)
+CHECK-NEXT:    DW_AT_decl_line (4)
+CHECK-NEXT:    DW_AT_decl_file ("{{.*}}container.cpp")
+
+CHECK:       DW_TAG_compile_unit
+CHECK-NOT:   DW_AT_declaration

diff  --git a/llvm/test/tools/dsymutil/X86/location-expression.test b/llvm/test/tools/dsymutil/X86/location-expression.test
index 5414dff3745b285..3bffc9aeacca77a 100644
--- a/llvm/test/tools/dsymutil/X86/location-expression.test
+++ b/llvm/test/tools/dsymutil/X86/location-expression.test
@@ -18,15 +18,15 @@
 # CHECK: Compile Unit:
 # CHECK: DW_TAG_compile_unit
 # CHECK: DW_AT_name{{.*}}"CU1"
-# CHECK: 0x0000001b:   DW_TAG_variable
+# CHECK: DW_TAG_variable
 # CHECK: DW_AT_name {{.*}}"var1"
 # CHECK: DW_AT_type {{.*}}"class1"
 # CHECK:   DW_AT_location [DW_FORM_block1]  (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
-# CHECK: 0x000000ab:   DW_TAG_variable
+# CHECK: DW_TAG_variable
 # CHECK: DW_AT_name {{.*}}"var2"
 # CHECK: DW_AT_type {{.*}}"class1"
 # CHECK:   DW_AT_location [DW_FORM_block]  (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address)
-# CHECK: 0x00000146:   DW_TAG_variable
+# CHECK: DW_TAG_variable
 # CHECK: DW_AT_name {{.*}}"var3"
 # CHECK: DW_AT_type {{.*}}"class1"
 #

diff  --git a/llvm/test/tools/dsymutil/X86/modules-empty.m b/llvm/test/tools/dsymutil/X86/modules-empty.m
index fc415acc59f6d60..eb70f51230de91b 100644
--- a/llvm/test/tools/dsymutil/X86/modules-empty.m
+++ b/llvm/test/tools/dsymutil/X86/modules-empty.m
@@ -29,6 +29,6 @@ int main() {
 }
 
 // The empty CU from the pcm should not get copied into the dSYM.
-// CHECK: DW_TAG_compile_unit
-// CHECK-NOT: DW_TAG_compile_unit
-
+// Check that module name occured only once.
+// CHECK: "Empty"
+// CHECK-NOT: "Empty"

diff  --git a/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp b/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
index 0e3b974ba005937..d87bb5b73c240e2 100644
--- a/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
+++ b/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp
@@ -14,6 +14,8 @@
 // RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=ODR,CHECK %s
 // RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=NOODR,CHECK %s
 
+// RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=NOODR,CHECK %s
+
 // The first compile unit contains all the types:
 // CHECK: TAG_compile_unit
 // CHECK-NOT: DW_TAG

diff  --git a/llvm/test/tools/dsymutil/X86/op-convert.test b/llvm/test/tools/dsymutil/X86/op-convert.test
index 15725a0435d4884..9960d1996496d65 100644
--- a/llvm/test/tools/dsymutil/X86/op-convert.test
+++ b/llvm/test/tools/dsymutil/X86/op-convert.test
@@ -12,21 +12,23 @@ objects:
       - { sym: _foo, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
 ...
 
+CHECK: DW_TAG_compile_unit
+CHECK: DW_AT_name        ("dbg.c")
 
-CHECK:      DW_TAG_base_type
+CHECK:0x[[ADDR1:[0-9a-f]+]]:      DW_TAG_base_type
 CHECK-NEXT:     DW_AT_name	("DW_ATE_signed_8")
 CHECK-NEXT:     DW_AT_encoding	(DW_ATE_signed)
 CHECK-NEXT:     DW_AT_byte_size	(0x01)
 
-CHECK:   DW_TAG_base_type
+CHECK:0x[[ADDR2:[0-9a-f]+]]:   DW_TAG_base_type
 CHECK-NEXT:     DW_AT_name	("DW_ATE_signed_32")
 CHECK-NEXT:     DW_AT_encoding	(DW_ATE_signed)
 CHECK-NEXT:     DW_AT_byte_size	(0x04)
 
 CHECK:     DW_TAG_variable
 CHECK-NEXT:     DW_AT_location	(
-CHECK-NEXT:     [0x0000000000001000,  0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value
-CHECK-NEXT:     [0x0000000000001002,  0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value)
+CHECK-NEXT:     [0x0000000000001000,  0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x[[ADDR1]]) "DW_ATE_signed_8", DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value
+CHECK-NEXT:     [0x0000000000001002,  0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x[[ADDR1]]) "DW_ATE_signed_8", DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value)
 CHECK-NEXT:     DW_AT_name	("y")
 
 CHECK:     DW_TAG_variable
@@ -34,6 +36,6 @@ CHECK-NEXT:     DW_AT_location	(DW_OP_constu 0x33, DW_OP_convert 0x0, DW_OP_stac
 CHECK-NEXT:     DW_AT_name	("d")
 
 CHECK:     DW_TAG_variable
-CHECK-NEXT:     DW_AT_location	(DW_OP_constu 0x2a, DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value)
+CHECK-NEXT:     DW_AT_location	(DW_OP_constu 0x2a, DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value)
 CHECK-NEXT:     DW_AT_name	("c")
 

diff  --git a/llvm/test/tools/dsymutil/X86/union-fwd-decl.test b/llvm/test/tools/dsymutil/X86/union-fwd-decl.test
index c5c8c9e93e0a06a..c73db0e3f5532e5 100644
--- a/llvm/test/tools/dsymutil/X86/union-fwd-decl.test
+++ b/llvm/test/tools/dsymutil/X86/union-fwd-decl.test
@@ -48,9 +48,6 @@ Note that the link order in the last command matters for this test.
 RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM
 RUN: llvm-dwarfdump %t.dSYM | FileCheck %s
 
-RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM
-RUN: llvm-dwarfdump %t.dSYM | FileCheck %s
-
 CHECK: DW_TAG_compile_unit
 
 CHECK:          DW_AT_name      ("Container_ivars")

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
index 90c40fd1e4ab62e..b63668c39c90187 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test
@@ -39,7 +39,7 @@
 #DWARF-CHECK:   DW_AT_name [DW_FORM_strx]  {{.*}}     "CU1"
 #DWARF-CHECK:   DW_AT_low_pc [DW_FORM_addrx]      (indexed (00000000) address = 0x0000000000001130)
 #DWARF-CHECK:   DW_AT_high_pc [DW_FORM_data8]   (0x0000000000000060)
-#DWARF-CHECK:   DW_AT_str_offsets_base [DW_FORM_sec_offset]       (0x00000008)
+#DWARF-CHECK:   DW_AT_str_offsets_base [DW_FORM_sec_offset]
 #DWARF-CHECK:   DW_TAG_subprogram
 #DWARF-CHECK:     DW_AT_name  [DW_FORM_strx] {{.*}}   "foo1"
 #DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]    (indexed (00000000) address = 0x0000000000001130)

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
index 78b53897346c48c..a1bb3ec7d846d8c 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test
@@ -35,7 +35,7 @@
 #DWARF-CHECK:   DW_AT_low_pc [DW_FORM_addrx]      (indexed (00000000) address = 0x0000000000001130)
 #DWARF-CHECK:   DW_AT_ranges [DW_FORM_sec_offset] (0x[[CURANGE_OFF:[0-9a-f]*]]
 #DWARF-CHECK:   [0x0000000000001130, 0x0000000000001170))
-#DWARF-CHECK:   DW_AT_str_offsets_base [DW_FORM_sec_offset]       (0x00000008)
+#DWARF-CHECK:   DW_AT_str_offsets_base [DW_FORM_sec_offset]
 #DWARF-CHECK:   DW_TAG_subprogram
 #DWARF-CHECK:     DW_AT_name  [DW_FORM_strx] {{.*}}   "foo1"
 #DWARF-CHECK:     DW_AT_low_pc [DW_FORM_addrx]    (indexed (00000000) address = 0x0000000000001130)
@@ -65,7 +65,7 @@
 #DWARF-CHECK:       DW_AT_ranges [DW_FORM_sec_offset]     (0x[[F4RANGE_OFF:[0-9a-f]*]]
 #DWARF-CHECK:          [0x0000000000001160, 0x0000000000001170))
 #DWARF-CHECK: .debug_aranges contents:
-#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00
+#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x000000{{00|21}}, addr_size = 0x08, seg_size = 0x00
 #DWARF-CHECK: [0x0000000000001130, 0x0000000000001170)
 #DWARF-CHECK: .debug_addr contents:
 #DWARF-CHECK: 0x00000000: Address table header: length = 0x00000024, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00
@@ -79,19 +79,19 @@
 #DWARF-CHECK: 0x00000000: range list header: length = 0x00000026, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000
 #DWARF-CHECK: ranges:
 #DWARF-CHECK: 0x[[F1RANGE_OFF]]: [DW_RLE_base_addressx]:  0x0000000000000000
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010
 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list  ]
 #DWARF-CHECK: 0x[[F2RANGE_OFF]]: [DW_RLE_base_addressx]:  0x0000000000000001
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010
 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list  ]
 #DWARF-CHECK: 0x[[F3RANGE_OFF]]: [DW_RLE_base_addressx]:  0x0000000000000002
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010
 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list  ]
 #DWARF-CHECK: 0x[[F4RANGE_OFF]]: [DW_RLE_base_addressx]:  0x0000000000000003
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000010
 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list  ]
 #DWARF-CHECK 0x[[CURANGE_OFF]]: [DW_RLE_base_addressx]:  0x0000000000000000
-#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170)
+#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair  ]:  0x0000000000000000, 0x0000000000000040
 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list  ]
 
 #UPD-DWARF-CHECK: DW_TAG_compile_unit
@@ -145,15 +145,15 @@
 #UPD-DWARF-CHECK: 0x00000032 => 0x0000003e
 #UPD-DWARF-CHECK: ]
 #UPD-DWARF-CHECK: ranges:
-#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]:  0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140)
+#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]:  0x0000000000000000, 0x0000000000000010
 #UPD-DWARF-CHECK: 0x00000023: [DW_RLE_end_of_list  ]
-#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]:  0x0000000000000001, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150)
+#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]:  0x0000000000000001, 0x0000000000000010
 #UPD-DWARF-CHECK: 0x00000027: [DW_RLE_end_of_list  ]
-#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]:  0x0000000000001150, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160)
+#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]:  0x0000000000001150, 0x0000000000000010
 #UPD-DWARF-CHECK: 0x00000032: [DW_RLE_end_of_list  ]
-#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]:  0x0000000000001160, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170)
+#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]:  0x0000000000001160, 0x0000000000000010
 #UPD-DWARF-CHECK: 0x0000003d: [DW_RLE_end_of_list  ]
-#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]:  0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170)
+#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]:  0x0000000000000000, 0x0000000000000040
 #UPD-DWARF-CHECK: 0x00000041: [DW_RLE_end_of_list  ]
 
 ## Following yaml description has Content of the .debug_rnglists exactly like above data ^^^^^^

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
index 90cb99858c9efc9..2c4caa158258d28 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
@@ -3,23 +3,23 @@
 
 # RUN: yaml2obj %s -o %t.o
 
-# RUN: llvm-dwarfutil %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
-# RUN: llvm-dwarfutil --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
-# RUN: llvm-dwarfutil --linker llvm %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --linker llvm %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
-# RUN: llvm-dwarfutil --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
-# RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
-# RUN: llvm-dwarfutil --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
+# RUN: llvm-dwarfutil --no-odr --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
 
-# RUN: llvm-dwarfutil --linker llvm --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
+# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC
 
-# RUN: llvm-dwarfutil %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
-# RUN: llvm-dwarfutil --linker llvm %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
+# RUN: llvm-dwarfutil --no-odr --linker llvm %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
 
 # CHECK: DW_TAG_compile_unit
 # CHECK: DW_AT_name{{.*}}"CU1"

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
index 232f6a5553e5717..46ebcf24fe64dc0 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test
@@ -2,10 +2,10 @@
 ## are combined during --garbage-collection optimisation.
 
 # RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o %t1
 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s
 
-# RUN: llvm-dwarfutil --linker llvm --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection %t.o %t1
 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s
 
 # CHECK: DW_TAG_compile_unit

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
index cb3b435ea9aa4cc..7f0533a882dd8bc 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test
@@ -3,11 +3,11 @@
 
 ## RUN: yaml2obj %s -o %t.o
 
-# RUN: llvm-dwarfutil --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
-# RUN: llvm-dwarfutil --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
 
-# RUN: llvm-dwarfutil --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
-# RUN: llvm-dwarfutil --linker llvm --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
 
 # CHECK: DW_TAG_compile_unit
 # CHECK: DW_AT_name{{.*}}"CU1"

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
index 1f5ddd78adaa24c..1a3f29d127cefc6 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test
@@ -2,9 +2,9 @@
 ## does not affect files which do not have dead debug info.
 
 # RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
 
-# RUN: llvm-dwarfutil --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
+# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s
 
 # CHECK: DW_TAG_compile_unit
 # CHECK: DW_AT_name{{.*}}"CU1"

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
index 2ee1d73b6f92f04..1a8010e364d25a6 100644
--- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test
@@ -3,10 +3,10 @@
 ## optimisation.
 
 # RUN: yaml2obj %s -o %t.o
-# RUN: llvm-dwarfutil --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o %t1
 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s
 
-# RUN: llvm-dwarfutil --linker llvm --garbage-collection %t.o %t1
+# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection %t.o %t1
 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s
 
 # CHECK: DW_TAG_compile_unit

diff  --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
index a1f18e6f169db9e..d00ef1a8c228b08 100644
--- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -1059,7 +1059,6 @@ DwarfLinkerForBinary::AddressManager<AddressesMapBase>::hasValidRelocationAt(
     uint64_t EndOffset) {
   std::vector<ValidReloc> Relocs =
       getRelocations(AllRelocs, StartOffset, EndOffset);
-
   if (Relocs.size() == 0)
     return std::nullopt;
 


        


More information about the llvm-commits mailing list