[DWARFLinkerParallel][Reland] Add interface files, create a skeleton implementation.

This patch creates skeleton implementation for the DWARFLinkerParallel.
It also integrates DWARFLinkerParallel into dsymutil and llvm-dwarfutil,
so that empty DWARFLinker::link() can be called. To do this new command
line option is added "--linker apple/llvm". Additionally it changes
existing DWARFLinker interfaces/implementations to be compatible:
use Error for error reporting for the DWARFStreamer, make DWARFFile to
owner of referenced resources, other small refactorings.

Differential Revision: https://reviews.llvm.org/D147952

GitOrigin-RevId: 36f351098cd50809658493d9b2e22a795874bab0
diff --git a/include/llvm/DWARFLinker/DWARFLinker.h b/include/llvm/DWARFLinker/DWARFLinker.h
index e5475bb..76ab36c 100644
--- a/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/include/llvm/DWARFLinker/DWARFLinker.h
@@ -14,6 +14,7 @@
 #include "llvm/CodeGen/AccelTable.h"
 #include "llvm/CodeGen/NonRelocatableStringpool.h"
 #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
@@ -21,7 +22,6 @@
 #include <map>
 
 namespace llvm {
-class DWARFContext;
 class DWARFExpression;
 class DWARFUnit;
 class DataExtractor;
@@ -30,13 +30,6 @@
 
 enum class DwarfLinkerClient { Dsymutil, LLD, General };
 
-/// The kind of accelerator tables we should emit.
-enum class DwarfLinkerAccelTableKind : uint8_t {
-  Apple,     ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc.
-  Pub,       ///< .debug_pubnames, .debug_pubtypes
-  DebugNames ///< .debug_names.
-};
-
 /// AddressesMap represents information about valid addresses used
 /// by debug information. Valid addresses are those which points to
 /// live code sections. i.e. relocations for these addresses point
@@ -221,39 +214,48 @@
 
   /// Returns size of generated .debug_loclists section.
   virtual uint64_t getLocListsSectionSize() const = 0;
+
+  /// Dump the file to the disk.
+  virtual void finish() = 0;
+
+  /// Emit the swift_ast section stored in \p Buffer.
+  virtual void emitSwiftAST(StringRef Buffer) = 0;
+
+  /// Emit the swift reflection section stored in \p Buffer.
+  virtual void emitSwiftReflectionSection(
+      llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
+      StringRef Buffer, uint32_t Alignment, uint32_t Size) = 0;
+
+  /// Returns underlying AsmPrinter.
+  virtual AsmPrinter &getAsmPrinter() const = 0;
 };
 
+class DwarfStreamer;
 using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>;
 
 /// This class represents DWARF information for source file
 /// and its address map.
 class DWARFFile {
 public:
-  DWARFFile(StringRef Name, DWARFContext *Dwarf, AddressesMap *Addresses,
+  DWARFFile(StringRef Name, std::unique_ptr<DWARFContext> Dwarf,
+            std::unique_ptr<AddressesMap> Addresses,
             const std::vector<std::string> &Warnings)
-      : FileName(Name), Dwarf(Dwarf), Addresses(Addresses), Warnings(Warnings) {
-  }
+      : FileName(Name), Dwarf(std::move(Dwarf)),
+        Addresses(std::move(Addresses)), Warnings(Warnings) {}
 
   /// The object file name.
   StringRef FileName;
 
   /// The source DWARF information.
-  DWARFContext *Dwarf = nullptr;
+  std::unique_ptr<DWARFContext> Dwarf;
 
   /// Helpful address information(list of valid address ranges, relocations).
-  AddressesMap *Addresses = nullptr;
+  std::unique_ptr<AddressesMap> Addresses;
 
   /// Warnings for this object file.
   const std::vector<std::string> &Warnings;
 };
 
-typedef std::function<void(const Twine &Warning, StringRef Context,
-                           const DWARFDie *DIE)>
-    messageHandler;
-typedef std::function<void(const DWARFFile &File)> inputVerificationHandler;
-typedef std::function<ErrorOr<DWARFFile &>(StringRef ContainerName,
-                                           StringRef Path)>
-    objFileLoader;
 typedef std::map<std::string, std::string> swiftInterfacesMap;
 typedef std::map<std::string, std::string> objectPrefixMap;
 
@@ -275,9 +277,43 @@
 /// processing a object file.
 class DWARFLinker {
 public:
-  DWARFLinker(DwarfEmitter *Emitter,
-              DwarfLinkerClient ClientID = DwarfLinkerClient::General)
-      : TheDwarfEmitter(Emitter), DwarfLinkerClientID(ClientID) {}
+  typedef std::function<void(const Twine &Warning, StringRef Context,
+                             const DWARFDie *DIE)>
+      messageHandler;
+  DWARFLinker(messageHandler ErrorHandler, messageHandler WarningHandler,
+              std::function<StringRef(StringRef)> StringsTranslator)
+      : DwarfLinkerClientID(DwarfLinkerClient::Dsymutil),
+        StringsTranslator(StringsTranslator), ErrorHandler(ErrorHandler),
+        WarningHandler(WarningHandler) {}
+
+  static std::unique_ptr<DWARFLinker> createLinker(
+      messageHandler ErrorHandler, messageHandler WarningHandler,
+      std::function<StringRef(StringRef)> StringsTranslator = nullptr) {
+    return std::make_unique<DWARFLinker>(ErrorHandler, WarningHandler,
+                                         StringsTranslator);
+  }
+
+  /// Type of output file.
+  enum class OutputFileType {
+    Object,
+    Assembly,
+  };
+
+  /// The kind of accelerator tables we should emit.
+  enum class AccelTableKind : uint8_t {
+    Apple,     ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc.
+    Pub,       ///< .debug_pubnames, .debug_pubtypes
+    DebugNames ///< .debug_names.
+  };
+  typedef std::function<void(const DWARFFile &File)> inputVerificationHandler;
+  typedef std::function<ErrorOr<DWARFFile &>(StringRef ContainerName,
+                                             StringRef Path)>
+      objFileLoader;
+
+  Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
+                      raw_pwrite_stream &OutFile);
+
+  DwarfEmitter *getEmitter();
 
   /// Add object file to be linked. Pre-load compile unit die. Call
   /// \p OnCUDieLoaded for each compile unit die. If specified \p File
@@ -289,8 +325,7 @@
       DWARFFile &File, objFileLoader Loader = nullptr,
       CompileUnitHandler OnCUDieLoaded = [](const DWARFUnit &) {});
 
-  /// Link debug info for added objFiles. Object
-  /// files are linked all together.
+  /// Link debug info for added objFiles. Object files are linked all together.
   Error link();
 
   /// A number of methods setting various linking options:
@@ -304,14 +339,15 @@
   /// Verify the input DWARF.
   void setVerifyInputDWARF(bool Verify) { Options.VerifyInputDWARF = Verify; }
 
-  /// Do not emit linked dwarf info.
-  void setNoOutput(bool NoOut) { Options.NoOutput = NoOut; }
-
   /// Do not unique types according to ODR.
   void setNoODR(bool NoODR) { Options.NoODR = NoODR; }
 
-  /// update existing DWARF info(for the linked binary).
-  void setUpdate(bool Update) { Options.Update = Update; }
+  /// Update index tables only(do not modify rest of DWARF).
+  void setUpdateIndexTablesOnly(bool Update) { Options.Update = Update; }
+
+  /// Allow generating valid, but non-deterministic output.
+  void setAllowNonDeterministicOutput(bool) { /* Nothing to do. */
+  }
 
   /// Set whether to keep the enclosing function for a static variable.
   void setKeepFunctionForStatic(bool KeepFunctionForStatic) {
@@ -322,7 +358,7 @@
   void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; }
 
   /// Add kind of accelerator tables to be generated.
-  void addAccelTableKind(DwarfLinkerAccelTableKind Kind) {
+  void addAccelTableKind(AccelTableKind Kind) {
     assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(),
                      Kind) == Options.AccelTables.end());
     Options.AccelTables.emplace_back(Kind);
@@ -331,27 +367,11 @@
   /// Set prepend path for clang modules.
   void setPrependPath(const std::string &Ppath) { Options.PrependPath = Ppath; }
 
-  /// Set translator which would be used for strings.
-  void
-  setStringsTranslator(std::function<StringRef(StringRef)> StringsTranslator) {
-    this->StringsTranslator = StringsTranslator;
-  }
-
   /// Set estimated objects files amount, for preliminary data allocation.
   void setEstimatedObjfilesAmount(unsigned ObjFilesNum) {
     ObjectContexts.reserve(ObjFilesNum);
   }
 
-  /// Set warning handler which would be used to report warnings.
-  void setWarningHandler(messageHandler Handler) {
-    Options.WarningHandler = Handler;
-  }
-
-  /// Set error handler which would be used to report errors.
-  void setErrorHandler(messageHandler Handler) {
-    Options.ErrorHandler = Handler;
-  }
-
   /// Set verification handler which would be used to report verification
   /// errors.
   void setInputVerificationHandler(inputVerificationHandler Handler) {
@@ -370,7 +390,7 @@
 
   /// Set target DWARF version.
   Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) {
-    if (TargetDWARFVersion < 1 || TargetDWARFVersion > 5)
+    if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5))
       return createStringError(std::errc::invalid_argument,
                                "unsupported DWARF version: %d",
                                TargetDWARFVersion);
@@ -444,14 +464,14 @@
 
   void reportWarning(const Twine &Warning, const DWARFFile &File,
                      const DWARFDie *DIE = nullptr) const {
-    if (Options.WarningHandler != nullptr)
-      Options.WarningHandler(Warning, File.FileName, DIE);
+    if (WarningHandler != nullptr)
+      WarningHandler(Warning, File.FileName, DIE);
   }
 
   void reportError(const Twine &Warning, const DWARFFile &File,
                    const DWARFDie *DIE = nullptr) const {
-    if (Options.ErrorHandler != nullptr)
-      Options.ErrorHandler(Warning, File.FileName, DIE);
+    if (ErrorHandler != nullptr)
+      ErrorHandler(Warning, File.FileName, DIE);
   }
 
   /// Emit warnings as Dwarf compile units to leave a trail after linking.
@@ -799,7 +819,7 @@
   BumpPtrAllocator DIEAlloc;
   /// @}
 
-  DwarfEmitter *TheDwarfEmitter;
+  std::unique_ptr<DwarfStreamer> TheDwarfEmitter;
   std::vector<LinkContext> ObjectContexts;
 
   /// The CIEs that have been emitted in the output section. The actual CIE
@@ -828,6 +848,12 @@
   /// A unique ID that identifies each compile unit.
   unsigned UniqueUnitID = 0;
 
+  // error handler
+  messageHandler ErrorHandler = nullptr;
+
+  // warning handler
+  messageHandler WarningHandler = nullptr;
+
   /// linking options
   struct DWARFLinkerOptions {
     /// DWARF version for the output.
@@ -842,9 +868,6 @@
     /// Verify the input DWARF.
     bool VerifyInputDWARF = false;
 
-    /// Skip emitting output
-    bool NoOutput = false;
-
     /// Do not unique types according to ODR
     bool NoODR = false;
 
@@ -859,17 +882,11 @@
     unsigned Threads = 1;
 
     /// The accelerator table kinds
-    SmallVector<DwarfLinkerAccelTableKind, 1> AccelTables;
+    SmallVector<AccelTableKind, 1> AccelTables;
 
     /// Prepend path for the clang modules.
     std::string PrependPath;
 
-    // warning handler
-    messageHandler WarningHandler = nullptr;
-
-    // error handler
-    messageHandler ErrorHandler = nullptr;
-
     // input verification handler
     inputVerificationHandler InputVerificationHandler = nullptr;
 
diff --git a/include/llvm/DWARFLinker/DWARFStreamer.h b/include/llvm/DWARFLinker/DWARFStreamer.h
index f7dbdd2..a384225 100644
--- a/include/llvm/DWARFLinker/DWARFStreamer.h
+++ b/include/llvm/DWARFLinker/DWARFStreamer.h
@@ -23,11 +23,6 @@
 namespace llvm {
 template <typename DataT> class AccelTable;
 
-enum class OutputFileType {
-  Object,
-  Assembly,
-};
-
 ///   User of DwarfStreamer should call initialization code
 ///   for AsmPrinter:
 ///
@@ -45,18 +40,19 @@
 /// information binary representation are handled in this class.
 class DwarfStreamer : public DwarfEmitter {
 public:
-  DwarfStreamer(OutputFileType OutFileType, raw_pwrite_stream &OutFile,
+  DwarfStreamer(DWARFLinker::OutputFileType OutFileType,
+                raw_pwrite_stream &OutFile,
                 std::function<StringRef(StringRef Input)> Translator,
-                messageHandler Error, messageHandler Warning)
+                DWARFLinker::messageHandler Warning)
       : OutFile(OutFile), OutFileType(OutFileType), Translator(Translator),
-        ErrorHandler(Error), WarningHandler(Warning) {}
+        WarningHandler(Warning) {}
 
-  bool init(Triple TheTriple, StringRef Swift5ReflectionSegmentName);
+  Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName);
 
   /// Dump the file to the disk.
-  void finish();
+  void finish() override;
 
-  AsmPrinter &getAsmPrinter() const { return *Asm; }
+  AsmPrinter &getAsmPrinter() const override { return *Asm; }
 
   /// Set the current output section to debug_info and change
   /// the MC Dwarf version to \p DwarfVersion.
@@ -89,12 +85,12 @@
   void emitLineStrings(const NonRelocatableStringpool &Pool) override;
 
   /// Emit the swift_ast section stored in \p Buffer.
-  void emitSwiftAST(StringRef Buffer);
+  void emitSwiftAST(StringRef Buffer) override;
 
   /// Emit the swift reflection section stored in \p Buffer.
   void emitSwiftReflectionSection(
       llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
-      StringRef Buffer, uint32_t Alignment, uint32_t Size);
+      StringRef Buffer, uint32_t Alignment, uint32_t Size) override;
 
   /// Emit debug ranges(.debug_ranges, .debug_rnglists) header.
   MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) override;
@@ -194,11 +190,6 @@
                        OffsetsStringPool &StringPool) override;
 
 private:
-  inline void error(const Twine &Error, StringRef Context = "") {
-    if (ErrorHandler)
-      ErrorHandler(Error, Context, nullptr);
-  }
-
   inline void warn(const Twine &Warning, StringRef Context = "") {
     if (WarningHandler)
       WarningHandler(Warning, Context, nullptr);
@@ -274,7 +265,7 @@
 
   /// The output file we stream the linked Dwarf to.
   raw_pwrite_stream &OutFile;
-  OutputFileType OutFileType = OutputFileType::Object;
+  DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object;
   std::function<StringRef(StringRef Input)> Translator;
 
   uint64_t RangesSectionSize = 0;
@@ -300,8 +291,7 @@
                              const CompileUnit &Unit,
                              const std::vector<CompileUnit::AccelInfo> &Names);
 
-  messageHandler ErrorHandler = nullptr;
-  messageHandler WarningHandler = nullptr;
+  DWARFLinker::messageHandler WarningHandler = nullptr;
 };
 
 } // end namespace llvm
diff --git a/include/llvm/DWARFLinkerParallel/DWARFFile.h b/include/llvm/DWARFLinkerParallel/DWARFFile.h
new file mode 100644
index 0000000..c20d59f
--- /dev/null
+++ b/include/llvm/DWARFLinkerParallel/DWARFFile.h
@@ -0,0 +1,73 @@
+//===- DWARFFile.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_DWARFFILE_H
+#define LLVM_DWARFLINKERPARALLEL_DWARFFILE_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DWARFLinkerParallel/AddressesMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Endian.h"
+#include <functional>
+#include <memory>
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// This class represents DWARF information for source file
+/// and it's address map.
+///
+/// May be used asynchroniously for reading.
+class DWARFFile {
+public:
+  using UnloadCallbackTy = std::function<void(StringRef FileName)>;
+
+  DWARFFile(StringRef Name, std::unique_ptr<DWARFContext> Dwarf,
+            std::unique_ptr<AddressesMap> Addresses,
+            const std::vector<std::string> &Warnings,
+            UnloadCallbackTy UnloadFunc = nullptr)
+      : FileName(Name), Dwarf(std::move(Dwarf)),
+        Addresses(std::move(Addresses)), Warnings(Warnings),
+        UnloadFunc(UnloadFunc) {
+    if (this->Dwarf)
+      Endianess = this->Dwarf->isLittleEndian() ? support::endianness::little
+                                                : support::endianness::big;
+  }
+
+  /// Object file name.
+  StringRef FileName;
+
+  /// Source DWARF information.
+  std::unique_ptr<DWARFContext> Dwarf;
+
+  /// Helpful address information(list of valid address ranges, relocations).
+  std::unique_ptr<AddressesMap> Addresses;
+
+  /// Warnings for object file.
+  const std::vector<std::string> &Warnings;
+
+  /// Endiannes of source DWARF information.
+  support::endianness Endianess = support::endianness::little;
+
+  /// Callback to the module keeping object file to unload.
+  UnloadCallbackTy UnloadFunc;
+
+  /// Unloads object file and corresponding AddressesMap and Dwarf Context.
+  void unload() {
+    Addresses.reset();
+    Dwarf.reset();
+
+    if (UnloadFunc)
+      UnloadFunc(FileName);
+  }
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_DWARFLINKERPARALLEL_DWARFFILE_H
diff --git a/include/llvm/DWARFLinkerParallel/DWARFLinker.h b/include/llvm/DWARFLinkerParallel/DWARFLinker.h
index b7f9b94..3c725fc 100644
--- a/include/llvm/DWARFLinkerParallel/DWARFLinker.h
+++ b/include/llvm/DWARFLinkerParallel/DWARFLinker.h
@@ -9,10 +9,219 @@
 #ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
 #define LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
 
-#include "llvm/DWARFLinkerParallel/AddressesMap.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/DWARFLinkerParallel/DWARFFile.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/TargetParser/Triple.h"
+
+/// ------------------------------------------------------------------
+/// The core of the Dwarf linking logic.
+///
+/// The generation of the dwarf information from the object files will be
+/// driven by the selection of 'root DIEs', which are DIEs that
+/// describe variables or functions that resolves to the corresponding
+/// code section(and thus have entries in the Addresses map). All the debug
+/// information that will be generated(the DIEs, but also the line
+/// tables, ranges, ...) is derived from that set of root DIEs.
+///
+/// The root DIEs are identified because they contain relocations that
+/// points to code section(the low_pc for a function, the location for
+/// a variable). These relocations are gathered as a very first step
+/// when we start processing a object file by AddressesMap.
+///
+/// The overall linking process looks like this:
+///
+/// parrallel_for_each(ObjectFile) {
+///   for_each (Compile Unit) {
+///     1. Load Clang modules.
+///   }
+///
+///   parrallel_for_each(Compile Unit) {
+///     1. Load input DWARF for Compile Unit.
+///     2. Report warnings for Clang modules.
+///     3. Analyze live DIEs and type names(if ODR deduplication is requested).
+///     4. Clone DIEs(Generate output DIEs and resulting DWARF tables).
+///        The result is in an OutDebugInfoBytes, which is an ELF file
+///        containing DWARF tables corresponding to the current compile unit.
+///     5. Cleanup Input and Output DIEs.
+///   }
+///
+///   Deallocate loaded Object file.
+/// }
+///
+/// if (ODR deduplication is requested)
+///   Generate an artificial compilation unit ("Type Table": used to partially
+///   generate DIEs at the clone stage).
+///
+/// for_each (ObjectFile) {
+///   for_each (Compile Unit) {
+///     1. Set offsets to Compile Units DWARF tables.
+///     2. Sort offsets/attributes/patches to have a predictable result.
+///     3. Patch size/offsets fields.
+///     4. Generate index tables.
+///     5. Move DWARF tables of compile units into the resulting file.
+///   }
+/// }
+///
+/// Every compile unit is processed separately, visited only once
+/// (except case inter-CU references exist), and used data is freed
+/// after the compile unit is processed. The resulting file is glued together
+/// from the generated debug tables which correspond to separate compile units.
+///
+/// Handling inter-CU references: inter-CU references are hard to process
+/// using only one pass. f.e. if CU1 references CU100 and CU100 references
+/// CU1, we could not finish handling of CU1 until we finished CU100.
+/// Thus we either need to load all CUs into the memory, either load CUs several
+/// times. This implementation loads inter-connected CU into memory at the first
+/// pass and processes them at the second pass.
+///
+/// ODR deduplication: Artificial compilation unit will be constructed to keep
+/// type dies. All types are moved into that compilation unit. Type's references
+/// are patched so that they point to the corresponding types from artificial
+/// compilation unit. All partial type definitions would be merged into single
+/// type definition.
+///
 
 namespace llvm {
-namespace dwarflinker_parallel {} // end namespace dwarflinker_parallel
+namespace dwarflinker_parallel {
+
+/// ExtraDwarfEmitter allows adding extra data to the DWARFLinker output.
+/// The finish() method should be called after all extra data are emitted.
+class ExtraDwarfEmitter {
+public:
+  virtual ~ExtraDwarfEmitter() = default;
+
+  /// Dump the file to the disk.
+  virtual void finish() = 0;
+
+  /// Emit section named SecName with data SecData.
+  virtual void emitSectionContents(StringRef SecData, StringRef SecName) = 0;
+
+  /// Emit temporarily symbol named \p SymName inside section \p SecName.
+  virtual MCSymbol *emitTempSym(StringRef SecName, StringRef SymName) = 0;
+
+  /// Emit the swift_ast section stored in \p Buffer.
+  virtual void emitSwiftAST(StringRef Buffer) = 0;
+
+  /// Emit the swift reflection section stored in \p Buffer.
+  virtual void emitSwiftReflectionSection(
+      llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
+      StringRef Buffer, uint32_t Alignment, uint32_t Size) = 0;
+
+  /// Returns underlying AsmPrinter.
+  virtual AsmPrinter &getAsmPrinter() const = 0;
+};
+
+class DWARFLinker {
+public:
+  /// Type of output file.
+  enum class OutputFileType {
+    Object,
+    Assembly,
+  };
+
+  /// The kind of accelerator tables we should emit.
+  enum class AccelTableKind : uint8_t {
+    Apple,     ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc.
+    Pub,       ///< .debug_pubnames, .debug_pubtypes
+    DebugNames ///< .debug_names.
+  };
+
+  using MessageHandlerTy = std::function<void(
+      const Twine &Warning, StringRef Context, const DWARFDie *DIE)>;
+  using ObjFileLoaderTy = std::function<ErrorOr<DWARFFile &>(
+      StringRef ContainerName, StringRef Path)>;
+  using InputVerificationHandlerTy = std::function<void(const DWARFFile &File)>;
+  using ObjectPrefixMapTy = std::map<std::string, std::string>;
+  using CompileUnitHandlerTy = function_ref<void(const DWARFUnit &Unit)>;
+  using TranslatorFuncTy = std::function<StringRef(StringRef)>;
+  using SwiftInterfacesMapTy = std::map<std::string, std::string>;
+
+  virtual ~DWARFLinker() = default;
+
+  /// Creates dwarf linker instance.
+  static std::unique_ptr<DWARFLinker>
+  createLinker(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler,
+               TranslatorFuncTy StringsTranslator = nullptr);
+
+  /// Creates emitter for output dwarf.
+  virtual Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
+                              raw_pwrite_stream &OutFile) = 0;
+
+  /// Returns previously created dwarf emitter. May be nullptr.
+  virtual ExtraDwarfEmitter *getEmitter() = 0;
+
+  /// Add object file to be linked. Pre-load compile unit die. Call
+  /// \p OnCUDieLoaded for each compile unit die. If specified \p File
+  /// has reference to the Clang module then such module would be
+  /// pre-loaded by \p Loader for !Update case.
+  ///
+  /// \pre NoODR, Update options should be set before call to addObjectFile.
+  virtual void addObjectFile(
+      DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
+      CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) = 0;
+
+  /// Link debug info for added files.
+  virtual Error link() = 0;
+
+  /// \defgroup Methods setting various linking options:
+  ///
+  /// @{
+
+  /// Allows to generate log of linking process to the standard output.
+  virtual void setVerbosity(bool Verbose) = 0;
+
+  /// Print statistics to standard output.
+  virtual void setStatistics(bool Statistics) = 0;
+
+  /// Verify the input DWARF.
+  virtual void setVerifyInputDWARF(bool Verify) = 0;
+
+  /// Do not unique types according to ODR.
+  virtual void setNoODR(bool NoODR) = 0;
+
+  /// Update index tables only(do not modify rest of DWARF).
+  virtual void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) = 0;
+
+  /// Allow generating valid, but non-deterministic output.
+  virtual void
+  setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) = 0;
+
+  /// Set to keep the enclosing function for a static variable.
+  virtual void setKeepFunctionForStatic(bool KeepFunctionForStatic) = 0;
+
+  /// Use specified number of threads for parallel files linking.
+  virtual void setNumThreads(unsigned NumThreads) = 0;
+
+  /// Add kind of accelerator tables to be generated.
+  virtual void addAccelTableKind(AccelTableKind Kind) = 0;
+
+  /// Set prepend path for clang modules.
+  virtual void setPrependPath(const std::string &Ppath) = 0;
+
+  /// Set estimated objects files amount, for preliminary data allocation.
+  virtual void setEstimatedObjfilesAmount(unsigned ObjFilesNum) = 0;
+
+  /// Set verification handler which would be used to report verification
+  /// errors.
+  virtual void
+  setInputVerificationHandler(InputVerificationHandlerTy Handler) = 0;
+
+  /// Set map for Swift interfaces.
+  virtual void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) = 0;
+
+  /// Set prefix map for objects.
+  virtual void setObjectPrefixMap(ObjectPrefixMapTy *Map) = 0;
+
+  /// Set target DWARF version.
+  virtual Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) = 0;
+  /// @}
+};
+
+} // end namespace dwarflinker_parallel
 } // end namespace llvm
 
 #endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
diff --git a/include/llvm/DWARFLinkerParallel/StringTable.h b/include/llvm/DWARFLinkerParallel/StringTable.h
index ac1c39f..4f8aece 100644
--- a/include/llvm/DWARFLinkerParallel/StringTable.h
+++ b/include/llvm/DWARFLinkerParallel/StringTable.h
@@ -67,6 +67,10 @@
       Handler(*Entry);
   }
 
+  std::function<StringRef(StringRef)> getTranslator() {
+    return StringsTranslator;
+  }
+
 protected:
   /// List of strings for emission.
   StringsVector StringEntriesForEmission;
diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index b4978cc..8d6310a 100644
--- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -43,6 +43,9 @@
 class raw_ostream;
 struct DIDumpOptions;
 struct DWARFSection;
+namespace dwarflinker_parallel {
+class CompileUnit;
+}
 
 /// Base class describing the header of any kind of "unit."  Some information
 /// is specific to certain unit types.  We separate this class out so we can
@@ -253,6 +256,8 @@
   std::shared_ptr<DWARFUnit> DWO;
 
 protected:
+  friend dwarflinker_parallel::CompileUnit;
+
   /// Return the index of a \p Die entry inside the unit's DIE vector.
   ///
   /// It is illegal to call this method with a DIE that hasn't be
diff --git a/lib/DWARFLinker/DWARFLinker.cpp b/lib/DWARFLinker/DWARFLinker.cpp
index e1a2d01..7d02e05 100644
--- a/lib/DWARFLinker/DWARFLinker.cpp
+++ b/lib/DWARFLinker/DWARFLinker.cpp
@@ -12,6 +12,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/CodeGen/NonRelocatableStringpool.h"
 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
+#include "llvm/DWARFLinker/DWARFStreamer.h"
 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
@@ -2056,7 +2057,7 @@
 }
 
 void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
-  if (LLVM_UNLIKELY(Linker.Options.NoOutput))
+  if (LLVM_UNLIKELY(Emitter == nullptr))
     return;
 
   // Check whether DW_AT_stmt_list attribute is presented.
@@ -2177,9 +2178,9 @@
 }
 
 void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
-  for (DwarfLinkerAccelTableKind AccelTableKind : Options.AccelTables) {
+  for (AccelTableKind AccelTableKind : Options.AccelTables) {
     switch (AccelTableKind) {
-    case DwarfLinkerAccelTableKind::Apple: {
+    case AccelTableKind::Apple: {
       // Add namespaces.
       for (const auto &Namespace : Unit.getNamespaces())
         AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
@@ -2201,11 +2202,11 @@
         AppleObjc.addName(ObjC.Name,
                           ObjC.Die->getOffset() + Unit.getStartOffset());
     } break;
-    case DwarfLinkerAccelTableKind::Pub: {
+    case AccelTableKind::Pub: {
       TheDwarfEmitter->emitPubNamesForUnit(Unit);
       TheDwarfEmitter->emitPubTypesForUnit(Unit);
     } break;
-    case DwarfLinkerAccelTableKind::DebugNames: {
+    case AccelTableKind::DebugNames: {
       for (const auto &Namespace : Unit.getNamespaces())
         DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(),
                            Namespace.Die->getTag(), Unit.getUniqueID());
@@ -2524,7 +2525,7 @@
 uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
     DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) {
   uint64_t OutputDebugInfoSize =
-      Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize();
+      (Emitter == nullptr) ? 0 : Emitter->getDebugInfoSectionSize();
   const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
 
   for (auto &CurrentUnit : CompileUnits) {
@@ -2547,8 +2548,7 @@
 
     OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
 
-    if (!Linker.Options.NoOutput) {
-      assert(Emitter);
+    if (Emitter != nullptr) {
 
       generateLineTableForUnit(*CurrentUnit);
 
@@ -2575,10 +2575,10 @@
     }
   }
 
-  if (!Linker.Options.NoOutput) {
+  if (Emitter != nullptr) {
     assert(Emitter);
     // Emit macro tables.
-    Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, DebugStrPool);
+    Emitter->emitMacroTables(File.Dwarf.get(), UnitMacroMap, DebugStrPool);
 
     // Emit all the compile unit's debug information.
     for (auto &CurrentUnit : CompileUnits) {
@@ -2703,7 +2703,6 @@
 }
 
 Error DWARFLinker::link() {
-  assert(Options.NoOutput || TheDwarfEmitter);
   assert((Options.TargetDWARFVersion != 0) &&
          "TargetDWARFVersion should be set");
 
@@ -2793,7 +2792,8 @@
   // later. This prevents undeterminism when analyze and clone execute
   // concurrently, as clone set the canonical DIE offset and analyze reads it.
   const uint64_t ModulesEndOffset =
-      Options.NoOutput ? 0 : TheDwarfEmitter->getDebugInfoSectionSize();
+      (TheDwarfEmitter == nullptr) ? 0
+                                   : TheDwarfEmitter->getDebugInfoSectionSize();
 
   // These variables manage the list of processed object files.
   // The mutex and condition variable are to ensure that this is thread safe.
@@ -2878,13 +2878,13 @@
       SizeByObject[OptContext.File.FileName].Input =
           getDebugInfoSize(*OptContext.File.Dwarf);
       SizeByObject[OptContext.File.FileName].Output =
-          DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,
+          DIECloner(*this, TheDwarfEmitter.get(), OptContext.File, DIEAlloc,
                     OptContext.CompileUnits, Options.Update, DebugStrPool,
                     DebugLineStrPool)
               .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
                                     OptContext.File.Dwarf->isLittleEndian());
     }
-    if (!Options.NoOutput && !OptContext.CompileUnits.empty() &&
+    if ((TheDwarfEmitter != nullptr) && !OptContext.CompileUnits.empty() &&
         LLVM_LIKELY(!Options.Update))
       patchFrameInfoForObject(
           OptContext.File, OptContext.File.Addresses->getValidAddressRanges(),
@@ -2897,23 +2897,23 @@
 
   auto EmitLambda = [&]() {
     // Emit everything that's global.
-    if (!Options.NoOutput) {
+    if (TheDwarfEmitter != nullptr) {
       TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
       TheDwarfEmitter->emitStrings(DebugStrPool);
       TheDwarfEmitter->emitLineStrings(DebugLineStrPool);
-      for (DwarfLinkerAccelTableKind TableKind : Options.AccelTables) {
+      for (AccelTableKind TableKind : Options.AccelTables) {
         switch (TableKind) {
-        case DwarfLinkerAccelTableKind::Apple:
+        case AccelTableKind::Apple:
           TheDwarfEmitter->emitAppleNamespaces(AppleNamespaces);
           TheDwarfEmitter->emitAppleNames(AppleNames);
           TheDwarfEmitter->emitAppleTypes(AppleTypes);
           TheDwarfEmitter->emitAppleObjc(AppleObjc);
           break;
-        case DwarfLinkerAccelTableKind::Pub:
+        case AccelTableKind::Pub:
           // Already emitted by emitAcceleratorEntriesForUnit.
           // Already emitted by emitAcceleratorEntriesForUnit.
           break;
-        case DwarfLinkerAccelTableKind::DebugNames:
+        case AccelTableKind::DebugNames:
           TheDwarfEmitter->emitDebugNames(DebugNames);
           break;
         }
@@ -3041,7 +3041,7 @@
   UnitListTy CompileUnits;
   CompileUnits.emplace_back(std::move(Unit.Unit));
   assert(TheDwarfEmitter);
-  DIECloner(*this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
+  DIECloner(*this, TheDwarfEmitter.get(), Unit.File, DIEAlloc, CompileUnits,
             Options.Update, DebugStrPool, DebugLineStrPool)
       .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
                             Unit.File.Dwarf->isLittleEndian());
@@ -3059,4 +3059,16 @@
   }
 }
 
+Error DWARFLinker::createEmitter(const Triple &TheTriple,
+                                 OutputFileType FileType,
+                                 raw_pwrite_stream &OutFile) {
+
+  TheDwarfEmitter = std::make_unique<DwarfStreamer>(
+      FileType, OutFile, StringsTranslator, WarningHandler);
+
+  return TheDwarfEmitter->init(TheTriple, "__DWARF");
+}
+
+DwarfEmitter *DWARFLinker::getEmitter() { return TheDwarfEmitter.get(); }
+
 } // namespace llvm
diff --git a/lib/DWARFLinker/DWARFStreamer.cpp b/lib/DWARFLinker/DWARFStreamer.cpp
index ebc765e..739b503 100644
--- a/lib/DWARFLinker/DWARFStreamer.cpp
+++ b/lib/DWARFLinker/DWARFStreamer.cpp
@@ -28,33 +28,37 @@
 
 namespace llvm {
 
-bool DwarfStreamer::init(Triple TheTriple,
-                         StringRef Swift5ReflectionSegmentName) {
+Error DwarfStreamer::init(Triple TheTriple,
+                          StringRef Swift5ReflectionSegmentName) {
   std::string ErrorStr;
   std::string TripleName;
-  StringRef Context = "dwarf streamer init";
 
   // Get the target.
   const Target *TheTarget =
       TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
   if (!TheTarget)
-    return error(ErrorStr, Context), false;
+    return createStringError(std::errc::invalid_argument, ErrorStr.c_str());
+
   TripleName = TheTriple.getTriple();
 
   // Create all the MC Objects.
   MRI.reset(TheTarget->createMCRegInfo(TripleName));
   if (!MRI)
-    return error(Twine("no register info for target ") + TripleName, Context),
-           false;
+    return createStringError(std::errc::invalid_argument,
+                             "no register info for target %s",
+                             TripleName.c_str());
 
   MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
   MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
   if (!MAI)
-    return error("no asm info for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no asm info for target %s", TripleName.c_str());
 
   MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
   if (!MSTI)
-    return error("no subtarget info for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no subtarget info for target %s",
+                             TripleName.c_str());
 
   MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,
                          nullptr, true, Swift5ReflectionSegmentName));
@@ -63,18 +67,24 @@
 
   MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
   if (!MAB)
-    return error("no asm backend for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no asm backend for target %s",
+                             TripleName.c_str());
 
   MII.reset(TheTarget->createMCInstrInfo());
   if (!MII)
-    return error("no instr info info for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no instr info info for target %s",
+                             TripleName.c_str());
 
   MCE = TheTarget->createMCCodeEmitter(*MII, *MC);
   if (!MCE)
-    return error("no code emitter for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no code emitter for target %s",
+                             TripleName.c_str());
 
   switch (OutFileType) {
-  case OutputFileType::Assembly: {
+  case DWARFLinker::OutputFileType::Assembly: {
     MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(),
                                          *MAI, *MII, *MRI);
     MS = TheTarget->createAsmStreamer(
@@ -83,7 +93,7 @@
         true);
     break;
   }
-  case OutputFileType::Object: {
+  case DWARFLinker::OutputFileType::Object: {
     MS = TheTarget->createMCObjectStreamer(
         TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
         MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
@@ -94,17 +104,23 @@
   }
 
   if (!MS)
-    return error("no object streamer for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no object streamer for target %s",
+                             TripleName.c_str());
 
   // Finally create the AsmPrinter we'll use to emit the DIEs.
   TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
                                           std::nullopt));
   if (!TM)
-    return error("no target machine for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no target machine for target %s",
+                             TripleName.c_str());
 
   Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
   if (!Asm)
-    return error("no asm printer for target " + TripleName, Context), false;
+    return createStringError(std::errc::invalid_argument,
+                             "no asm printer for target %s",
+                             TripleName.c_str());
   Asm->setDwarfUsesRelocationsAcrossSections(false);
 
   RangesSectionSize = 0;
@@ -117,7 +133,7 @@
   MacInfoSectionSize = 0;
   MacroSectionSize = 0;
 
-  return true;
+  return Error::success();
 }
 
 void DwarfStreamer::finish() { MS->finish(); }
diff --git a/lib/DWARFLinkerParallel/CMakeLists.txt b/lib/DWARFLinkerParallel/CMakeLists.txt
index 390c192..8a1481c 100644
--- a/lib/DWARFLinkerParallel/CMakeLists.txt
+++ b/lib/DWARFLinkerParallel/CMakeLists.txt
@@ -1,5 +1,8 @@
 add_llvm_component_library(LLVMDWARFLinkerParallel
+  DWARFEmitterImpl.cpp
   DWARFLinker.cpp
+  DWARFLinkerImpl.cpp
+  OutputSections.cpp
   StringPool.cpp
 
   ADDITIONAL_HEADER_DIRS
@@ -16,4 +19,5 @@
   MC
   Object
   Support
+  TargetParser
   )
diff --git a/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp b/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp
new file mode 100644
index 0000000..50909c0
--- /dev/null
+++ b/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp
@@ -0,0 +1,131 @@
+//===- DWARFEmitterImpl.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 "DWARFEmitterImpl.h"
+#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/FormattedStream.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+Error DwarfEmitterImpl::init(Triple TheTriple,
+                             StringRef Swift5ReflectionSegmentName) {
+  std::string ErrorStr;
+  std::string TripleName;
+
+  // Get the target.
+  const Target *TheTarget =
+      TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
+  if (!TheTarget)
+    return createStringError(std::errc::invalid_argument, ErrorStr.c_str());
+  TripleName = TheTriple.getTriple();
+
+  // Create all the MC Objects.
+  MRI.reset(TheTarget->createMCRegInfo(TripleName));
+  if (!MRI)
+    return createStringError(std::errc::invalid_argument,
+                             "no register info for target %s",
+                             TripleName.c_str());
+
+  MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
+  MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
+  if (!MAI)
+    return createStringError(std::errc::invalid_argument,
+                             "no asm info for target %s", TripleName.c_str());
+
+  MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+  if (!MSTI)
+    return createStringError(std::errc::invalid_argument,
+                             "no subtarget info for target %s",
+                             TripleName.c_str());
+
+  MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,
+                         nullptr, true, Swift5ReflectionSegmentName));
+  MOFI.reset(TheTarget->createMCObjectFileInfo(*MC, /*PIC=*/false, false));
+  MC->setObjectFileInfo(MOFI.get());
+
+  MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
+  if (!MAB)
+    return createStringError(std::errc::invalid_argument,
+                             "no asm backend for target %s",
+                             TripleName.c_str());
+
+  MII.reset(TheTarget->createMCInstrInfo());
+  if (!MII)
+    return createStringError(std::errc::invalid_argument,
+                             "no instr info info for target %s",
+                             TripleName.c_str());
+
+  MCE = TheTarget->createMCCodeEmitter(*MII, *MC);
+  if (!MCE)
+    return createStringError(std::errc::invalid_argument,
+                             "no code emitter for target %s",
+                             TripleName.c_str());
+
+  switch (OutFileType) {
+  case DWARFLinker::OutputFileType::Assembly: {
+    MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(),
+                                         *MAI, *MII, *MRI);
+    MS = TheTarget->createAsmStreamer(
+        *MC, std::make_unique<formatted_raw_ostream>(OutFile), true, true, MIP,
+        std::unique_ptr<MCCodeEmitter>(MCE), std::unique_ptr<MCAsmBackend>(MAB),
+        true);
+    break;
+  }
+  case DWARFLinker::OutputFileType::Object: {
+    MS = TheTarget->createMCObjectStreamer(
+        TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
+        MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
+        *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible,
+        /*DWARFMustBeAtTheEnd*/ false);
+    break;
+  }
+  }
+
+  if (!MS)
+    return createStringError(std::errc::invalid_argument,
+                             "no object streamer for target %s",
+                             TripleName.c_str());
+
+  // Finally create the AsmPrinter we'll use to emit the DIEs.
+  TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
+                                          std::nullopt));
+  if (!TM)
+    return createStringError(std::errc::invalid_argument,
+                             "no target machine for target %s",
+                             TripleName.c_str());
+
+  Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
+  if (!Asm)
+    return createStringError(std::errc::invalid_argument,
+                             "no asm printer for target %s",
+                             TripleName.c_str());
+  Asm->setDwarfUsesRelocationsAcrossSections(false);
+
+  RangesSectionSize = 0;
+  RngListsSectionSize = 0;
+  LocSectionSize = 0;
+  LocListsSectionSize = 0;
+  LineSectionSize = 0;
+  FrameSectionSize = 0;
+  DebugInfoSectionSize = 0;
+  MacInfoSectionSize = 0;
+  MacroSectionSize = 0;
+
+  return Error::success();
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm
diff --git a/lib/DWARFLinkerParallel/DWARFEmitterImpl.h b/lib/DWARFLinkerParallel/DWARFEmitterImpl.h
new file mode 100644
index 0000000..d07397a
--- /dev/null
+++ b/lib/DWARFLinkerParallel/DWARFEmitterImpl.h
@@ -0,0 +1,274 @@
+//===- DwarfEmitterImpl.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_DWARFEMITTERIMPL_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H
+
+#include "DWARFLinkerCompileUnit.h"
+#include "llvm/BinaryFormat/Swift.h"
+#include "llvm/CodeGen/AccelTable.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
+#include "llvm/DWARFLinkerParallel/StringTable.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+
+///   User of DwarfEmitterImpl should call initialization code
+///   for AsmPrinter:
+///
+///   InitializeAllTargetInfos();
+///   InitializeAllTargetMCs();
+///   InitializeAllTargets();
+///   InitializeAllAsmPrinters();
+
+template <typename DataT> class AccelTable;
+class MCCodeEmitter;
+class DWARFDebugMacro;
+
+namespace dwarflinker_parallel {
+
+struct UnitStartSymbol {
+  unsigned UnitID = 0;
+  MCSymbol *Symbol = 0;
+};
+using UnitStartSymbolsTy = SmallVector<UnitStartSymbol>;
+using Offset2UnitMapTy = DenseMap<uint64_t, CompileUnit *>;
+
+struct RangeAttrPatch;
+struct LocAttrPatch;
+
+/// The Dwarf emission logic.
+///
+/// All interactions with the MC layer that is used to build the debug
+/// information binary representation are handled in this class.
+class DwarfEmitterImpl : public ExtraDwarfEmitter {
+public:
+  DwarfEmitterImpl(DWARFLinker::OutputFileType OutFileType,
+                   raw_pwrite_stream &OutFile,
+                   std::function<StringRef(StringRef Input)> Translator,
+                   DWARFLinker::MessageHandlerTy Warning)
+      : OutFile(OutFile), OutFileType(OutFileType), Translator(Translator),
+        WarningHandler(Warning) {}
+
+  Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName);
+
+  /// Dump the file to the disk.
+  void finish() override { MS->finish(); }
+
+  AsmPrinter &getAsmPrinter() const override { return *Asm; }
+
+  /// Set the current output section to debug_info and change
+  /// the MC Dwarf version to \p DwarfVersion.
+  void switchToDebugInfoSection(unsigned DwarfVersion) {}
+
+  /// Emit the swift_ast section stored in \p Buffer.
+  void emitSwiftAST(StringRef Buffer) override {}
+
+  /// Emit the swift reflection section stored in \p Buffer.
+  void emitSwiftReflectionSection(
+      llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
+      StringRef Buffer, uint32_t Alignment, uint32_t Size) override {}
+
+  void emitPaperTrailWarningsDie(DIE &Die) {}
+
+  void emitSectionContents(StringRef SecData, StringRef SecName) override {}
+
+  MCSymbol *emitTempSym(StringRef SecName, StringRef SymName) override {
+    return nullptr;
+  }
+
+  void emitAbbrevs(const SmallVector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
+                   unsigned DwarfVersion) {}
+
+  void emitStrings(const StringTable &Strings) {}
+
+  void emitLineStrings(const StringTable &Strings) {}
+
+  void emitDebugNames(AccelTable<DWARF5AccelTableStaticData> &,
+                      UnitStartSymbolsTy &UnitOffsets) {}
+
+  void emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &) {}
+
+  void emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &) {}
+
+  void emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &) {}
+
+  void emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &) {}
+
+  MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) {
+    return nullptr;
+  }
+
+  void emitDwarfDebugRangeListFragment(const CompileUnit &Unit,
+                                       const AddressRanges &LinkedRanges,
+                                       RangeAttrPatch &Patch) {}
+
+  void emitDwarfDebugRangeListFooter(const CompileUnit &Unit,
+                                     MCSymbol *EndLabel) {}
+
+  MCSymbol *emitDwarfDebugLocListHeader(const CompileUnit &Unit) {
+    return nullptr;
+  }
+
+  void emitDwarfDebugLocListFragment(
+      const CompileUnit &Unit,
+      const DWARFLocationExpressionsVector &LinkedLocationExpression,
+      LocAttrPatch &Patch) {}
+
+  void emitDwarfDebugLocListFooter(const CompileUnit &Unit,
+                                   MCSymbol *EndLabel) {}
+
+  void emitDwarfDebugArangesTable(const CompileUnit &Unit,
+                                  const AddressRanges &LinkedRanges) {}
+
+  void translateLineTable(DataExtractor LineData, uint64_t Offset) {}
+
+  void emitLineTableForUnit(MCDwarfLineTableParams Params,
+                            StringRef PrologueBytes, unsigned MinInstLength,
+                            std::vector<DWARFDebugLine::Row> &Rows,
+                            unsigned AdddressSize) {}
+
+  void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable,
+                            const CompileUnit &Unit, const StringTable &Strings,
+                            const StringTable &LineTableStrings) {}
+
+  void emitPubNamesForUnit(const CompileUnit &Unit) {}
+
+  void emitPubTypesForUnit(const CompileUnit &Unit) {}
+
+  void emitCIE(StringRef CIEBytes) {}
+
+  void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address,
+               StringRef Bytes) {}
+
+  void emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) {}
+
+  void emitDIE(DIE &Die) {}
+
+  void emitMacroTables(DWARFContext *Context,
+                       const Offset2UnitMapTy &UnitMacroMap,
+                       StringTable &Strings) {}
+
+  /// Returns size of generated .debug_line section.
+  uint64_t getDebugLineSectionSize() const { return LineSectionSize; }
+
+  /// Returns size of generated .debug_frame section.
+  uint64_t getDebugFrameSectionSize() const { return FrameSectionSize; }
+
+  /// Returns size of generated .debug_ranges section.
+  uint64_t getDebugRangesSectionSize() const { return RangesSectionSize; }
+
+  /// Returns size of generated .debug_rnglists section.
+  uint64_t getDebugRngListsSectionSize() const { return RngListsSectionSize; }
+
+  /// Returns size of generated .debug_info section.
+  uint64_t getDebugInfoSectionSize() const { return DebugInfoSectionSize; }
+
+  /// Returns size of generated .debug_macinfo section.
+  uint64_t getDebugMacInfoSectionSize() const { return MacInfoSectionSize; }
+
+  /// Returns size of generated .debug_macro section.
+  uint64_t getDebugMacroSectionSize() const { return MacroSectionSize; }
+
+  /// Returns size of generated .debug_loc section.
+  uint64_t getDebugLocSectionSize() const { return LocSectionSize; }
+
+  /// Returns size of generated .debug_loclists section.
+  uint64_t getDebugLocListsSectionSize() const { return LocListsSectionSize; }
+
+private:
+  inline void warn(const Twine &Warning, StringRef Context = "") {
+    if (WarningHandler)
+      WarningHandler(Warning, Context, nullptr);
+  }
+
+  void emitMacroTableImpl(const DWARFDebugMacro *MacroTable,
+                          const Offset2UnitMapTy &UnitMacroMap,
+                          StringPool &StringPool, uint64_t &OutOffset) {}
+
+  /// Emit piece of .debug_ranges for \p LinkedRanges.
+  void emitDwarfDebugRangesTableFragment(const CompileUnit &Unit,
+                                         const AddressRanges &LinkedRanges,
+                                         RangeAttrPatch &Patch) {}
+
+  /// Emit piece of .debug_rnglists for \p LinkedRanges.
+  void emitDwarfDebugRngListsTableFragment(const CompileUnit &Unit,
+                                           const AddressRanges &LinkedRanges,
+                                           RangeAttrPatch &Patch) {}
+
+  /// Emit piece of .debug_loc for \p LinkedRanges.
+  void emitDwarfDebugLocTableFragment(
+      const CompileUnit &Unit,
+      const DWARFLocationExpressionsVector &LinkedLocationExpression,
+      LocAttrPatch &Patch) {}
+
+  /// Emit piece of .debug_loclists for \p LinkedRanges.
+  void emitDwarfDebugLocListsTableFragment(
+      const CompileUnit &Unit,
+      const DWARFLocationExpressionsVector &LinkedLocationExpression,
+      LocAttrPatch &Patch) {}
+
+  /// \defgroup MCObjects MC layer objects constructed by the streamer
+  /// @{
+  std::unique_ptr<MCRegisterInfo> MRI;
+  std::unique_ptr<MCAsmInfo> MAI;
+  std::unique_ptr<MCObjectFileInfo> MOFI;
+  std::unique_ptr<MCContext> MC;
+  MCAsmBackend *MAB; // Owned by MCStreamer
+  std::unique_ptr<MCInstrInfo> MII;
+  std::unique_ptr<MCSubtargetInfo> MSTI;
+  MCInstPrinter *MIP; // Owned by AsmPrinter
+  MCCodeEmitter *MCE; // Owned by MCStreamer
+  MCStreamer *MS;     // Owned by AsmPrinter
+  std::unique_ptr<TargetMachine> TM;
+  std::unique_ptr<AsmPrinter> Asm;
+  /// @}
+
+  /// The output file we stream the linked Dwarf to.
+  raw_pwrite_stream &OutFile;
+  DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object;
+  std::function<StringRef(StringRef Input)> Translator;
+
+  uint64_t RangesSectionSize = 0;
+  uint64_t RngListsSectionSize = 0;
+  uint64_t LocSectionSize = 0;
+  uint64_t LocListsSectionSize = 0;
+  uint64_t LineSectionSize = 0;
+  uint64_t FrameSectionSize = 0;
+  uint64_t DebugInfoSectionSize = 0;
+  uint64_t MacInfoSectionSize = 0;
+  uint64_t MacroSectionSize = 0;
+
+  /// Keep track of emitted CUs and their Unique ID.
+  struct EmittedUnit {
+    unsigned ID;
+    MCSymbol *LabelBegin;
+  };
+  std::vector<EmittedUnit> EmittedUnitsTy;
+
+  /// Emit the pubnames or pubtypes section contribution for \p
+  /// Unit into \p Sec. The data is provided in \p Names.
+  void emitPubSectionForUnit(MCSection *Sec, StringRef Name,
+                             const CompileUnit &Unit,
+                             const std::vector<CompileUnit::AccelInfo> &Names);
+
+  DWARFLinker::MessageHandlerTy WarningHandler = nullptr;
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H
diff --git a/lib/DWARFLinkerParallel/DWARFLinker.cpp b/lib/DWARFLinkerParallel/DWARFLinker.cpp
index a54d2e3..f082fd6 100644
--- a/lib/DWARFLinkerParallel/DWARFLinker.cpp
+++ b/lib/DWARFLinkerParallel/DWARFLinker.cpp
@@ -6,8 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
+#include "DWARFLinkerImpl.h"
 
-namespace llvm {
-namespace dwarflinker_parallel {} // end of namespace dwarflinker_parallel
-} // namespace llvm
+std::unique_ptr<llvm::dwarflinker_parallel::DWARFLinker>
+llvm::dwarflinker_parallel::DWARFLinker::createLinker(
+    MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler,
+    TranslatorFuncTy StringsTranslator) {
+  return std::make_unique<DWARFLinkerImpl>(ErrorHandler, WarningHandler,
+                                           StringsTranslator);
+}
diff --git a/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h b/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
new file mode 100644
index 0000000..6182dff
--- /dev/null
+++ b/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
@@ -0,0 +1,163 @@
+//===- DWARFLinkerCompileUnit.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_DWARFLINKERCOMPILEUNIT_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
+
+#include "DWARFLinkerUnit.h"
+#include "llvm/DWARFLinkerParallel/DWARFFile.h"
+#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
+#include <optional>
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+struct LinkContext;
+class DWARFFile;
+
+/// Stores all information related to a compile unit, be it in its original
+/// instance of the object file or its brand new cloned and generated DIE tree.
+class CompileUnit : public DwarfUnit {
+public:
+  CompileUnit(LinkContext &Context, unsigned ID, StringRef ClangModuleName,
+              DWARFFile &File,
+              DWARFLinker::SwiftInterfacesMapTy *SwiftInterfaces,
+              UnitMessageHandlerTy WarningHandler)
+      : DwarfUnit(ID, ClangModuleName, WarningHandler), Context(Context),
+        ContaingFile(File), ParseableSwiftInterfaces(SwiftInterfaces) {
+    FormParams.Version = 4;
+    FormParams.Format = dwarf::DWARF32;
+    FormParams.AddrSize = 4;
+    UnitName = ContaingFile.FileName;
+  }
+
+  CompileUnit(LinkContext &Context, DWARFUnit &OrigUnit, unsigned ID,
+              StringRef ClangModuleName, DWARFFile &File,
+              UnitMessageHandlerTy WarningHandler)
+      : DwarfUnit(ID, ClangModuleName, WarningHandler), Context(Context),
+        ContaingFile(File), OrigUnit(&OrigUnit) {
+    DWARFDie CUDie = OrigUnit.getUnitDIE();
+    if (!CUDie)
+      return;
+
+    if (File.Dwarf)
+      Endianess = File.Dwarf->isLittleEndian() ? support::endianness::little
+                                               : support::endianness::big;
+
+    FormParams.Version = OrigUnit.getVersion();
+    FormParams.Format = dwarf::DWARF32;
+    FormParams.AddrSize = OrigUnit.getAddressByteSize();
+
+    Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0);
+
+    UnitName = ContaingFile.FileName;
+    SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str();
+  }
+
+  /// \defgroup Helper methods to access OrigUnit.
+  ///
+  /// @{
+
+  /// Returns paired compile unit from input DWARF.
+  DWARFUnit &getOrigUnit() const {
+    assert(OrigUnit != nullptr);
+    return *OrigUnit;
+  }
+
+  const DWARFDebugInfoEntry *
+  getFirstChildEntry(const DWARFDebugInfoEntry *Die) const {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getFirstChildEntry(Die);
+  }
+
+  const DWARFDebugInfoEntry *
+  getSiblingEntry(const DWARFDebugInfoEntry *Die) const {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getSiblingEntry(Die);
+  }
+
+  DWARFDie getParent(const DWARFDebugInfoEntry *Die) {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getParent(Die);
+  }
+
+  DWARFDie getDIEAtIndex(unsigned Index) {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getDIEAtIndex(Index);
+  }
+
+  const DWARFDebugInfoEntry *getDebugInfoEntry(unsigned Index) const {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getDebugInfoEntry(Index);
+  }
+
+  DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getUnitDIE(ExtractUnitDIEOnly);
+  }
+
+  DWARFDie getDIE(const DWARFDebugInfoEntry *Die) {
+    assert(OrigUnit != nullptr);
+    return DWARFDie(OrigUnit, Die);
+  }
+
+  uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) const {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getDIEIndex(Die);
+  }
+
+  uint32_t getDIEIndex(const DWARFDie &Die) const {
+    assert(OrigUnit != nullptr);
+    return OrigUnit->getDIEIndex(Die);
+  }
+
+  std::optional<DWARFFormValue> find(uint32_t DieIdx,
+                                     ArrayRef<dwarf::Attribute> Attrs) const {
+    assert(OrigUnit != nullptr);
+    return find(OrigUnit->getDebugInfoEntry(DieIdx), Attrs);
+  }
+
+  std::optional<DWARFFormValue> find(const DWARFDebugInfoEntry *Die,
+                                     ArrayRef<dwarf::Attribute> Attrs) const {
+    if (!Die)
+      return std::nullopt;
+    auto AbbrevDecl = Die->getAbbreviationDeclarationPtr();
+    if (AbbrevDecl) {
+      for (auto Attr : Attrs) {
+        if (auto Value = AbbrevDecl->getAttributeValue(Die->getOffset(), Attr,
+                                                       *OrigUnit))
+          return Value;
+      }
+    }
+    return std::nullopt;
+  }
+
+  std::optional<uint32_t> getDIEIndexForOffset(uint64_t Offset) {
+    return OrigUnit->getDIEIndexForOffset(Offset);
+  }
+
+  /// @}
+
+private:
+  /// Context containing this compilation unit.
+  LinkContext &Context;
+
+  /// DWARFFile containing this compile unit.
+  DWARFFile &ContaingFile;
+
+  /// Pointer to the paired compile unit from the input DWARF.
+  DWARFUnit *OrigUnit = nullptr;
+
+  /// Map for swift interfaces.
+  DWARFLinker::SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
diff --git a/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp b/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
new file mode 100644
index 0000000..dfd77af
--- /dev/null
+++ b/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
@@ -0,0 +1,46 @@
+//=== DWARFLinkerImpl.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 "DWARFLinkerImpl.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
+/// CompileUnit object instead.
+CompileUnit *
+DWARFLinkerImpl::LinkContext::getUnitForOffset(CompileUnit &CurrentCU,
+                                               uint64_t Offset) const {
+  if (CurrentCU.isClangModule())
+    return &CurrentCU;
+
+  auto CU = llvm::upper_bound(
+      CompileUnits, Offset,
+      [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) {
+        return LHS < RHS->getOrigUnit().getNextUnitOffset();
+      });
+
+  return CU != CompileUnits.end() ? CU->get() : nullptr;
+}
+
+Error DWARFLinkerImpl::createEmitter(const Triple &TheTriple,
+                                     OutputFileType FileType,
+                                     raw_pwrite_stream &OutFile) {
+
+  TheDwarfEmitter = std::make_unique<DwarfEmitterImpl>(
+      FileType, OutFile, OutputStrings.getTranslator(), WarningHandler);
+
+  return TheDwarfEmitter->init(TheTriple, "__DWARF");
+}
+
+ExtraDwarfEmitter *DWARFLinkerImpl::getEmitter() {
+  return TheDwarfEmitter.get();
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm
diff --git a/lib/DWARFLinkerParallel/DWARFLinkerImpl.h b/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
new file mode 100644
index 0000000..88e284f
--- /dev/null
+++ b/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
@@ -0,0 +1,320 @@
+//===- DWARFLinkerImpl.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_DWARFLINKERIMPL_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H
+
+#include "DWARFEmitterImpl.h"
+#include "DWARFLinkerCompileUnit.h"
+#include "llvm/ADT/AddressRanges.h"
+#include "llvm/CodeGen/AccelTable.h"
+#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
+#include "llvm/DWARFLinkerParallel/StringPool.h"
+#include "llvm/DWARFLinkerParallel/StringTable.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+using Offset2UnitMapTy = DenseMap<uint64_t, CompileUnit *>;
+
+struct RangeAttrPatch;
+struct LocAttrPatch;
+
+class DWARFLinkerImpl : public DWARFLinker {
+public:
+  DWARFLinkerImpl(MessageHandlerTy ErrorHandler,
+                  MessageHandlerTy WarningHandler,
+                  TranslatorFuncTy StringsTranslator)
+      : UniqueUnitID(0), ErrorHandler(ErrorHandler),
+        WarningHandler(WarningHandler),
+        OutputStrings(Strings, StringsTranslator) {}
+
+  Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
+                      raw_pwrite_stream &OutFile) override;
+
+  ExtraDwarfEmitter *getEmitter() override;
+
+  /// Add object file to be linked. Pre-load compile unit die. Call
+  /// \p OnCUDieLoaded for each compile unit die. If specified \p File
+  /// has reference to the Clang module then such module would be
+  /// pre-loaded by \p Loader for !Update case.
+  ///
+  /// \pre NoODR, Update options should be set before call to addObjectFile.
+  void addObjectFile(
+      DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
+      CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override {}
+
+  /// Link debug info for added files.
+  Error link() override {
+    reportWarning("LLVM parallel dwarflinker is not implemented yet.", "");
+    return Error::success();
+  }
+
+  /// \defgroup Methods setting various linking options:
+  ///
+  /// @{
+  ///
+
+  /// Allows to generate log of linking process to the standard output.
+  void setVerbosity(bool Verbose) override { Options.Verbose = Verbose; }
+
+  /// Print statistics to standard output.
+  void setStatistics(bool Statistics) override {
+    Options.Statistics = Statistics;
+  }
+
+  /// Verify the input DWARF.
+  void setVerifyInputDWARF(bool Verify) override {
+    Options.VerifyInputDWARF = Verify;
+  }
+
+  /// Do not unique types according to ODR.
+  void setNoODR(bool NoODR) override { Options.NoODR = NoODR; }
+
+  /// Update index tables only(do not modify rest of DWARF).
+  void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override {
+    Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly;
+  }
+
+  /// Allow generating valid, but non-deterministic output.
+  void
+  setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override {
+    Options.AllowNonDeterministicOutput = AllowNonDeterministicOutput;
+  }
+
+  /// Set to keep the enclosing function for a static variable.
+  void setKeepFunctionForStatic(bool KeepFunctionForStatic) override {
+    Options.KeepFunctionForStatic = KeepFunctionForStatic;
+  }
+
+  /// Use specified number of threads for parallel files linking.
+  void setNumThreads(unsigned NumThreads) override {
+    Options.Threads = NumThreads;
+  }
+
+  /// Add kind of accelerator tables to be generated.
+  void addAccelTableKind(AccelTableKind Kind) override {
+    assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(),
+                     Kind) == Options.AccelTables.end());
+    Options.AccelTables.emplace_back(Kind);
+  }
+
+  /// Set prepend path for clang modules.
+  void setPrependPath(const std::string &Ppath) override {
+    Options.PrependPath = Ppath;
+  }
+
+  /// Set estimated objects files amount, for preliminary data allocation.
+  void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override {
+    ObjectContexts.reserve(ObjFilesNum);
+  }
+
+  /// Set verification handler which would be used to report verification
+  /// errors.
+  void
+  setInputVerificationHandler(InputVerificationHandlerTy Handler) override {
+    Options.InputVerificationHandler = Handler;
+  }
+
+  /// Set map for Swift interfaces.
+  void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override {
+    Options.ParseableSwiftInterfaces = Map;
+  }
+
+  /// Set prefix map for objects.
+  void setObjectPrefixMap(ObjectPrefixMapTy *Map) override {
+    Options.ObjectPrefixMap = Map;
+  }
+
+  /// Set target DWARF version.
+  Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override {
+    if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5))
+      return createStringError(std::errc::invalid_argument,
+                               "unsupported DWARF version: %d",
+                               TargetDWARFVersion);
+
+    Options.TargetDWARFVersion = TargetDWARFVersion;
+    return Error::success();
+  }
+  /// @}
+
+protected:
+  /// Reports Warning.
+  void reportWarning(const Twine &Warning, const DWARFFile &File,
+                     const DWARFDie *DIE = nullptr) const {
+    if (WarningHandler != nullptr)
+      WarningHandler(Warning, File.FileName, DIE);
+  }
+
+  /// Reports Warning.
+  void reportWarning(const Twine &Warning, StringRef FileName,
+                     const DWARFDie *DIE = nullptr) const {
+    if (WarningHandler != nullptr)
+      WarningHandler(Warning, FileName, DIE);
+  }
+
+  /// Reports Error.
+  void reportError(const Twine &Warning, StringRef FileName,
+                   const DWARFDie *DIE = nullptr) const {
+    if (ErrorHandler != nullptr)
+      ErrorHandler(Warning, FileName, DIE);
+  }
+
+  /// Returns next available unique Compile Unit ID.
+  unsigned getNextUniqueUnitID() { return UniqueUnitID.fetch_add(1); }
+
+  /// Keeps track of data associated with one object during linking.
+  /// i.e. source file descriptor, compilation units, output data
+  /// for compilation units common tables.
+  struct LinkContext : public OutputSections {
+    using UnitListTy = SmallVector<std::unique_ptr<CompileUnit>>;
+
+    /// 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(const RefModuleUnit &) = delete;
+
+      DWARFFile &File;
+      std::unique_ptr<CompileUnit> Unit;
+    };
+    using ModuleUnitListTy = SmallVector<RefModuleUnit>;
+
+    /// Object file descriptor.
+    DWARFFile &File;
+
+    /// Set of Compilation Units(may be accessed asynchroniously for reading).
+    UnitListTy CompileUnits;
+
+    /// Set of Compile Units for modules.
+    ModuleUnitListTy ModulesCompileUnits;
+
+    /// Size of Debug info before optimizing.
+    uint64_t OriginalDebugInfoSize = 0;
+
+    /// Output sections, common for all compilation units.
+    OutTablesFileTy OutDebugInfoBytes;
+
+    /// Endianness for the final file.
+    support::endianness Endianess = support::endianness::little;
+
+    LinkContext(DWARFFile &File) : File(File) {
+      if (File.Dwarf) {
+        if (!File.Dwarf->compile_units().empty())
+          CompileUnits.reserve(File.Dwarf->getNumCompileUnits());
+
+        Endianess = File.Dwarf->isLittleEndian() ? support::endianness::little
+                                                 : support::endianness::big;
+      }
+    }
+
+    /// Add Compile Unit corresponding to the module.
+    void addModulesCompileUnit(RefModuleUnit &&Unit) {
+      ModulesCompileUnits.emplace_back(std::move(Unit));
+    }
+
+    /// Return Endiannes of the source DWARF information.
+    support::endianness getEndianness() { return Endianess; }
+
+    /// \returns pointer to compilation unit which corresponds \p Offset.
+    CompileUnit *getUnitForOffset(CompileUnit &CU, uint64_t Offset) const;
+  };
+
+  /// linking options
+  struct DWARFLinkerOptions {
+    /// DWARF version for the output.
+    uint16_t TargetDWARFVersion = 0;
+
+    /// Generate processing log to the standard output.
+    bool Verbose = false;
+
+    /// Print statistics.
+    bool Statistics = false;
+
+    /// Verify the input DWARF.
+    bool VerifyInputDWARF = false;
+
+    /// Do not unique types according to ODR
+    bool NoODR = false;
+
+    /// Update index tables.
+    bool UpdateIndexTablesOnly = false;
+
+    /// Whether we want a static variable to force us to keep its enclosing
+    /// function.
+    bool KeepFunctionForStatic = false;
+
+    /// Allow to generate valid, but non deterministic output.
+    bool AllowNonDeterministicOutput = false;
+
+    /// Number of threads.
+    unsigned Threads = 1;
+
+    /// The accelerator table kinds
+    SmallVector<AccelTableKind, 1> AccelTables;
+
+    /// Prepend path for the clang modules.
+    std::string PrependPath;
+
+    /// input verification handler(it might be called asynchronously).
+    InputVerificationHandlerTy InputVerificationHandler = nullptr;
+
+    /// A list of all .swiftinterface files referenced by the debug
+    /// info, mapping Module name to path on disk. The entries need to
+    /// be uniqued and sorted and there are only few entries expected
+    /// per compile unit, which is why this is a std::map.
+    /// this is dsymutil specific fag.
+    ///
+    /// (it might be called asynchronously).
+    SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr;
+
+    /// A list of remappings to apply to file paths.
+    ///
+    /// (it might be called asynchronously).
+    ObjectPrefixMapTy *ObjectPrefixMap = nullptr;
+  } Options;
+
+  /// \defgroup Data members accessed asinchroniously.
+  ///
+  /// @{
+
+  /// Unique ID for compile unit.
+  std::atomic<unsigned> UniqueUnitID;
+
+  /// Strings pool. Keeps all strings.
+  StringPool Strings;
+
+  /// error handler(it might be called asynchronously).
+  MessageHandlerTy ErrorHandler = nullptr;
+
+  /// warning handler(it might be called asynchronously).
+  MessageHandlerTy WarningHandler = nullptr;
+  /// @}
+
+  /// \defgroup Data members accessed sequentially.
+  ///
+  /// @{
+
+  /// Set of strings which should be emitted.
+  StringTable OutputStrings;
+
+  /// Keeps all linking contexts.
+  SmallVector<std::unique_ptr<LinkContext>> ObjectContexts;
+
+  /// The emitter of final dwarf file.
+  std::unique_ptr<DwarfEmitterImpl> TheDwarfEmitter;
+  /// @}
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H
diff --git a/lib/DWARFLinkerParallel/DWARFLinkerUnit.h b/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
new file mode 100644
index 0000000..0d5905a
--- /dev/null
+++ b/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
@@ -0,0 +1,185 @@
+//===- DWARFLinkerUnit.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_DWARFLINKERUNIT_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
+
+#include "OutputSections.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DWARFLinkerParallel/StringPool.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/LEB128.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+using UnitMessageHandlerTy = function_ref<void(
+    const Twine &Error, StringRef Context, const DWARFDie *DIE)>;
+
+/// Each unit keeps output data as a file with debug tables
+/// corresponding to the concrete unit.
+using OutTablesFileTy = SmallString<0>;
+
+/// Base class for all Dwarf units(Compile unit/Type table unit).
+class DwarfUnit : public OutputSections {
+public:
+  virtual ~DwarfUnit() {}
+  DwarfUnit(unsigned ID, StringRef ClangModuleName,
+            UnitMessageHandlerTy WarningHandler)
+      : ID(ID), ClangModuleName(ClangModuleName),
+        WarningHandler(WarningHandler) {
+    FormParams.Version = 4;
+    FormParams.Format = dwarf::DWARF32;
+    FormParams.AddrSize = 4;
+  }
+
+  /// Endiannes for the compile unit.
+  support::endianness getEndianness() const { return Endianess; }
+
+  /// Return DWARF version.
+  uint16_t getVersion() const { return FormParams.Version; }
+
+  /// Return size of header of debug_info table.
+  uint16_t getHeaderSize() const { return FormParams.Version >= 5 ? 12 : 11; }
+
+  /// Return size of address.
+  uint8_t getAddressByteSize() const { return FormParams.AddrSize; }
+
+  /// Return size of reference.
+  uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); }
+
+  /// Return format of the Dwarf(DWARF32 or DWARF64).
+  /// TODO: DWARF64 is not currently supported.
+  dwarf::DwarfFormat getDwarfFormat() const { return FormParams.Format; }
+
+  /// Unique id of the unit.
+  unsigned getUniqueID() const { return ID; }
+
+  /// Return language of this unit.
+  uint16_t getLanguage() const { return Language; }
+
+  /// Set size of this(newly generated) compile unit.
+  void setUnitSize(uint64_t UnitSize) { this->UnitSize = UnitSize; }
+
+  /// Returns size of this(newly generated) compile unit.
+  uint64_t getUnitSize() const { return UnitSize; }
+
+  /// Returns this unit name.
+  StringRef getUnitName() const { return UnitName; }
+
+  /// Return the DW_AT_LLVM_sysroot of the compile unit or an empty StringRef.
+  StringRef getSysRoot() { return SysRoot; }
+
+  /// Create a Die for this unit.
+  void setOutputDIE(DIE *UnitDie) { NewUnit = UnitDie; }
+
+  /// Return Die for this compile unit.
+  DIE *getOutputUnitDIE() const { return NewUnit; }
+
+  /// Return true if this compile unit is from Clang module.
+  bool isClangModule() const { return !ClangModuleName.empty(); }
+
+  /// Return Clang module name;
+  const std::string &getClangModuleName() const { return ClangModuleName; }
+
+  /// Returns generated file keeping debug tables for this compile unit.
+  OutTablesFileTy &getOutDwarfBits() { return OutDebugInfoBits; }
+
+  /// Erases generated file keeping debug tables for this compile unit.
+  void eraseDwarfBits() { OutDebugInfoBits = OutTablesFileTy(); }
+
+  MCSymbol *getLabelBegin() { return LabelBegin; }
+  void setLabelBegin(MCSymbol *S) { LabelBegin = S; }
+
+  /// Error reporting methods.
+  /// @{
+
+  void reportWarning(const Twine &Warning,
+                     const DWARFDie *Die = nullptr) const {
+    if (WarningHandler)
+      WarningHandler(Warning, getUnitName(), Die);
+  }
+  void reportWarning(Error Warning) const {
+    handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
+      if (WarningHandler)
+        WarningHandler(Info.message(), getUnitName(), nullptr);
+    });
+  }
+  /// @}
+
+  /// This structure keeps fields which would be used for creating accelerator
+  /// table.
+  struct AccelInfo {
+    AccelInfo(StringEntry *Name, const DIE *Die, bool SkipPubSection = false);
+    AccelInfo(StringEntry *Name, const DIE *Die, uint32_t QualifiedNameHash,
+              bool ObjCClassIsImplementation);
+
+    /// Name of the entry.
+    StringEntry *Name = nullptr;
+
+    /// Tag of the DIE this entry describes.
+    dwarf::Tag Tag = dwarf::DW_TAG_null;
+
+    /// Output offset of the DIE this entry describes.
+    uint64_t OutOffset = 0;
+
+    /// Hash of the fully qualified name.
+    uint32_t QualifiedNameHash = 0;
+
+    /// Emit this entry only in the apple_* sections.
+    bool SkipPubSection = false;
+
+    /// Is this an ObjC class implementation?
+    bool ObjcClassImplementation = false;
+
+    /// Cloned Die containing acceleration info.
+    const DIE *Die = nullptr;
+  };
+
+protected:
+  /// Unique ID for the unit.
+  unsigned ID = 0;
+
+  /// Properties of the unit.
+  dwarf::FormParams FormParams;
+
+  /// DIE for newly generated compile unit.
+  DIE *NewUnit = nullptr;
+
+  /// The DW_AT_language of this unit.
+  uint16_t Language = 0;
+
+  /// The name of this unit.
+  std::string UnitName;
+
+  /// The DW_AT_LLVM_sysroot of this unit.
+  std::string SysRoot;
+
+  /// If this is a Clang module, this holds the module's name.
+  std::string ClangModuleName;
+
+  uint64_t UnitSize = 0;
+
+  /// Elf file containg generated debug tables for this compile unit.
+  OutTablesFileTy OutDebugInfoBits;
+
+  /// Endiannes for this compile unit.
+  support::endianness Endianess = support::endianness::little;
+
+  MCSymbol *LabelBegin = nullptr;
+
+  /// true if current unit references_to/is_referenced by other unit.
+  std::atomic<bool> IsInterconnectedCU = {false};
+
+  UnitMessageHandlerTy WarningHandler;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
diff --git a/lib/DWARFLinkerParallel/OutputSections.cpp b/lib/DWARFLinkerParallel/OutputSections.cpp
new file mode 100644
index 0000000..69c5bfa
--- /dev/null
+++ b/lib/DWARFLinkerParallel/OutputSections.cpp
@@ -0,0 +1,36 @@
+//=== OutputSections.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 "OutputSections.h"
+#include "llvm/ADT/StringSwitch.h"
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+std::optional<OutputSections::DebugSectionKind>
+OutputSections::parseDebugSectionName(llvm::StringRef SecName) {
+  return llvm::StringSwitch<std::optional<OutputSections::DebugSectionKind>>(
+             SecName)
+      .Case("debug_info", DebugSectionKind::DebugInfo)
+      .Case("debug_line", DebugSectionKind::DebugLine)
+      .Case("debug_frame", DebugSectionKind::DebugFrame)
+      .Case("debug_ranges", DebugSectionKind::DebugRange)
+      .Case("debug_rnglists", DebugSectionKind::DebugRngLists)
+      .Case("debug_loc", DebugSectionKind::DebugLoc)
+      .Case("debug_loclists", DebugSectionKind::DebugLocLists)
+      .Case("debug_aranges", DebugSectionKind::DebugARanges)
+      .Case("debug_abbrev", DebugSectionKind::DebugAbbrev)
+      .Case("debug_macinfo", DebugSectionKind::DebugMacinfo)
+      .Case("debug_macro", DebugSectionKind::DebugMacro)
+      .Default(std::nullopt);
+
+  return std::nullopt;
+}
+
+} // end of namespace dwarflinker_parallel
+} // end of namespace llvm
diff --git a/lib/DWARFLinkerParallel/OutputSections.h b/lib/DWARFLinkerParallel/OutputSections.h
new file mode 100644
index 0000000..15ab4cc
--- /dev/null
+++ b/lib/DWARFLinkerParallel/OutputSections.h
@@ -0,0 +1,67 @@
+//===- OutputSections.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_OUTPUTSECTIONS_H
+#define LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
+
+#include "llvm/ADT/StringRef.h"
+#include <array>
+#include <cstdint>
+
+namespace llvm {
+namespace dwarflinker_parallel {
+
+/// This class keeps offsets to the debug sections. Any object which is
+/// supposed to be emitted into the debug section should use this class to
+/// track debug sections offsets.
+class OutputSections {
+public:
+  /// List of tracked debug sections.
+  enum class DebugSectionKind : uint8_t {
+    DebugInfo = 0,
+    DebugLine,
+    DebugFrame,
+    DebugRange,
+    DebugRngLists,
+    DebugLoc,
+    DebugLocLists,
+    DebugARanges,
+    DebugAbbrev,
+    DebugMacinfo,
+    DebugMacro,
+  };
+  constexpr static size_t SectionKindsNum = 11;
+
+  /// Recognise the section name and match it with the DebugSectionKind.
+  static std::optional<DebugSectionKind> parseDebugSectionName(StringRef Name);
+
+  /// When objects(f.e. compile units) are glued into the single file,
+  /// the debug sections corresponding to the concrete object are assigned
+  /// with offsets inside the whole file. This method returns offset
+  /// to the \p SectionKind debug section, corresponding to this object.
+  uint64_t getStartOffset(DebugSectionKind SectionKind) const {
+    return Offsets[static_cast<
+        typename std::underlying_type<DebugSectionKind>::type>(SectionKind)];
+  }
+
+  /// Set offset to the start of specified \p SectionKind debug section,
+  /// corresponding to this object.
+  void setStartOffset(DebugSectionKind SectionKind, uint64_t Offset) {
+    Offsets[static_cast<typename std::underlying_type<DebugSectionKind>::type>(
+        SectionKind)] = Offset;
+  }
+
+protected:
+  /// Offsets to the debug sections composing this object.
+  std::array<uint64_t, SectionKindsNum> Offsets = {0};
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
diff --git a/test/tools/dsymutil/X86/DWARFLinkerParallel/basic-linking-x86.test b/test/tools/dsymutil/X86/DWARFLinkerParallel/basic-linking-x86.test
new file mode 100644
index 0000000..a9dcc76
--- /dev/null
+++ b/test/tools/dsymutil/X86/DWARFLinkerParallel/basic-linking-x86.test
@@ -0,0 +1,4 @@
+RUN: cat %p/../../Inputs/basic.macho.x86_64 > %t1
+RUN: dsymutil --linker llvm -accelerator=Pub -f -oso-prepend-path=%p/../.. %t1 2>&1 | FileCheck %s --allow-empty
+
+#CHECK: LLVM parallel dwarflinker is not implemented yet.
diff --git a/test/tools/llvm-dwarfutil/ELF/X86/DWARFLinkerParallel/gc-default.test b/test/tools/llvm-dwarfutil/ELF/X86/DWARFLinkerParallel/gc-default.test
new file mode 100644
index 0000000..5083fd5
--- /dev/null
+++ b/test/tools/llvm-dwarfutil/ELF/X86/DWARFLinkerParallel/gc-default.test
@@ -0,0 +1,134 @@
+## This test checks that debug info related to deleted code (marked with
+## default tombstone value) is removed.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: llvm-dwarfutil --linker llvm %t.o %t1.out 2>&1 | FileCheck %s --allow-empty
+
+#CHECK: LLVM parallel dwarflinker is not implemented yet.
+
+--- !ELF
+FileHeader:
+  Class:    ELFCLASS64
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    Size:            0x1b
+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
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addr
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+      - 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_ref4
+          - 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_ref4
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+  debug_info:
+    - Version: 4
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+            - Value:  0x1000
+            - Value:  0x1b
+        - AbbrCode: 3
+          Values:
+            - CStr: class1
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000006c
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 3
+          Values:
+            - CStr: class2
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000006c
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 3
+          Values:
+            - CStr: class3
+        - AbbrCode: 4
+          Values:
+            - Value:  0x0000006c
+            - CStr: member1
+        - AbbrCode: 0
+        - AbbrCode: 8
+          Values:
+            - CStr: int
+        - AbbrCode: 2
+          Values:
+            - CStr: foo1
+            - Value:  0x1000
+            - Value:  0x10
+            - Value:  0x0000002a
+        - AbbrCode: 2
+          Values:
+            - CStr: foo2
+            - Value:  0x0
+            - Value:  0x100
+            - Value:  0x00000040
+        - AbbrCode: 0
+...
diff --git a/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test b/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
index 4cac7c5..b364a75 100644
--- a/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
+++ b/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test
@@ -5,6 +5,8 @@
 
 # RUN: llvm-dwarfutil %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 --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
diff --git a/tools/dsymutil/CMakeLists.txt b/tools/dsymutil/CMakeLists.txt
index d2f964ef..3cb88a5 100644
--- a/tools/dsymutil/CMakeLists.txt
+++ b/tools/dsymutil/CMakeLists.txt
@@ -10,6 +10,7 @@
   CodeGen
   CodeGenTypes
   DWARFLinker
+  DWARFLinkerParallel
   DebugInfoDWARF
   MC
   Object
diff --git a/tools/dsymutil/DwarfLinkerForBinary.cpp b/tools/dsymutil/DwarfLinkerForBinary.cpp
index cf772e5..5331eab 100644
--- a/tools/dsymutil/DwarfLinkerForBinary.cpp
+++ b/tools/dsymutil/DwarfLinkerForBinary.cpp
@@ -33,6 +33,7 @@
 #include "llvm/CodeGen/NonRelocatableStringpool.h"
 #include "llvm/Config/config.h"
 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
+#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
@@ -134,22 +135,6 @@
   dumpDIE(DIE, Options.Verbose);
 }
 
-bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple,
-                                          raw_fd_ostream &OutFile) {
-  if (Options.NoOutput)
-    return true;
-
-  Streamer = std::make_unique<DwarfStreamer>(
-      Options.FileType, OutFile, Options.Translator,
-      [&](const Twine &Error, StringRef Context, const DWARFDie *) {
-        reportError(Error, Context);
-      },
-      [&](const Twine &Warning, StringRef Context, const DWARFDie *) {
-        reportWarning(Warning, Context);
-      });
-  return Streamer->init(TheTriple, "__DWARF");
-}
-
 ErrorOr<const object::ObjectFile &>
 DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
                                  const Triple &Triple) {
@@ -238,22 +223,19 @@
   return Error::success();
 }
 
-ErrorOr<DWARFFile &>
+template <typename OutDWARFFile, typename AddressesMap>
+ErrorOr<std::unique_ptr<OutDWARFFile>>
 DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
                                  const DebugMap &DebugMap,
                                  remarks::RemarkLinker &RL) {
   auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
+  std::unique_ptr<OutDWARFFile> Res;
 
   if (ErrorOrObj) {
-    ContextForLinking.push_back(
-        std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
-    AddressMapForLinking.push_back(
-        std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
-
-    ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
-        Obj.getObjectFilename(), ContextForLinking.back().get(),
-        AddressMapForLinking.back().get(),
-        Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
+    Res = std::make_unique<OutDWARFFile>(
+        Obj.getObjectFilename(), DWARFContext::create(*ErrorOrObj),
+        std::make_unique<AddressesMap>(*this, *ErrorOrObj, Obj),
+        Obj.empty() ? Obj.getWarnings() : EmptyWarnings);
 
     Error E = RL.link(*ErrorOrObj);
     if (Error NewE = handleErrors(
@@ -262,7 +244,7 @@
             }))
       return errorToErrorCode(std::move(NewE));
 
-    return *ObjectsForLinking.back();
+    return Res;
   }
 
   return ErrorOrObj.getError();
@@ -274,7 +256,7 @@
   // need to copy them to the .dSYM. Only copy them for binaries where the
   // linker omitted the reflection metadata.
   if (!Map.getBinaryPath().empty() &&
-      Options.FileType == OutputFileType::Object) {
+      Options.FileType == DWARFLinker::OutputFileType::Object) {
 
     auto ObjectEntry = BinHolder.getObjectEntry(Map.getBinaryPath());
     // If ObjectEntry or Object has an error, no binary exists, therefore no
@@ -498,8 +480,9 @@
   return Error::success();
 }
 
+template <typename OutStreamer>
 void DwarfLinkerForBinary::copySwiftReflectionMetadata(
-    const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
+    const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
     std::vector<uint64_t> &SectionToOffsetInDwarf,
     std::vector<MachOUtils::DwarfRelocationApplicationInfo>
         &RelocationsToApply) {
@@ -557,59 +540,117 @@
 }
 
 bool DwarfLinkerForBinary::link(const DebugMap &Map) {
-  if (!createStreamer(Map.getTriple(), OutFile))
-    return false;
+  if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::LLVM) {
+    dwarflinker_parallel::DWARFLinker::OutputFileType DWARFLinkerOutputType;
+    switch (Options.FileType) {
+    case DWARFLinker::OutputFileType::Object:
+      DWARFLinkerOutputType =
+          dwarflinker_parallel::DWARFLinker::OutputFileType::Object;
+      break;
 
-  ObjectsForLinking.clear();
-  ContextForLinking.clear();
-  AddressMapForLinking.clear();
+    case DWARFLinker::OutputFileType::Assembly:
+      DWARFLinkerOutputType =
+          dwarflinker_parallel::DWARFLinker::OutputFileType::Assembly;
+      break;
+    }
+
+    return linkImpl<dwarflinker_parallel::DWARFLinker,
+                    dwarflinker_parallel::DWARFFile,
+                    AddressManager<dwarflinker_parallel::AddressesMap>>(
+        Map, DWARFLinkerOutputType);
+  }
+
+  return linkImpl<DWARFLinker, DWARFFile, AddressManager<AddressesMap>>(
+      Map, Options.FileType);
+}
+
+template <typename Linker>
+void setAcceleratorTables(Linker &GeneralLinker,
+                          DsymutilAccelTableKind TableKind,
+                          uint16_t MaxDWARFVersion) {
+  switch (TableKind) {
+  case DsymutilAccelTableKind::Apple:
+    GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
+    return;
+  case DsymutilAccelTableKind::Dwarf:
+    GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
+    return;
+  case DsymutilAccelTableKind::Pub:
+    GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Pub);
+    return;
+  case DsymutilAccelTableKind::Default:
+    if (MaxDWARFVersion >= 5)
+      GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
+    else
+      GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
+    return;
+  case DsymutilAccelTableKind::None:
+    // Nothing to do.
+    return;
+  }
+
+  llvm_unreachable("All cases handled above!");
+}
+
+template <typename Linker, typename OutDwarfFile, typename AddressMap>
+bool DwarfLinkerForBinary::linkImpl(
+    const DebugMap &Map, typename Linker::OutputFileType ObjectType) {
+
+  std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking;
 
   DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
 
-  DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
-
-  remarks::RemarkLinker RL;
-  if (!Options.RemarksPrependPath.empty())
-    RL.setExternalFilePrependPath(Options.RemarksPrependPath);
-  RL.setKeepAllRemarks(Options.RemarksKeepAll);
-  GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap);
-
   std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
     assert(Options.Translator);
     return Options.Translator(Input);
   };
 
-  GeneralLinker.setVerbosity(Options.Verbose);
-  GeneralLinker.setStatistics(Options.Statistics);
-  GeneralLinker.setVerifyInputDWARF(Options.VerifyInputDWARF);
-  GeneralLinker.setNoOutput(Options.NoOutput);
-  GeneralLinker.setNoODR(Options.NoODR);
-  GeneralLinker.setUpdate(Options.Update);
-  GeneralLinker.setNumThreads(Options.Threads);
-  GeneralLinker.setPrependPath(Options.PrependPath);
-  GeneralLinker.setKeepFunctionForStatic(Options.KeepFunctionForStatic);
-  if (Options.Translator)
-    GeneralLinker.setStringsTranslator(TranslationLambda);
-  GeneralLinker.setWarningHandler(
-      [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
-        reportWarning(Warning, Context, DIE);
-      });
-  GeneralLinker.setErrorHandler(
+  std::unique_ptr<Linker> GeneralLinker = Linker::createLinker(
       [&](const Twine &Error, StringRef Context, const DWARFDie *DIE) {
         reportError(Error, Context, DIE);
+      },
+      [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
+        reportWarning(Warning, Context, DIE);
+      },
+      Options.Translator ? TranslationLambda : nullptr);
+
+  if (!Options.NoOutput) {
+    if (Error Err = GeneralLinker->createEmitter(Map.getTriple(), ObjectType,
+                                                 OutFile)) {
+      handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+        reportError(EI.message(), "dwarf streamer init");
       });
-  GeneralLinker.setInputVerificationHandler([&](const DWARFFile &File) {
+      return false;
+    }
+  }
+
+  remarks::RemarkLinker RL;
+  if (!Options.RemarksPrependPath.empty())
+    RL.setExternalFilePrependPath(Options.RemarksPrependPath);
+  RL.setKeepAllRemarks(Options.RemarksKeepAll);
+  GeneralLinker->setObjectPrefixMap(&Options.ObjectPrefixMap);
+
+  GeneralLinker->setVerbosity(Options.Verbose);
+  GeneralLinker->setStatistics(Options.Statistics);
+  GeneralLinker->setVerifyInputDWARF(Options.VerifyInputDWARF);
+  GeneralLinker->setNoODR(Options.NoODR);
+  GeneralLinker->setUpdateIndexTablesOnly(Options.Update);
+  GeneralLinker->setNumThreads(Options.Threads);
+  GeneralLinker->setPrependPath(Options.PrependPath);
+  GeneralLinker->setKeepFunctionForStatic(Options.KeepFunctionForStatic);
+  GeneralLinker->setInputVerificationHandler([&](const OutDwarfFile &File) {
     reportWarning("input verification failed", File.FileName);
     HasVerificationErrors = true;
   });
-  objFileLoader Loader = [&DebugMap, &RL,
-                          this](StringRef ContainerName,
-                                StringRef Path) -> ErrorOr<DWARFFile &> {
+  auto Loader = [&](StringRef ContainerName,
+                    StringRef Path) -> ErrorOr<OutDwarfFile &> {
     auto &Obj = DebugMap.addDebugMapObject(
         Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
 
-    if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
-      return *ErrorOrObj;
+    if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
+            loadObject<OutDwarfFile, AddressMap>(Obj, DebugMap, RL)) {
+      ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
+      return *ObjectsForLinking.back();
     } else {
       // Try and emit more helpful warnings by applying some heuristics.
       StringRef ObjFile = ContainerName;
@@ -654,7 +695,7 @@
 
     llvm_unreachable("Unhandled DebugMap object");
   };
-  GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
+  GeneralLinker->setSwiftInterfacesMap(&ParseableSwiftInterfaces);
   bool ReflectionSectionsPresentInBinary = false;
   // If there is no output specified, no point in checking the binary for swift5
   // reflection sections.
@@ -668,7 +709,7 @@
     auto SectionToOffsetInDwarf =
         calculateStartOfStrippableReflectionSections(Map);
     for (const auto &Obj : Map.objects())
-      copySwiftReflectionMetadata(Obj.get(), Streamer.get(),
+      copySwiftReflectionMetadata(Obj.get(), GeneralLinker->getEmitter(),
                                   SectionToOffsetInDwarf, RelocationsToApply);
   }
 
@@ -715,18 +756,21 @@
 
       // Copy the module into the .swift_ast section.
       if (!Options.NoOutput)
-        Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
+        GeneralLinker->getEmitter()->emitSwiftAST((*ErrorOrMem)->getBuffer());
 
       continue;
     }
 
-    if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
-      GeneralLinker.addObjectFile(*ErrorOrObj, Loader, OnCUDieLoaded);
-    else {
-      ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
+    if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
+            loadObject<OutDwarfFile, AddressMap>(*Obj, Map, RL)) {
+      ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
+      GeneralLinker->addObjectFile(*ObjectsForLinking.back(), Loader,
+                                   OnCUDieLoaded);
+    } else {
+      ObjectsForLinking.push_back(std::make_unique<OutDwarfFile>(
           Obj->getObjectFilename(), nullptr, nullptr,
           Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
-      GeneralLinker.addObjectFile(*ObjectsForLinking.back());
+      GeneralLinker->addObjectFile(*ObjectsForLinking.back());
     }
   }
 
@@ -734,32 +778,14 @@
   if (MaxDWARFVersion == 0)
     MaxDWARFVersion = 3;
 
-  if (Error E = GeneralLinker.setTargetDWARFVersion(MaxDWARFVersion))
+  if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))
     return error(toString(std::move(E)));
 
-  switch (Options.TheAccelTableKind) {
-  case DsymutilAccelTableKind::Apple:
-    GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple);
-    break;
-  case DsymutilAccelTableKind::Dwarf:
-    GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames);
-    break;
-  case DsymutilAccelTableKind::Pub:
-    GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Pub);
-    break;
-  case DsymutilAccelTableKind::Default:
-    if (MaxDWARFVersion >= 5)
-      GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames);
-    else
-      GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple);
-    break;
-  case DsymutilAccelTableKind::None:
-    // Nothing to do.
-    break;
-  }
+  setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,
+                               MaxDWARFVersion);
 
   // link debug info for loaded object files.
-  if (Error E = GeneralLinker.link())
+  if (Error E = GeneralLinker->link())
     return error(toString(std::move(E)));
 
   StringRef ArchName = Map.getTriple().getArchName();
@@ -776,21 +802,25 @@
   }
 
   if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
-      Options.FileType == OutputFileType::Object)
+      ObjectType == Linker::OutputFileType::Object)
     return MachOUtils::generateDsymCompanion(
         Options.VFS, Map, Options.Translator,
-        *Streamer->getAsmPrinter().OutStreamer, OutFile, RelocationsToApply);
+        *GeneralLinker->getEmitter()->getAsmPrinter().OutStreamer, OutFile,
+        RelocationsToApply);
 
-  Streamer->finish();
+  GeneralLinker->getEmitter()->finish();
   return true;
 }
 
 /// Iterate over the relocations of the given \p Section and
 /// store the ones that correspond to debug map entries into the
 /// ValidRelocs array.
-void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
-    const object::SectionRef &Section, const object::MachOObjectFile &Obj,
-    const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
+template <typename AddressesMapBase>
+void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
+    findValidRelocsMachO(const object::SectionRef &Section,
+                         const object::MachOObjectFile &Obj,
+                         const DebugMapObject &DMO,
+                         std::vector<ValidReloc> &ValidRelocs) {
   Expected<StringRef> ContentsOrErr = Section.getContents();
   if (!ContentsOrErr) {
     consumeError(ContentsOrErr.takeError());
@@ -865,7 +895,8 @@
 
 /// Dispatch the valid relocation finding logic to the
 /// appropriate handler depending on the object file format.
-bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
+template <typename AddressesMapBase>
+bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::findValidRelocs(
     const object::SectionRef &Section, const object::ObjectFile &Obj,
     const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
   // Dispatch to the right handler depending on the file type.
@@ -890,8 +921,10 @@
 /// entries in the debug map. These relocations will drive the Dwarf link by
 /// indicating which DIEs refer to symbols present in the linked binary.
 /// \returns whether there are any valid relocations in the debug info.
-bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
-    const object::ObjectFile &Obj, const DebugMapObject &DMO) {
+template <typename AddressesMapBase>
+bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
+    findValidRelocsInDebugSections(const object::ObjectFile &Obj,
+                                   const DebugMapObject &DMO) {
   // Find the debug_info section.
   bool FoundValidRelocs = false;
   for (const object::SectionRef &Section : Obj.sections()) {
@@ -912,10 +945,14 @@
   return FoundValidRelocs;
 }
 
-std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc>
-DwarfLinkerForBinary::AddressManager::getRelocations(
+template <typename AddressesMapBase>
+std::vector<
+    typename DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
+DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocations(
     const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
-  std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc> Res;
+  std::vector<
+      DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
+      Res;
 
   auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
     return Reloc.Offset < StartPos;
@@ -930,7 +967,9 @@
   return Res;
 }
 
-void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {
+template <typename AddressesMapBase>
+void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::printReloc(
+    const ValidReloc &Reloc) {
   const auto &Mapping = Reloc.Mapping->getValue();
   const uint64_t ObjectAddress = Mapping.ObjectAddress
                                      ? uint64_t(*Mapping.ObjectAddress)
@@ -941,16 +980,18 @@
                    uint64_t(Mapping.BinaryAddress));
 }
 
-int64_t
-DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) {
+template <typename AddressesMapBase>
+int64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocValue(
+    const ValidReloc &Reloc) {
   int64_t AddrAdjust = relocate(Reloc);
   if (Reloc.Mapping->getValue().ObjectAddress)
     AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
   return AddrAdjust;
 }
 
+template <typename AddressesMapBase>
 std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
+DwarfLinkerForBinary::AddressManager<AddressesMapBase>::hasValidRelocationAt(
     const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
     uint64_t EndOffset) {
   std::vector<ValidReloc> Relocs =
@@ -986,10 +1027,11 @@
   return std::make_pair(Offset, End);
 }
 
-std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
-    DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
-    uint64_t EndOffset) {
+template <typename AddressesMapBase>
+std::optional<int64_t> DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
+    getExprOpAddressRelocAdjustment(DWARFUnit &U,
+                                    const DWARFExpression::Operation &Op,
+                                    uint64_t StartOffset, uint64_t EndOffset) {
   switch (Op.getCode()) {
   default: {
     assert(false && "Specified operation does not have address operand");
@@ -1010,9 +1052,9 @@
   return std::nullopt;
 }
 
-std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
-    const DWARFDie &DIE) {
+template <typename AddressesMapBase>
+std::optional<int64_t> DwarfLinkerForBinary::AddressManager<
+    AddressesMapBase>::getSubprogramRelocAdjustment(const DWARFDie &DIE) {
   const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
 
   std::optional<uint32_t> LowPcIdx =
@@ -1053,8 +1095,9 @@
   }
 }
 
-uint64_t
-DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
+template <typename AddressesMapBase>
+uint64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::relocate(
+    const ValidReloc &Reloc) const {
   return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
 }
 
@@ -1066,7 +1109,8 @@
 /// monotonic \p BaseOffset values.
 ///
 /// \returns whether any reloc has been applied.
-bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
+template <typename AddressesMapBase>
+bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::applyValidRelocs(
     MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
   std::vector<ValidReloc> Relocs = getRelocations(
       ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
diff --git a/tools/dsymutil/DwarfLinkerForBinary.h b/tools/dsymutil/DwarfLinkerForBinary.h
index 8b967f9..61737be 100644
--- a/tools/dsymutil/DwarfLinkerForBinary.h
+++ b/tools/dsymutil/DwarfLinkerForBinary.h
@@ -65,7 +65,8 @@
 private:
 
   /// Keeps track of relocations.
-  class AddressManager : public AddressesMap {
+  template <typename AddressesMapBase>
+  class AddressManager : public AddressesMapBase {
     struct ValidReloc {
       uint64_t Offset;
       uint32_t Size;
@@ -180,6 +181,7 @@
     std::optional<int64_t> getExprOpAddressRelocAdjustment(
         DWARFUnit &U, const DWARFExpression::Operation &Op,
         uint64_t StartOffset, uint64_t EndOffset) override;
+
     std::optional<int64_t>
     getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
 
@@ -199,14 +201,20 @@
   /// \defgroup Helpers Various helper methods.
   ///
   /// @{
-  bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
+  template <typename OutStreamer>
+  bool createStreamer(const Triple &TheTriple,
+                      typename OutStreamer::OutputFileType FileType,
+                      std::unique_ptr<OutStreamer> &Streamer,
+                      raw_fd_ostream &OutFile);
 
   /// Attempt to load a debug object from disk.
   ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
                                                  const Triple &triple);
-  ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj,
-                                  const DebugMap &DebugMap,
-                                  remarks::RemarkLinker &RL);
+
+  template <typename OutDWARFFile, typename AddressesMap>
+  ErrorOr<std::unique_ptr<OutDWARFFile>> loadObject(const DebugMapObject &Obj,
+                                                    const DebugMap &DebugMap,
+                                                    remarks::RemarkLinker &RL);
 
   void collectRelocationsToApplyToSwiftReflectionSections(
       const object::SectionRef &Section, StringRef &Contents,
@@ -218,21 +226,22 @@
 
   Error copySwiftInterfaces(StringRef Architecture) const;
 
+  template <typename OutStreamer>
   void copySwiftReflectionMetadata(
-      const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
+      const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
       std::vector<uint64_t> &SectionToOffsetInDwarf,
       std::vector<MachOUtils::DwarfRelocationApplicationInfo>
           &RelocationsToApply);
 
+  template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
+  bool linkImpl(const DebugMap &Map,
+                typename Linker::OutputFileType ObjectType);
+
   raw_fd_ostream &OutFile;
   BinaryHolder &BinHolder;
   LinkOptions Options;
   std::mutex &ErrorHandlerMutex;
 
-  std::unique_ptr<DwarfStreamer> Streamer;
-  std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking;
-  std::vector<std::unique_ptr<DWARFContext>> ContextForLinking;
-  std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking;
   std::vector<std::string> EmptyWarnings;
 
   /// A list of all .swiftinterface files referenced by the debug
diff --git a/tools/dsymutil/LinkUtils.h b/tools/dsymutil/LinkUtils.h
index 9d25190..88c17d5 100644
--- a/tools/dsymutil/LinkUtils.h
+++ b/tools/dsymutil/LinkUtils.h
@@ -31,6 +31,11 @@
   Pub,     ///< .debug_pubnames, .debug_pubtypes
 };
 
+enum class DsymutilDWARFLinkerType : uint8_t {
+  Apple, /// Apple`s implementation of DWARFLinker.
+  LLVM   /// LLVM implementation of DWARFLinker.
+};
+
 struct LinkOptions {
   /// Verbosity
   bool Verbose = false;
@@ -57,6 +62,9 @@
   /// function.
   bool KeepFunctionForStatic = false;
 
+  /// Type of DWARFLinker to use.
+  DsymutilDWARFLinkerType DWARFLinkerType = DsymutilDWARFLinkerType::Apple;
+
   /// Use a 64-bit header when emitting universal binaries.
   bool Fat64 = false;
 
@@ -64,7 +72,7 @@
   unsigned Threads = 1;
 
   // Output file type.
-  OutputFileType FileType = OutputFileType::Object;
+  DWARFLinker::OutputFileType FileType = DWARFLinker::OutputFileType::Object;
 
   /// The accelerator table kind
   DsymutilAccelTableKind TheAccelTableKind;
diff --git a/tools/dsymutil/Options.td b/tools/dsymutil/Options.td
index 57d117b..9b0b31b 100644
--- a/tools/dsymutil/Options.td
+++ b/tools/dsymutil/Options.td
@@ -199,3 +199,9 @@
   HelpText<"Drop remarks without valid debug locations. Without this flags, "
            "all remarks are kept.">,
   Group<grp_general>;
+
+def linker: Separate<["--", "-"], "linker">,
+  MetaVarName<"<DWARF linker type>">,
+  HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">,
+  Group<grp_general>;
+def: Joined<["--", "-"], "linker=">, Alias<linker>;
diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp
index 9bd0bc6..5a8d219 100644
--- a/tools/dsymutil/dsymutil.cpp
+++ b/tools/dsymutil/dsymutil.cpp
@@ -241,6 +241,24 @@
   return DsymutilAccelTableKind::Default;
 }
 
+static Expected<DsymutilDWARFLinkerType>
+getDWARFLinkerType(opt::InputArgList &Args) {
+  if (opt::Arg *LinkerType = Args.getLastArg(OPT_linker)) {
+    StringRef S = LinkerType->getValue();
+    if (S == "apple")
+      return DsymutilDWARFLinkerType::Apple;
+    if (S == "llvm")
+      return DsymutilDWARFLinkerType::LLVM;
+    return make_error<StringError>("invalid DWARF linker type specified: '" +
+                                       S +
+                                       "'. Supported values are 'apple', "
+                                       "'llvm'.",
+                                   inconvertibleErrorCode());
+  }
+
+  return DsymutilDWARFLinkerType::Apple;
+}
+
 static Expected<ReproducerMode> getReproducerMode(opt::InputArgList &Args) {
   if (Args.hasArg(OPT_gen_reproducer))
     return ReproducerMode::GenerateOnExit;
@@ -330,6 +348,13 @@
     return AccelKind.takeError();
   }
 
+  if (Expected<DsymutilDWARFLinkerType> DWARFLinkerType =
+          getDWARFLinkerType(Args)) {
+    Options.LinkOpts.DWARFLinkerType = *DWARFLinkerType;
+  } else {
+    return DWARFLinkerType.takeError();
+  }
+
   if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
     Options.SymbolMap = SymbolMap->getValue();
 
@@ -362,7 +387,7 @@
     Options.Toolchain = Toolchain->getValue();
 
   if (Args.hasArg(OPT_assembly))
-    Options.LinkOpts.FileType = OutputFileType::Assembly;
+    Options.LinkOpts.FileType = DWARFLinker::OutputFileType::Assembly;
 
   if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
     Options.LinkOpts.Threads = atoi(NumThreads->getValue());
diff --git a/tools/llvm-dwarfutil/CMakeLists.txt b/tools/llvm-dwarfutil/CMakeLists.txt
index 40e09af..b258579 100644
--- a/tools/llvm-dwarfutil/CMakeLists.txt
+++ b/tools/llvm-dwarfutil/CMakeLists.txt
@@ -8,6 +8,7 @@
   AllTargetsInfos
   CodeGenTypes
   DWARFLinker
+  DWARFLinkerParallel
   DebugInfoDWARF
   MC
   ObjCopy
diff --git a/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/tools/llvm-dwarfutil/DebugInfoLinker.cpp
index b36c57a..b4f3c5a 100644
--- a/tools/llvm-dwarfutil/DebugInfoLinker.cpp
+++ b/tools/llvm-dwarfutil/DebugInfoLinker.cpp
@@ -11,6 +11,7 @@
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/DWARFLinker/DWARFLinker.h"
 #include "llvm/DWARFLinker/DWARFStreamer.h"
+#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include "llvm/Object/ObjectFile.h"
@@ -37,7 +38,8 @@
 // exec: [LowPC, HighPC] is not inside address ranges of .text sections
 //
 // universal: maxpc and bfd
-class ObjFileAddressMap : public AddressesMap {
+template <typename AddressMapBase>
+class ObjFileAddressMap : public AddressMapBase {
 public:
   ObjFileAddressMap(DWARFContext &Context, const Options &Options,
                     object::ObjectFile &ObjFile)
@@ -224,12 +226,13 @@
       .Default(false);
 }
 
-static std::optional<DwarfLinkerAccelTableKind>
+template <typename AccelTableKind>
+static std::optional<AccelTableKind>
 getAcceleratorTableKind(StringRef SecName) {
-  return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName)
-      .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub)
-      .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub)
-      .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames)
+  return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
+      .Case(".debug_pubnames", AccelTableKind::Pub)
+      .Case(".debug_pubtypes", AccelTableKind::Pub)
+      .Case(".debug_names", AccelTableKind::DebugNames)
       .Default(std::nullopt);
 }
 
@@ -275,9 +278,9 @@
   return Message;
 }
 
-Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
-                    raw_pwrite_stream &OutStream) {
-
+template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
+Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
+                        raw_pwrite_stream &OutStream) {
   auto ReportWarn = [&](const Twine &Message, StringRef Context,
                         const DWARFDie *Die) {
     warning(Message, Context);
@@ -297,39 +300,33 @@
     WithColor::error(errs(), Context) << Message << '\n';
   };
 
-  // Create output streamer.
-  DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
-                            ReportWarn, ReportWarn);
-  Triple TargetTriple = File.makeTriple();
-  if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}",
-                                              TargetTriple.getTriple())
-                                          .str()))
-    return createStringError(std::errc::invalid_argument, "");
-
-  std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
-
   // Create DWARF linker.
-  DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
+  std::unique_ptr<Linker> DebugInfoLinker =
+      Linker::createLinker(ReportErr, ReportWarn);
 
-  DebugInfoLinker.setEstimatedObjfilesAmount(1);
-  DebugInfoLinker.setErrorHandler(ReportErr);
-  DebugInfoLinker.setWarningHandler(ReportWarn);
-  DebugInfoLinker.setNumThreads(Options.NumThreads);
-  DebugInfoLinker.setNoODR(!Options.DoODRDeduplication);
-  DebugInfoLinker.setVerbosity(Options.Verbose);
-  DebugInfoLinker.setUpdate(!Options.DoGarbageCollection);
+  Triple TargetTriple = File.makeTriple();
+  if (Error Err = DebugInfoLinker->createEmitter(
+          TargetTriple, Linker::OutputFileType::Object, OutStream))
+    return Err;
 
-  std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
-  std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
+  DebugInfoLinker->setEstimatedObjfilesAmount(1);
+  DebugInfoLinker->setNumThreads(Options.NumThreads);
+  DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
+  DebugInfoLinker->setVerbosity(Options.Verbose);
+  DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
+
+  std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1);
   std::vector<std::string> EmptyWarnings;
 
   // Add object files to the DWARFLinker.
-  AddresssMapForLinking[0] =
-      std::make_unique<ObjFileAddressMap>(*Context, Options, File);
+  std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
+  std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap(
+      std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options,
+                                                          File));
 
-  ObjectsForLinking[0] = std::make_unique<DWARFFile>(
-      File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
-      EmptyWarnings);
+  ObjectsForLinking[0] =
+      std::make_unique<OutDwarfFile>(File.getFileName(), std::move(Context),
+                                     std::move(AddressesMap), EmptyWarnings);
 
   uint16_t MaxDWARFVersion = 0;
   std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
@@ -338,17 +335,17 @@
       };
 
   for (size_t I = 0; I < ObjectsForLinking.size(); I++)
-    DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr,
-                                  OnCUDieLoaded);
+    DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
+                                   OnCUDieLoaded);
 
   // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
   if (MaxDWARFVersion == 0)
     MaxDWARFVersion = 3;
 
-  if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion))
+  if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
     return Err;
 
-  SmallVector<DwarfLinkerAccelTableKind> AccelTables;
+  SmallVector<typename Linker::AccelTableKind> AccelTables;
 
   switch (Options.AccelTableKind) {
   case DwarfUtilAccelKind::None:
@@ -356,60 +353,75 @@
     break;
   case DwarfUtilAccelKind::DWARF:
     // use .debug_names for all DWARF versions.
-    AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames);
+    AccelTables.push_back(Linker::AccelTableKind::DebugNames);
     break;
   }
 
   // Add accelerator tables to DWARFLinker.
-  for (DwarfLinkerAccelTableKind Table : AccelTables)
-    DebugInfoLinker.addAccelTableKind(Table);
+  for (typename Linker::AccelTableKind Table : AccelTables)
+    DebugInfoLinker->addAccelTableKind(Table);
 
-  SmallVector<StringRef> AccelTableNamesToReplace;
-  SmallVector<StringRef> AccelTableNamesToDelete;
+  for (std::unique_ptr<OutDwarfFile> &CurFile : ObjectsForLinking) {
+    SmallVector<StringRef> AccelTableNamesToReplace;
+    SmallVector<StringRef> AccelTableNamesToDelete;
 
-  // Unknown debug sections or non-requested accelerator sections would be
-  // removed. Display warning for such sections.
-  for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
-    if (isDebugSection(Sec.Name)) {
-      std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind =
-          getAcceleratorTableKind(Sec.Name);
+    // Unknown debug sections or non-requested accelerator sections would be
+    // removed. Display warning for such sections.
+    for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
+      if (isDebugSection(Sec.Name)) {
+        std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
+            getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
 
-      if (SrcAccelTableKind) {
-        assert(knownByDWARFUtil(Sec.Name));
+        if (SrcAccelTableKind) {
+          assert(knownByDWARFUtil(Sec.Name));
 
-        if (Options.AccelTableKind == DwarfUtilAccelKind::None)
-          AccelTableNamesToDelete.push_back(Sec.Name);
-        else if (std::find(AccelTables.begin(), AccelTables.end(),
-                           *SrcAccelTableKind) == AccelTables.end())
-          AccelTableNamesToReplace.push_back(Sec.Name);
-      } else if (!knownByDWARFUtil(Sec.Name)) {
-        assert(!SrcAccelTableKind);
-        warning(
-            formatv("'{0}' is not currently supported: section will be skipped",
-                    Sec.Name),
-            Options.InputFileName);
+          if (Options.AccelTableKind == DwarfUtilAccelKind::None)
+            AccelTableNamesToDelete.push_back(Sec.Name);
+          else if (std::find(AccelTables.begin(), AccelTables.end(),
+                             *SrcAccelTableKind) == AccelTables.end())
+            AccelTableNamesToReplace.push_back(Sec.Name);
+        } else if (!knownByDWARFUtil(Sec.Name)) {
+          assert(!SrcAccelTableKind);
+          warning(
+              formatv(
+                  "'{0}' is not currently supported: section will be skipped",
+                  Sec.Name),
+              Options.InputFileName);
+        }
       }
     }
+
+    // Display message for the replaced accelerator tables.
+    if (!AccelTableNamesToReplace.empty())
+      warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
+                                                     Options.AccelTableKind),
+              Options.InputFileName);
+
+    // Display message for the removed accelerator tables.
+    if (!AccelTableNamesToDelete.empty())
+      warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
+              Options.InputFileName);
   }
 
-  // Display message for the replaced accelerator tables.
-  if (!AccelTableNamesToReplace.empty())
-    warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
-                                                   Options.AccelTableKind),
-            Options.InputFileName);
-
-  // Display message for the removed accelerator tables.
-  if (!AccelTableNamesToDelete.empty())
-    warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
-            Options.InputFileName);
-
   // Link debug info.
-  if (Error Err = DebugInfoLinker.link())
+  if (Error Err = DebugInfoLinker->link())
     return Err;
 
-  OutStreamer.finish();
+  DebugInfoLinker->getEmitter()->finish();
   return Error::success();
 }
 
+Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
+                    raw_pwrite_stream &OutStream) {
+  if (Options.UseLLVMDWARFLinker)
+    return linkDebugInfoImpl<dwarflinker_parallel::DWARFLinker,
+                             dwarflinker_parallel::DWARFFile,
+                             dwarflinker_parallel::AddressesMap>(File, Options,
+                                                                 OutStream);
+  else
+    return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>(
+        File, Options, OutStream);
+}
+
 } // end of namespace dwarfutil
 } // end of namespace llvm
diff --git a/tools/llvm-dwarfutil/Options.h b/tools/llvm-dwarfutil/Options.h
index 38fa2b9..e97833b 100644
--- a/tools/llvm-dwarfutil/Options.h
+++ b/tools/llvm-dwarfutil/Options.h
@@ -40,6 +40,7 @@
   bool Verbose = false;
   int NumThreads = 0;
   bool Verify = false;
+  bool UseLLVMDWARFLinker = false;
   DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None;
 
   std::string getSeparateDebugFileName() const {
diff --git a/tools/llvm-dwarfutil/Options.td b/tools/llvm-dwarfutil/Options.td
index d454118..26b9ac6 100644
--- a/tools/llvm-dwarfutil/Options.td
+++ b/tools/llvm-dwarfutil/Options.td
@@ -20,6 +20,11 @@
   Alias<help>,
   HelpText<"Alias for --help">;
 
+def linker: Separate<["--", "-"], "linker">,
+  MetaVarName<"<DWARF linker type>">,
+  HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">;
+def: Joined<["--", "-"], "linker=">, Alias<linker>;
+
 defm odr_deduplication : BB<"odr-deduplication",
   "Do ODR deduplication for debug types(default)",
   "Don`t do ODR deduplication for debug types">;
diff --git a/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index 74b6104..1c76271 100644
--- a/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -123,6 +123,18 @@
           formatv("unknown tombstone value: '{0}'", S).str().c_str());
   }
 
+  if (opt::Arg *LinkerKind = Args.getLastArg(OPT_linker)) {
+    StringRef S = LinkerKind->getValue();
+    if (S == "apple")
+      Options.UseLLVMDWARFLinker = false;
+    else if (S == "llvm")
+      Options.UseLLVMDWARFLinker = true;
+    else
+      return createStringError(
+          std::errc::invalid_argument,
+          formatv("unknown linker kind value: '{0}'", S).str().c_str());
+  }
+
   if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
     StringRef S = BuildAccelerator->getValue();