[llvm] r278330 - Resolution-based LTO API.

Teresa Johnson via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 11 05:56:41 PDT 2016


Author: tejohnson
Date: Thu Aug 11 07:56:40 2016
New Revision: 278330

URL: http://llvm.org/viewvc/llvm-project?rev=278330&view=rev
Log:
Resolution-based LTO API.

Summary:
This introduces a resolution-based LTO API. The main advantage of this API over
existing APIs is that it allows the linker to supply a resolution for each
symbol in each object, rather than the combined object as a whole. This will
become increasingly important for use cases such as ThinLTO which require us
to process symbol resolutions in a more complicated way than just adjusting
linkage.

Patch by Peter Collingbourne.

Reviewers: rafael, tejohnson, mehdi_amini

Subscribers: lhames, tejohnson, mehdi_amini, llvm-commits

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

Address review comments

Added:
    llvm/trunk/include/llvm/LTO/Config.h
    llvm/trunk/include/llvm/LTO/LTOBackend.h
    llvm/trunk/lib/LTO/LTOBackend.cpp
    llvm/trunk/test/LTO/Resolution/
    llvm/trunk/test/LTO/Resolution/X86/
    llvm/trunk/test/LTO/Resolution/X86/Inputs/
    llvm/trunk/test/LTO/Resolution/X86/Inputs/alias-1.ll
    llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll
    llvm/trunk/test/LTO/Resolution/X86/alias.ll
    llvm/trunk/test/LTO/Resolution/X86/comdat.ll
      - copied, changed from r278309, llvm/trunk/test/tools/gold/X86/comdat.ll
    llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg
    llvm/trunk/test/tools/llvm-lto2/
    llvm/trunk/test/tools/llvm-lto2/errors.ll
    llvm/trunk/tools/llvm-lto2/
    llvm/trunk/tools/llvm-lto2/CMakeLists.txt
    llvm/trunk/tools/llvm-lto2/LLVMBuild.txt
      - copied, changed from r278309, llvm/trunk/lib/LTO/LLVMBuild.txt
    llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp
Modified:
    llvm/trunk/include/llvm/LTO/LTO.h
    llvm/trunk/lib/LTO/CMakeLists.txt
    llvm/trunk/lib/LTO/LLVMBuild.txt
    llvm/trunk/lib/LTO/LTO.cpp
    llvm/trunk/lib/Object/IRObjectFile.cpp
    llvm/trunk/test/CMakeLists.txt
    llvm/trunk/test/lit.cfg
    llvm/trunk/test/tools/gold/X86/coff.ll
    llvm/trunk/test/tools/gold/X86/comdat.ll
    llvm/trunk/test/tools/gold/X86/common.ll
    llvm/trunk/test/tools/gold/X86/emit-llvm.ll
    llvm/trunk/test/tools/gold/X86/opt-level.ll
    llvm/trunk/test/tools/gold/X86/parallel.ll
    llvm/trunk/test/tools/gold/X86/slp-vectorize.ll
    llvm/trunk/test/tools/gold/X86/start-lib-common.ll
    llvm/trunk/test/tools/gold/X86/strip_names.ll
    llvm/trunk/test/tools/gold/X86/thinlto.ll
    llvm/trunk/test/tools/gold/X86/thinlto_alias.ll
    llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll
    llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll
    llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll
    llvm/trunk/test/tools/gold/X86/type-merge2.ll
    llvm/trunk/test/tools/gold/X86/vectorize.ll
    llvm/trunk/test/tools/gold/X86/visibility.ll
    llvm/trunk/tools/gold/gold-plugin.cpp

Added: llvm/trunk/include/llvm/LTO/Config.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LTO/Config.h?rev=278330&view=auto
==============================================================================
--- llvm/trunk/include/llvm/LTO/Config.h (added)
+++ llvm/trunk/include/llvm/LTO/Config.h Thu Aug 11 07:56:40 2016
@@ -0,0 +1,169 @@
+//===-Config.h - LLVM Link Time Optimizer Configuration -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the lto::Config data structure, which allows clients to
+// configure LTO.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LTO_CONFIG_H
+#define LLVM_LTO_CONFIG_H
+
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/Target/TargetOptions.h"
+
+#include <functional>
+
+namespace llvm {
+
+class Error;
+class Module;
+class ModuleSummaryIndex;
+class raw_pwrite_stream;
+
+namespace lto {
+
+/// LTO configuration. A linker can configure LTO by setting fields in this data
+/// structure and passing it to the lto::LTO constructor.
+struct Config {
+  std::string CPU;
+  std::string Features;
+  TargetOptions Options;
+  std::vector<std::string> MAttrs;
+  Reloc::Model RelocModel = Reloc::PIC_;
+  CodeModel::Model CodeModel = CodeModel::Default;
+  CodeGenOpt::Level CGOptLevel = CodeGenOpt::Default;
+  unsigned OptLevel = 2;
+  bool DisableVerify = false;
+
+  /// Setting this field will replace target triples in input files with this
+  /// triple.
+  std::string OverrideTriple;
+
+  /// Setting this field will replace unspecified target triples in input files
+  /// with this triple.
+  std::string DefaultTriple;
+
+  bool ShouldDiscardValueNames = true;
+  DiagnosticHandlerFunction DiagHandler;
+
+  /// If this field is set, LTO will write input file paths and symbol
+  /// resolutions here in llvm-lto2 command line flag format. This can be
+  /// used for testing and for running the LTO pipeline outside of the linker
+  /// with llvm-lto2.
+  std::unique_ptr<raw_ostream> ResolutionFile;
+
+  /// The following callbacks deal with tasks, which normally represent the
+  /// entire optimization and code generation pipeline for what will become a
+  /// single native object file. Each task has a unique identifier between 0 and
+  /// getMaxTasks()-1, which is supplied to the callback via the Task parameter.
+  /// A task represents the entire pipeline for ThinLTO and regular
+  /// (non-parallel) LTO, but a parallel code generation task will be split into
+  /// N tasks before code generation, where N is the parallelism level.
+  ///
+  /// LTO may decide to stop processing a task at any time, for example if the
+  /// module is empty or if a module hook (see below) returns false. For this
+  /// reason, the client should not expect to receive exactly getMaxTasks()
+  /// native object files.
+
+  /// A module hook may be used by a linker to perform actions during the LTO
+  /// pipeline. For example, a linker may use this function to implement
+  /// -save-temps, or to add its own resolved symbols to the module. If this
+  /// function returns false, any further processing for that task is aborted.
+  ///
+  /// Module hooks must be thread safe with respect to the linker's internal
+  /// data structures. A module hook will never be called concurrently from
+  /// multiple threads with the same task ID, or the same module.
+  ///
+  /// Note that in out-of-process backend scenarios, none of the hooks will be
+  /// called for ThinLTO tasks.
+  typedef std::function<bool(size_t Task, Module &)> ModuleHookFn;
+
+  /// This module hook is called after linking (regular LTO) or loading
+  /// (ThinLTO) the module, before modifying it.
+  ModuleHookFn PreOptModuleHook;
+
+  /// This hook is called after promoting any internal functions
+  /// (ThinLTO-specific).
+  ModuleHookFn PostPromoteModuleHook;
+
+  /// This hook is called after internalizing the module.
+  ModuleHookFn PostInternalizeModuleHook;
+
+  /// This hook is called after importing from other modules (ThinLTO-specific).
+  ModuleHookFn PostImportModuleHook;
+
+  /// This module hook is called after optimization is complete.
+  ModuleHookFn PostOptModuleHook;
+
+  /// This module hook is called before code generation. It is similar to the
+  /// PostOptModuleHook, but for parallel code generation it is called after
+  /// splitting the module.
+  ModuleHookFn PreCodeGenModuleHook;
+
+  /// A combined index hook is called after all per-module indexes have been
+  /// combined (ThinLTO-specific). It can be used to implement -save-temps for
+  /// the combined index.
+  ///
+  /// If this function returns false, any further processing for ThinLTO tasks
+  /// is aborted.
+  ///
+  /// It is called regardless of whether the backend is in-process, although it
+  /// is not called from individual backend processes.
+  typedef std::function<bool(const ModuleSummaryIndex &Index)>
+      CombinedIndexHookFn;
+  CombinedIndexHookFn CombinedIndexHook;
+
+  /// This is a convenience function that configures this Config object to write
+  /// temporary files named after the given OutputFileName for each of the LTO
+  /// phases to disk. A client can use this function to implement -save-temps.
+  ///
+  /// FIXME: Temporary files derived from ThinLTO backends are currently named
+  /// after the input file name, rather than the output file name.
+  ///
+  /// Specifically, it (1) sets each of the above module hooks and the combined
+  /// index hook to a function that calls the hook function (if any) that was
+  /// present in the appropriate field when the addSaveTemps function was
+  /// called, and writes the module to a bitcode file with a name prefixed by
+  /// the given output file name, and (2) creates a resolution file whose name
+  /// is prefixed by the given output file name and sets ResolutionFile to its
+  /// file handle.
+  Error addSaveTemps(std::string OutputFileName);
+};
+
+/// This type defines a stream callback. A stream callback is used to add a
+/// native object that is generated on the fly. The callee must set up and
+/// return a output stream to write the native object to.
+///
+/// Stream callbacks must be thread safe.
+typedef std::function<std::unique_ptr<raw_pwrite_stream>(size_t Task)>
+    AddStreamFn;
+
+/// A derived class of LLVMContext that initializes itself according to a given
+/// Config object. The purpose of this class is to tie ownership of the
+/// diagnostic handler to the context, as opposed to the Config object (which
+/// may be ephemeral).
+struct LTOLLVMContext : LLVMContext {
+  static void funcDiagHandler(const DiagnosticInfo &DI, void *Context) {
+    auto *Fn = static_cast<DiagnosticHandlerFunction *>(Context);
+    (*Fn)(DI);
+  }
+
+  LTOLLVMContext(const Config &C) : DiagHandler(C.DiagHandler) {
+    setDiscardValueNames(C.ShouldDiscardValueNames);
+    enableDebugTypeODRUniquing();
+    setDiagnosticHandler(funcDiagHandler, &DiagHandler, true);
+  }
+  DiagnosticHandlerFunction DiagHandler;
+};
+
+}
+}
+
+#endif

Modified: llvm/trunk/include/llvm/LTO/LTO.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LTO/LTO.h?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/include/llvm/LTO/LTO.h (original)
+++ llvm/trunk/include/llvm/LTO/LTO.h Thu Aug 11 07:56:40 2016
@@ -16,14 +16,27 @@
 #ifndef LLVM_LTO_LTO_H
 #define LLVM_LTO_LTO_H
 
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/ModuleSummaryIndex.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/Linker/IRMover.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/thread.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/IPO/FunctionImport.h"
 
 namespace llvm {
 
+class Error;
 class LLVMContext;
 class MemoryBufferRef;
 class Module;
+class Target;
+class raw_pwrite_stream;
 
 /// Helper to load a module from bitcode.
 std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer,
@@ -69,6 +82,319 @@ void thinLTOResolveWeakForLinkerInIndex(
 void thinLTOInternalizeAndPromoteInIndex(
     ModuleSummaryIndex &Index,
     function_ref<bool(StringRef, GlobalValue::GUID)> isExported);
-}
+
+namespace lto {
+
+class LTO;
+struct SymbolResolution;
+class ThinBackendProc;
+
+/// An input file. This is a wrapper for IRObjectFile that exposes only the
+/// information that an LTO client should need in order to do symbol resolution.
+class InputFile {
+  // FIXME: Remove LTO class friendship once we have bitcode symbol tables.
+  friend LTO;
+  InputFile() = default;
+
+  // FIXME: Remove the LLVMContext once we have bitcode symbol tables.
+  LLVMContext Ctx;
+  std::unique_ptr<object::IRObjectFile> Obj;
+
+public:
+  /// Create an InputFile.
+  static Expected<std::unique_ptr<InputFile>> create(MemoryBufferRef Object);
+
+  class symbol_iterator;
+
+  /// This is a wrapper for object::basic_symbol_iterator that exposes only the
+  /// information that an LTO client should need in order to do symbol
+  /// resolution.
+  ///
+  /// This object is ephemeral; it is only valid as long as an iterator obtained
+  /// from symbols() refers to it.
+  class Symbol {
+    friend symbol_iterator;
+    friend LTO;
+
+    object::basic_symbol_iterator I;
+    const GlobalValue *GV;
+    uint32_t Flags;
+    SmallString<64> Name;
+
+    bool shouldSkip() {
+      return !(Flags & object::BasicSymbolRef::SF_Global) ||
+             (Flags & object::BasicSymbolRef::SF_FormatSpecific);
+    }
+
+    void skip() {
+      const object::SymbolicFile *Obj = I->getObject();
+      auto E = Obj->symbol_end();
+      while (I != E) {
+        Flags = I->getFlags();
+        if (!shouldSkip())
+          break;
+        ++I;
+      }
+      if (I == E)
+        return;
+
+      Name.clear();
+      {
+        raw_svector_ostream OS(Name);
+        I->printName(OS);
+      }
+      GV = cast<object::IRObjectFile>(Obj)->getSymbolGV(I->getRawDataRefImpl());
+    }
+
+  public:
+    Symbol(object::basic_symbol_iterator I) : I(I) { skip(); }
+
+    StringRef getName() const { return Name; }
+    StringRef getIRName() const {
+      if (GV)
+        return GV->getName();
+      return StringRef();
+    }
+    uint32_t getFlags() const { return Flags; }
+    GlobalValue::VisibilityTypes getVisibility() const {
+      if (GV)
+        return GV->getVisibility();
+      return GlobalValue::DefaultVisibility;
+    }
+    bool canBeOmittedFromSymbolTable() const {
+      return GV && llvm::canBeOmittedFromSymbolTable(GV);
+    }
+    Expected<const Comdat *> getComdat() const {
+      const GlobalObject *GO;
+      if (auto *GA = dyn_cast<GlobalAlias>(GV)) {
+        GO = GA->getBaseObject();
+        if (!GO)
+          return make_error<StringError>("Unable to determine comdat of alias!",
+                                         inconvertibleErrorCode());
+      } else {
+        GO = cast<GlobalObject>(GV);
+      }
+      if (GV)
+        return GV->getComdat();
+      return nullptr;
+    }
+    size_t getCommonSize() const {
+      assert(Flags & object::BasicSymbolRef::SF_Common);
+      if (!GV)
+        return 0;
+      return GV->getParent()->getDataLayout().getTypeAllocSize(
+          GV->getType()->getElementType());
+    }
+    unsigned getCommonAlignment() const {
+      assert(Flags & object::BasicSymbolRef::SF_Common);
+      if (!GV)
+        return 0;
+      return GV->getAlignment();
+    }
+  };
+
+  class symbol_iterator {
+    Symbol Sym;
+
+  public:
+    symbol_iterator(object::basic_symbol_iterator I) : Sym(I) {}
+
+    symbol_iterator &operator++() {
+      ++Sym.I;
+      Sym.skip();
+      return *this;
+    }
+
+    symbol_iterator operator++(int) {
+      symbol_iterator I = *this;
+      ++*this;
+      return I;
+    }
+
+    const Symbol &operator*() const { return Sym; }
+    const Symbol *operator->() const { return &Sym; }
+
+    bool operator!=(const symbol_iterator &Other) const {
+      return Sym.I != Other.Sym.I;
+    }
+  };
+
+  /// A range over the symbols in this InputFile.
+  iterator_range<symbol_iterator> symbols() {
+    return llvm::make_range(symbol_iterator(Obj->symbol_begin()),
+                            symbol_iterator(Obj->symbol_end()));
+  }
+
+  StringRef getSourceFileName() const {
+    return Obj->getModule().getSourceFileName();
+  }
+};
+
+/// A ThinBackend defines what happens after the thin-link phase during ThinLTO.
+/// The details of this type definition aren't important; clients can only
+/// create a ThinBackend using one of the create*ThinBackend() functions below.
+typedef std::function<std::unique_ptr<ThinBackendProc>(
+    Config &C, ModuleSummaryIndex &CombinedIndex,
+    StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+    AddStreamFn AddStream)>
+    ThinBackend;
+
+/// This ThinBackend runs the individual backend jobs in-process.
+ThinBackend createInProcessThinBackend(unsigned ParallelismLevel);
+
+/// This ThinBackend writes individual module indexes to files, instead of
+/// running the individual backend jobs. This backend is for distributed builds
+/// where separate processes will invoke the real backends.
+///
+/// To find the path to write the index to, the backend checks if the path has a
+/// prefix of OldPrefix; if so, it replaces that prefix with NewPrefix. It then
+/// appends ".thinlto.bc" and writes the index to that path. If
+/// ShouldEmitImportsFiles is true it also writes a list of imported files to a
+/// similar path with ".imports" appended instead.
+ThinBackend createWriteIndexesThinBackend(std::string OldPrefix,
+                                          std::string NewPrefix,
+                                          bool ShouldEmitImportsFiles,
+                                          std::string LinkedObjectsFile);
+
+/// This class implements a resolution-based interface to LLVM's LTO
+/// functionality. It supports regular LTO, parallel LTO code generation and
+/// ThinLTO. You can use it from a linker in the following way:
+/// - Set hooks and code generation options (see lto::Config struct defined in
+///   Config.h), and use the lto::Config object to create an lto::LTO object.
+/// - Create lto::InputFile objects using lto::InputFile::create(), then use
+///   the symbols() function to enumerate its symbols and compute a resolution
+///   for each symbol (see SymbolResolution below).
+/// - After the linker has visited each input file (and each regular object
+///   file) and computed a resolution for each symbol, take each lto::InputFile
+///   and pass it and an array of symbol resolutions to the add() function.
+/// - Call the getMaxTasks() function to get an upper bound on the number of
+///   native object files that LTO may add to the link.
+/// - Call the run() function. This function will use the supplied AddStream
+///   function to add up to getMaxTasks() native object files to the link.
+class LTO {
+  friend InputFile;
+
+public:
+  /// Create an LTO object. A default constructed LTO object has a reasonable
+  /// production configuration, but you can customize it by passing arguments to
+  /// this constructor.
+  /// FIXME: We do currently require the DiagHandler field to be set in Conf.
+  /// Until that is fixed, a Config argument is required.
+  LTO(Config Conf, ThinBackend Backend = nullptr,
+      unsigned ParallelCodeGenParallelismLevel = 1);
+
+  /// Add an input file to the LTO link, using the provided symbol resolutions.
+  /// The symbol resolutions must appear in the enumeration order given by
+  /// InputFile::symbols().
+  Error add(std::unique_ptr<InputFile> Obj, ArrayRef<SymbolResolution> Res);
+
+  /// Returns an upper bound on the number of tasks that the client may expect.
+  /// This may only be called after all IR object files have been added. For a
+  /// full description of tasks see LTOBackend.h.
+  size_t getMaxTasks() const;
+
+  /// Runs the LTO pipeline. This function calls the supplied AddStream function
+  /// to add native object files to the link.
+  Error run(AddStreamFn AddStream);
+
+private:
+  Config Conf;
+
+  struct RegularLTOState {
+    RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf);
+
+    unsigned ParallelCodeGenParallelismLevel;
+    LTOLLVMContext Ctx;
+    bool HasModule = false;
+    std::unique_ptr<Module> CombinedModule;
+    IRMover Mover;
+  } RegularLTO;
+
+  struct ThinLTOState {
+    ThinLTOState(ThinBackend Backend);
+
+    ThinBackend Backend;
+    ModuleSummaryIndex CombinedIndex;
+    MapVector<StringRef, MemoryBufferRef> ModuleMap;
+    DenseMap<GlobalValue::GUID, StringRef> PrevailingModuleForGUID;
+  } ThinLTO;
+
+  // The global resolution for a particular (mangled) symbol name. This is in
+  // particular necessary to track whether each symbol can be internalized.
+  // Because any input file may introduce a new cross-partition reference, we
+  // cannot make any final internalization decisions until all input files have
+  // been added and the client has called run(). During run() we apply
+  // internalization decisions either directly to the module (for regular LTO)
+  // or to the combined index (for ThinLTO).
+  struct GlobalResolution {
+    /// The unmangled name of the global.
+    std::string IRName;
+
+    bool UnnamedAddr = true;
+
+    /// This field keeps track of the partition number of this global. The
+    /// regular LTO object is partition 0, while each ThinLTO object has its own
+    /// partition number from 1 onwards.
+    ///
+    /// Any global that is defined or used by more than one partition, or that
+    /// is referenced externally, may not be internalized.
+    ///
+    /// Partitions generally have a one-to-one correspondence with tasks, except
+    /// that we use partition 0 for all parallel LTO code generation partitions.
+    /// Any partitioning of the combined LTO object is done internally by the
+    /// LTO backend.
+    size_t Partition = Unknown;
+
+    /// Special partition numbers.
+    enum {
+      /// A partition number has not yet been assigned to this global.
+      Unknown = -1ull,
+
+      /// This global is either used by more than one partition or has an
+      /// external reference, and therefore cannot be internalized.
+      External = -2ull,
+    };
+  };
+
+  // Global mapping from mangled symbol names to resolutions.
+  StringMap<GlobalResolution> GlobalResolutions;
+
+  void writeToResolutionFile(InputFile *Input, ArrayRef<SymbolResolution> Res);
+
+  void addSymbolToGlobalRes(object::IRObjectFile *Obj,
+                            SmallPtrSet<GlobalValue *, 8> &Used,
+                            const InputFile::Symbol &Sym, SymbolResolution Res,
+                            size_t Partition);
+
+  Error addRegularLTO(std::unique_ptr<InputFile> Input,
+                      ArrayRef<SymbolResolution> Res);
+  Error addThinLTO(std::unique_ptr<InputFile> Input,
+                   ArrayRef<SymbolResolution> Res);
+
+  Error runRegularLTO(AddStreamFn AddStream);
+  Error runThinLTO(AddStreamFn AddStream);
+
+  mutable bool CalledGetMaxTasks = false;
+};
+
+/// The resolution for a symbol. The linker must provide a SymbolResolution for
+/// each global symbol based on its internal resolution of that symbol.
+struct SymbolResolution {
+  SymbolResolution()
+      : Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0) {
+  }
+  /// The linker has chosen this definition of the symbol.
+  unsigned Prevailing : 1;
+
+  /// The definition of this symbol is unpreemptable at runtime and is known to
+  /// be in this linkage unit.
+  unsigned FinalDefinitionInLinkageUnit : 1;
+
+  /// The definition of this symbol is visible outside of the LTO unit.
+  unsigned VisibleToRegularObj : 1;
+};
+
+} // namespace lto
+} // namespace llvm
 
 #endif

Added: llvm/trunk/include/llvm/LTO/LTOBackend.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LTO/LTOBackend.h?rev=278330&view=auto
==============================================================================
--- llvm/trunk/include/llvm/LTO/LTOBackend.h (added)
+++ llvm/trunk/include/llvm/LTO/LTOBackend.h Thu Aug 11 07:56:40 2016
@@ -0,0 +1,51 @@
+//===-LTOBackend.h - LLVM Link Time Optimizer Backend ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the "backend" phase of LTO, i.e. it performs
+// optimization and code generation on a loaded module. It is generally used
+// internally by the LTO class but can also be used independently, for example
+// to implement a standalone ThinLTO backend.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LTO_LTOBACKEND_H
+#define LLVM_LTO_LTOBACKEND_H
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/IPO/FunctionImport.h"
+
+namespace llvm {
+
+class Error;
+class Module;
+class Target;
+
+namespace lto {
+
+/// Runs a regular LTO backend.
+Error backend(Config &C, AddStreamFn AddStream,
+              unsigned ParallelCodeGenParallelismLevel,
+              std::unique_ptr<Module> M);
+
+/// Runs a ThinLTO backend.
+Error thinBackend(Config &C, size_t Task, AddStreamFn AddStream, Module &M,
+                  ModuleSummaryIndex &CombinedIndex,
+                  const FunctionImporter::ImportMapTy &ImportList,
+                  const GVSummaryMapTy &DefinedGlobals,
+                  MapVector<StringRef, MemoryBufferRef> &ModuleMap);
+
+}
+}
+
+#endif

Modified: llvm/trunk/lib/LTO/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/CMakeLists.txt?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/CMakeLists.txt (original)
+++ llvm/trunk/lib/LTO/CMakeLists.txt Thu Aug 11 07:56:40 2016
@@ -49,6 +49,7 @@ endif()
 
 add_llvm_library(LLVMLTO
   LTO.cpp
+  LTOBackend.cpp
   LTOModule.cpp
   LTOCodeGenerator.cpp
   UpdateCompilerUsed.cpp

Modified: llvm/trunk/lib/LTO/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LLVMBuild.txt?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/LLVMBuild.txt (original)
+++ llvm/trunk/lib/LTO/LLVMBuild.txt Thu Aug 11 07:56:40 2016
@@ -34,4 +34,4 @@ required_libraries =
  Scalar
  Support
  Target
- TransformUtils
\ No newline at end of file
+ TransformUtils

Modified: llvm/trunk/lib/LTO/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTO.cpp?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/LTO.cpp (original)
+++ llvm/trunk/lib/LTO/LTO.cpp Thu Aug 11 07:56:40 2016
@@ -12,16 +12,39 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/LTO/LTO.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/LTO/LTOBackend.h"
+#include "llvm/Linker/IRMover.h"
+#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/SplitModule.h"
 
-namespace llvm {
+#include <set>
+
+using namespace llvm;
+using namespace lto;
+using namespace object;
 
 // Simple helper to load a module from bitcode
-std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer,
-                                             LLVMContext &Context, bool Lazy) {
+std::unique_ptr<Module>
+llvm::loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context,
+                           bool Lazy) {
   SMDiagnostic Err;
   ErrorOr<std::unique_ptr<Module>> ModuleOrErr(nullptr);
   if (Lazy) {
@@ -76,7 +99,7 @@ static void thinLTOResolveWeakForLinkerG
 // current module. However there is a chance that another module is still
 // referencing them because of the import. We make sure we always emit at least
 // one copy.
-void thinLTOResolveWeakForLinkerInIndex(
+void llvm::thinLTOResolveWeakForLinkerInIndex(
     ModuleSummaryIndex &Index,
     function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
         isPrevailing,
@@ -110,10 +133,513 @@ static void thinLTOInternalizeAndPromote
 
 // Update the linkages in the given \p Index to mark exported values
 // as external and non-exported values as internal.
-void thinLTOInternalizeAndPromoteInIndex(
+void llvm::thinLTOInternalizeAndPromoteInIndex(
     ModuleSummaryIndex &Index,
     function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
   for (auto &I : Index)
     thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported);
 }
+
+Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
+  std::unique_ptr<InputFile> File(new InputFile);
+  std::string Msg;
+  auto DiagHandler = [](const DiagnosticInfo &DI, void *MsgP) {
+    auto *Msg = reinterpret_cast<std::string *>(MsgP);
+    raw_string_ostream OS(*Msg);
+    DiagnosticPrinterRawOStream DP(OS);
+    DI.print(DP);
+  };
+  File->Ctx.setDiagnosticHandler(DiagHandler, static_cast<void *>(&Msg));
+
+  ErrorOr<std::unique_ptr<object::IRObjectFile>> IRObj =
+      IRObjectFile::create(Object, File->Ctx);
+  if (!Msg.empty())
+    return make_error<StringError>(Msg, inconvertibleErrorCode());
+  if (!IRObj)
+    return errorCodeToError(IRObj.getError());
+  File->Obj = std::move(*IRObj);
+
+  File->Ctx.setDiagnosticHandler(nullptr, nullptr);
+
+  return std::move(File);
+}
+
+LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel,
+                                      Config &Conf)
+    : ParallelCodeGenParallelismLevel(ParallelCodeGenParallelismLevel),
+      Ctx(Conf), CombinedModule(make_unique<Module>("ld-temp.o", Ctx)),
+      Mover(*CombinedModule) {}
+
+LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) : Backend(Backend) {
+  if (!Backend)
+    this->Backend = createInProcessThinBackend(thread::hardware_concurrency());
+}
+
+LTO::LTO(Config Conf, ThinBackend Backend,
+         unsigned ParallelCodeGenParallelismLevel)
+    : Conf(std::move(Conf)),
+      RegularLTO(ParallelCodeGenParallelismLevel, this->Conf),
+      ThinLTO(Backend) {}
+
+// Add the given symbol to the GlobalResolutions map, and resolve its partition.
+void LTO::addSymbolToGlobalRes(IRObjectFile *Obj,
+                               SmallPtrSet<GlobalValue *, 8> &Used,
+                               const InputFile::Symbol &Sym,
+                               SymbolResolution Res, size_t Partition) {
+  GlobalValue *GV = Obj->getSymbolGV(Sym.I->getRawDataRefImpl());
+
+  auto &GlobalRes = GlobalResolutions[Sym.getName()];
+  if (GV) {
+    GlobalRes.UnnamedAddr &= GV->hasGlobalUnnamedAddr();
+    if (Res.Prevailing)
+      GlobalRes.IRName = GV->getName();
+  }
+  if (Res.VisibleToRegularObj || (GV && Used.count(GV)) ||
+      (GlobalRes.Partition != GlobalResolution::Unknown &&
+       GlobalRes.Partition != Partition))
+    GlobalRes.Partition = GlobalResolution::External;
+  else
+    GlobalRes.Partition = Partition;
+}
+
+void LTO::writeToResolutionFile(InputFile *Input,
+                                ArrayRef<SymbolResolution> Res) {
+  StringRef Path = Input->Obj->getMemoryBufferRef().getBufferIdentifier();
+  *Conf.ResolutionFile << Path << '\n';
+  auto ResI = Res.begin();
+  for (const InputFile::Symbol &Sym : Input->symbols()) {
+    assert(ResI != Res.end());
+    SymbolResolution Res = *ResI++;
+
+    *Conf.ResolutionFile << "-r=" << Path << ',' << Sym.getName() << ',';
+    if (Res.Prevailing)
+      *Conf.ResolutionFile << 'p';
+    if (Res.FinalDefinitionInLinkageUnit)
+      *Conf.ResolutionFile << 'l';
+    if (Res.VisibleToRegularObj)
+      *Conf.ResolutionFile << 'x';
+    *Conf.ResolutionFile << '\n';
+  }
+  assert(ResI == Res.end());
+}
+
+Error LTO::add(std::unique_ptr<InputFile> Input,
+               ArrayRef<SymbolResolution> Res) {
+  assert(!CalledGetMaxTasks);
+
+  if (Conf.ResolutionFile)
+    writeToResolutionFile(Input.get(), Res);
+
+  Module &M = Input->Obj->getModule();
+  SmallPtrSet<GlobalValue *, 8> Used;
+  collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+
+  if (!Conf.OverrideTriple.empty())
+    M.setTargetTriple(Conf.OverrideTriple);
+  else if (M.getTargetTriple().empty())
+    M.setTargetTriple(Conf.DefaultTriple);
+
+  MemoryBufferRef MBRef = Input->Obj->getMemoryBufferRef();
+  bool HasThinLTOSummary = hasGlobalValueSummary(MBRef, Conf.DiagHandler);
+
+  if (HasThinLTOSummary)
+    return addThinLTO(std::move(Input), Res);
+  else
+    return addRegularLTO(std::move(Input), Res);
+}
+
+// Add a regular LTO object to the link.
+Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
+                         ArrayRef<SymbolResolution> Res) {
+  RegularLTO.HasModule = true;
+
+  ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
+      IRObjectFile::create(Input->Obj->getMemoryBufferRef(), RegularLTO.Ctx);
+  if (!ObjOrErr)
+    return errorCodeToError(ObjOrErr.getError());
+  std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr);
+
+  Module &M = Obj->getModule();
+  M.materializeMetadata();
+  UpgradeDebugInfo(M);
+
+  SmallPtrSet<GlobalValue *, 8> Used;
+  collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+
+  std::vector<GlobalValue *> Keep;
+
+  for (GlobalVariable &GV : M.globals())
+    if (GV.hasAppendingLinkage())
+      Keep.push_back(&GV);
+
+  auto ResI = Res.begin();
+  for (const InputFile::Symbol &Sym :
+       make_range(InputFile::symbol_iterator(Obj->symbol_begin()),
+                  InputFile::symbol_iterator(Obj->symbol_end()))) {
+    assert(ResI != Res.end());
+    SymbolResolution Res = *ResI++;
+    addSymbolToGlobalRes(Obj.get(), Used, Sym, Res, 0);
+
+    GlobalValue *GV = Obj->getSymbolGV(Sym.I->getRawDataRefImpl());
+    if (Res.Prevailing && GV) {
+      Keep.push_back(GV);
+      switch (GV->getLinkage()) {
+      default:
+        break;
+      case GlobalValue::LinkOnceAnyLinkage:
+        GV->setLinkage(GlobalValue::WeakAnyLinkage);
+        break;
+      case GlobalValue::LinkOnceODRLinkage:
+        GV->setLinkage(GlobalValue::WeakODRLinkage);
+        break;
+      }
+    }
+
+    // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
+  }
+  assert(ResI == Res.end());
+
+  return RegularLTO.Mover.move(Obj->takeModule(), Keep,
+                               [](GlobalValue &, IRMover::ValueAdder) {});
+}
+
+// Add a ThinLTO object to the link.
+Error LTO::addThinLTO(std::unique_ptr<InputFile> Input,
+                      ArrayRef<SymbolResolution> Res) {
+  Module &M = Input->Obj->getModule();
+  SmallPtrSet<GlobalValue *, 8> Used;
+  collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+
+  // We need to initialize the target info for the combined regular LTO module
+  // in case we have no regular LTO objects. In that case we still need to build
+  // it as usual because the client may want to add symbol definitions to it.
+  if (RegularLTO.CombinedModule->getTargetTriple().empty()) {
+    RegularLTO.CombinedModule->setTargetTriple(M.getTargetTriple());
+    RegularLTO.CombinedModule->setDataLayout(M.getDataLayout());
+  }
+
+  MemoryBufferRef MBRef = Input->Obj->getMemoryBufferRef();
+  ErrorOr<std::unique_ptr<object::ModuleSummaryIndexObjectFile>>
+      SummaryObjOrErr =
+          object::ModuleSummaryIndexObjectFile::create(MBRef, Conf.DiagHandler);
+  if (!SummaryObjOrErr)
+    return errorCodeToError(SummaryObjOrErr.getError());
+  ThinLTO.CombinedIndex.mergeFrom((*SummaryObjOrErr)->takeIndex(),
+                                  ThinLTO.ModuleMap.size());
+
+  auto ResI = Res.begin();
+  for (const InputFile::Symbol &Sym : Input->symbols()) {
+    assert(ResI != Res.end());
+    SymbolResolution Res = *ResI++;
+    addSymbolToGlobalRes(Input->Obj.get(), Used, Sym, Res,
+                         ThinLTO.ModuleMap.size() + 1);
+
+    GlobalValue *GV = Input->Obj->getSymbolGV(Sym.I->getRawDataRefImpl());
+    if (Res.Prevailing && GV)
+      ThinLTO.PrevailingModuleForGUID[GV->getGUID()] =
+          MBRef.getBufferIdentifier();
+  }
+  assert(ResI == Res.end());
+
+  ThinLTO.ModuleMap[MBRef.getBufferIdentifier()] = MBRef;
+  return Error();
+}
+
+size_t LTO::getMaxTasks() const {
+  CalledGetMaxTasks = true;
+  return RegularLTO.ParallelCodeGenParallelismLevel + ThinLTO.ModuleMap.size();
+}
+
+Error LTO::run(AddStreamFn AddStream) {
+  // Invoke regular LTO if there was a regular LTO module to start with,
+  // or if there are any hooks that the linker may have used to add
+  // its own resolved symbols to the combined module.
+  if (RegularLTO.HasModule || Conf.PreOptModuleHook ||
+      Conf.PostInternalizeModuleHook || Conf.PostOptModuleHook ||
+      Conf.PreCodeGenModuleHook)
+    if (auto E = runRegularLTO(AddStream))
+      return E;
+  return runThinLTO(AddStream);
+}
+
+Error LTO::runRegularLTO(AddStreamFn AddStream) {
+  if (Conf.PreOptModuleHook &&
+      !Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
+    return Error();
+
+  for (const auto &R : GlobalResolutions) {
+    if (R.second.IRName.empty())
+      continue;
+    if (R.second.Partition != 0 &&
+        R.second.Partition != GlobalResolution::External)
+      continue;
+
+    GlobalValue *GV = RegularLTO.CombinedModule->getNamedValue(R.second.IRName);
+    // Ignore symbols defined in other partitions.
+    if (!GV || GV->hasLocalLinkage())
+      continue;
+    GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global
+                                            : GlobalValue::UnnamedAddr::None);
+    if (R.second.Partition == 0)
+      GV->setLinkage(GlobalValue::InternalLinkage);
+  }
+
+  if (Conf.PostInternalizeModuleHook &&
+      !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
+    return Error();
+
+  return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
+                 std::move(RegularLTO.CombinedModule));
+}
+
+/// This class defines the interface to the ThinLTO backend.
+class lto::ThinBackendProc {
+protected:
+  Config &Conf;
+  ModuleSummaryIndex &CombinedIndex;
+  AddStreamFn AddStream;
+  StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries;
+
+public:
+  ThinBackendProc(Config &Conf, ModuleSummaryIndex &CombinedIndex,
+                  AddStreamFn AddStream,
+                  StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries)
+      : Conf(Conf), CombinedIndex(CombinedIndex), AddStream(AddStream),
+        ModuleToDefinedGVSummaries(ModuleToDefinedGVSummaries) {}
+
+  virtual ~ThinBackendProc() {}
+  virtual Error start(size_t Task, MemoryBufferRef MBRef,
+                      StringMap<FunctionImporter::ImportMapTy> &ImportLists,
+                      MapVector<StringRef, MemoryBufferRef> &ModuleMap) = 0;
+  virtual Error wait() = 0;
+};
+
+class InProcessThinBackend : public ThinBackendProc {
+  ThreadPool BackendThreadPool;
+
+  Optional<Error> Err;
+  std::mutex ErrMu;
+
+public:
+  InProcessThinBackend(Config &Conf, ModuleSummaryIndex &CombinedIndex,
+                       unsigned ThinLTOParallelismLevel,
+                       StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+                       AddStreamFn AddStream)
+      : ThinBackendProc(Conf, CombinedIndex, AddStream,
+                        ModuleToDefinedGVSummaries),
+        BackendThreadPool(ThinLTOParallelismLevel) {}
+
+  Error
+  runThinLTOBackendThread(AddStreamFn AddStream, size_t Task,
+                          MemoryBufferRef MBRef,
+                          ModuleSummaryIndex &CombinedIndex,
+                          const FunctionImporter::ImportMapTy &ImportList,
+                          const GVSummaryMapTy &DefinedGlobals,
+                          MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
+    LLVMContext BackendContext;
+
+    ErrorOr<std::unique_ptr<Module>> MOrErr =
+        parseBitcodeFile(MBRef, BackendContext);
+    assert(MOrErr && "Unable to load module in thread?");
+
+    return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
+                       ImportList, DefinedGlobals, ModuleMap);
+  }
+
+  Error start(size_t Task, MemoryBufferRef MBRef,
+              StringMap<FunctionImporter::ImportMapTy> &ImportLists,
+              MapVector<StringRef, MemoryBufferRef> &ModuleMap) override {
+    StringRef ModulePath = MBRef.getBufferIdentifier();
+    BackendThreadPool.async(
+        [=](MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex,
+            const FunctionImporter::ImportMapTy &ImportList,
+            GVSummaryMapTy &DefinedGlobals,
+            MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
+          Error E =
+              runThinLTOBackendThread(AddStream, Task, MBRef, CombinedIndex,
+                                      ImportList, DefinedGlobals, ModuleMap);
+          if (E) {
+            std::unique_lock<std::mutex> L(ErrMu);
+            if (Err)
+              Err = joinErrors(std::move(*Err), std::move(E));
+            else
+              Err = std::move(E);
+          }
+        },
+        MBRef, std::ref(CombinedIndex), std::ref(ImportLists[ModulePath]),
+        std::ref(ModuleToDefinedGVSummaries[ModulePath]), std::ref(ModuleMap));
+    return Error();
+  }
+
+  Error wait() override {
+    BackendThreadPool.wait();
+    if (Err)
+      return std::move(*Err);
+    else
+      return Error();
+  }
+};
+
+ThinBackend lto::createInProcessThinBackend(unsigned ParallelismLevel) {
+  return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
+             StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+             AddStreamFn AddStream) {
+    return make_unique<InProcessThinBackend>(
+        Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries,
+        AddStream);
+  };
+}
+
+class WriteIndexesThinBackend : public ThinBackendProc {
+  std::string OldPrefix, NewPrefix;
+  bool ShouldEmitImportsFiles;
+
+  std::string LinkedObjectsFileName;
+  std::unique_ptr<llvm::raw_fd_ostream> LinkedObjectsFile;
+
+public:
+  WriteIndexesThinBackend(Config &Conf, ModuleSummaryIndex &CombinedIndex,
+                          StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+                          AddStreamFn AddStream, std::string OldPrefix,
+                          std::string NewPrefix, bool ShouldEmitImportsFiles,
+                          std::string LinkedObjectsFileName)
+      : ThinBackendProc(Conf, CombinedIndex, AddStream,
+                        ModuleToDefinedGVSummaries),
+        OldPrefix(OldPrefix), NewPrefix(NewPrefix),
+        ShouldEmitImportsFiles(ShouldEmitImportsFiles),
+        LinkedObjectsFileName(LinkedObjectsFileName) {}
+
+  /// Given the original \p Path to an output file, replace any path
+  /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
+  /// resulting directory if it does not yet exist.
+  std::string getThinLTOOutputFile(const std::string &Path,
+                                   const std::string &OldPrefix,
+                                   const std::string &NewPrefix) {
+    if (OldPrefix.empty() && NewPrefix.empty())
+      return Path;
+    SmallString<128> NewPath(Path);
+    llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
+    StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
+    if (!ParentPath.empty()) {
+      // Make sure the new directory exists, creating it if necessary.
+      if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
+        llvm::errs() << "warning: could not create directory '" << ParentPath
+                     << "': " << EC.message() << '\n';
+    }
+    return NewPath.str();
+  }
+
+  Error start(size_t Task, MemoryBufferRef MBRef,
+              StringMap<FunctionImporter::ImportMapTy> &ImportLists,
+              MapVector<StringRef, MemoryBufferRef> &ModuleMap) override {
+    StringRef ModulePath = MBRef.getBufferIdentifier();
+    std::string NewModulePath =
+        getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix);
+
+    std::error_code EC;
+    if (!LinkedObjectsFileName.empty()) {
+      if (!LinkedObjectsFile) {
+        LinkedObjectsFile = make_unique<raw_fd_ostream>(
+            LinkedObjectsFileName, EC, sys::fs::OpenFlags::F_None);
+        if (EC)
+          return errorCodeToError(EC);
+      }
+      *LinkedObjectsFile << NewModulePath << '\n';
+    }
+
+    std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
+    gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries,
+                                     ImportLists, ModuleToSummariesForIndex);
+
+    raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC,
+                      sys::fs::OpenFlags::F_None);
+    if (EC)
+      return errorCodeToError(EC);
+    WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex);
+
+    if (ShouldEmitImportsFiles)
+      return errorCodeToError(EmitImportsFiles(
+          ModulePath, NewModulePath + ".imports", ImportLists));
+    return Error();
+  }
+
+  Error wait() override { return Error(); }
+};
+
+ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix,
+                                               std::string NewPrefix,
+                                               bool ShouldEmitImportsFiles,
+                                               std::string LinkedObjectsFile) {
+  return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
+             StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+             AddStreamFn AddStream) {
+    return make_unique<WriteIndexesThinBackend>(
+        Conf, CombinedIndex, ModuleToDefinedGVSummaries, AddStream, OldPrefix,
+        NewPrefix, ShouldEmitImportsFiles, LinkedObjectsFile);
+  };
+}
+
+Error LTO::runThinLTO(AddStreamFn AddStream) {
+  if (ThinLTO.ModuleMap.empty())
+    return Error();
+
+  if (Conf.CombinedIndexHook && !Conf.CombinedIndexHook(ThinLTO.CombinedIndex))
+    return Error();
+
+  // Collect for each module the list of function it defines (GUID ->
+  // Summary).
+  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+      ModuleToDefinedGVSummaries(ThinLTO.ModuleMap.size());
+  ThinLTO.CombinedIndex.collectDefinedGVSummariesPerModule(
+      ModuleToDefinedGVSummaries);
+
+  StringMap<FunctionImporter::ImportMapTy> ImportLists(
+      ThinLTO.ModuleMap.size());
+  StringMap<FunctionImporter::ExportSetTy> ExportLists(
+      ThinLTO.ModuleMap.size());
+  ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
+                           ImportLists, ExportLists);
+
+  std::set<GlobalValue::GUID> ExportedGUIDs;
+  for (auto &Res : GlobalResolutions) {
+    if (!Res.second.IRName.empty() &&
+        Res.second.Partition == GlobalResolution::External)
+      ExportedGUIDs.insert(GlobalValue::getGUID(Res.second.IRName));
+  }
+
+  auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
+    return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath();
+  };
+  auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
+    const auto &ExportList = ExportLists.find(ModuleIdentifier);
+    return (ExportList != ExportLists.end() &&
+            ExportList->second.count(GUID)) ||
+           ExportedGUIDs.count(GUID);
+  };
+  thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
+  thinLTOResolveWeakForLinkerInIndex(
+      ThinLTO.CombinedIndex, isPrevailing,
+      [](StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes) {});
+
+  std::unique_ptr<ThinBackendProc> BackendProc = ThinLTO.Backend(
+      Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, AddStream);
+
+  // Partition numbers for ThinLTO jobs start at 1 (see comments for
+  // GlobalResolution in LTO.h). Task numbers, however, start at
+  // ParallelCodeGenParallelismLevel, as tasks 0 through
+  // ParallelCodeGenParallelismLevel-1 are reserved for parallel code generation
+  // partitions.
+  size_t Task = RegularLTO.ParallelCodeGenParallelismLevel;
+  size_t Partition = 1;
+
+  for (auto &Mod : ThinLTO.ModuleMap) {
+    if (Error E = BackendProc->start(Task, Mod.second, ImportLists,
+                                     ThinLTO.ModuleMap))
+      return E;
+
+    ++Task;
+    ++Partition;
+  }
+
+  return BackendProc->wait();
 }

Added: llvm/trunk/lib/LTO/LTOBackend.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTOBackend.cpp?rev=278330&view=auto
==============================================================================
--- llvm/trunk/lib/LTO/LTOBackend.cpp (added)
+++ llvm/trunk/lib/LTO/LTOBackend.cpp Thu Aug 11 07:56:40 2016
@@ -0,0 +1,277 @@
+//===-LTOBackend.cpp - LLVM Link Time Optimizer Backend -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the "backend" phase of LTO, i.e. it performs
+// optimization and code generation on a loaded module. It is generally used
+// internally by the LTO class but can also be used independently, for example
+// to implement a standalone ThinLTO backend.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/LTO/LTOBackend.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/FunctionImportUtils.h"
+#include "llvm/Transforms/Utils/SplitModule.h"
+
+using namespace llvm;
+using namespace lto;
+
+Error Config::addSaveTemps(std::string OutputFileName) {
+  ShouldDiscardValueNames = false;
+
+  std::error_code EC;
+  ResolutionFile = make_unique<raw_fd_ostream>(
+      OutputFileName + ".resolution.txt", EC, sys::fs::OpenFlags::F_Text);
+  if (EC)
+    return errorCodeToError(EC);
+
+  auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) {
+    // Keep track of the hook provided by the linker, which also needs to run.
+    ModuleHookFn LinkerHook = Hook;
+    Hook = [=](size_t Task, Module &M) {
+      // If the linker's hook returned false, we need to pass that result
+      // through.
+      if (LinkerHook && !LinkerHook(Task, M))
+        return false;
+
+      std::string PathPrefix;
+      PathPrefix = OutputFileName;
+      if (Task != 0)
+        PathPrefix += "." + utostr(Task);
+      std::string Path = PathPrefix + "." + PathSuffix + ".bc";
+      std::error_code EC;
+      raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
+      if (EC) {
+        // Because -save-temps is a debugging feature, we report the error
+        // directly and exit.
+        llvm::errs() << "failed to open " << Path << ": " << EC.message()
+                     << '\n';
+        exit(1);
+      }
+      WriteBitcodeToFile(&M, OS, /*ShouldPreserveUseListOrder=*/false);
+      return true;
+    };
+  };
+
+  setHook("0.preopt", PreOptModuleHook);
+  setHook("1.promote", PostPromoteModuleHook);
+  setHook("2.internalize", PostInternalizeModuleHook);
+  setHook("3.import", PostImportModuleHook);
+  setHook("4.opt", PostOptModuleHook);
+  setHook("5.precodegen", PreCodeGenModuleHook);
+
+  CombinedIndexHook = [=](const ModuleSummaryIndex &Index) {
+    std::string Path = OutputFileName + ".index.bc";
+    std::error_code EC;
+    raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
+    if (EC) {
+      // Because -save-temps is a debugging feature, we report the error
+      // directly and exit.
+      llvm::errs() << "failed to open " << Path << ": " << EC.message() << '\n';
+      exit(1);
+    }
+    WriteIndexToFile(Index, OS);
+    return true;
+  };
+
+  return Error();
+}
+
+namespace {
+
+std::unique_ptr<TargetMachine>
+createTargetMachine(Config &C, StringRef TheTriple, const Target *TheTarget) {
+  SubtargetFeatures Features;
+  Features.getDefaultSubtargetFeatures(Triple(TheTriple));
+  for (const std::string &A : C.MAttrs)
+    Features.AddFeature(A);
+
+  return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
+      TheTriple, C.CPU, Features.getString(), C.Options, C.RelocModel,
+      C.CodeModel, C.CGOptLevel));
+}
+
+bool opt(Config &C, TargetMachine *TM, size_t Task, Module &M, bool IsThinLto) {
+  M.setDataLayout(TM->createDataLayout());
+
+  legacy::PassManager passes;
+  passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
+
+  PassManagerBuilder PMB;
+  PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()));
+  PMB.Inliner = createFunctionInliningPass();
+  // Unconditionally verify input since it is not verified before this
+  // point and has unknown origin.
+  PMB.VerifyInput = true;
+  PMB.VerifyOutput = !C.DisableVerify;
+  PMB.LoopVectorize = true;
+  PMB.SLPVectorize = true;
+  PMB.OptLevel = C.OptLevel;
+  if (IsThinLto)
+    PMB.populateThinLTOPassManager(passes);
+  else
+    PMB.populateLTOPassManager(passes);
+  passes.run(M);
+
+  if (C.PostOptModuleHook && !C.PostOptModuleHook(Task, M))
+    return false;
+
+  return true;
+}
+
+void codegen(Config &C, TargetMachine *TM, AddStreamFn AddStream, size_t Task,
+             Module &M) {
+  if (C.PreCodeGenModuleHook && !C.PreCodeGenModuleHook(Task, M))
+    return;
+
+  std::unique_ptr<raw_pwrite_stream> OS = AddStream(Task);
+  legacy::PassManager CodeGenPasses;
+  if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
+                              TargetMachine::CGFT_ObjectFile))
+    report_fatal_error("Failed to setup codegen");
+  CodeGenPasses.run(M);
+}
+
+void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream,
+                  unsigned ParallelCodeGenParallelismLevel,
+                  std::unique_ptr<Module> M) {
+  ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
+  unsigned ThreadCount = 0;
+  const Target *T = &TM->getTarget();
+
+  SplitModule(
+      std::move(M), ParallelCodeGenParallelismLevel,
+      [&](std::unique_ptr<Module> MPart) {
+        // We want to clone the module in a new context to multi-thread the
+        // codegen. We do it by serializing partition modules to bitcode
+        // (while still on the main thread, in order to avoid data races) and
+        // spinning up new threads which deserialize the partitions into
+        // separate contexts.
+        // FIXME: Provide a more direct way to do this in LLVM.
+        SmallString<0> BC;
+        raw_svector_ostream BCOS(BC);
+        WriteBitcodeToFile(MPart.get(), BCOS);
+
+        // Enqueue the task
+        CodegenThreadPool.async(
+            [&](const SmallString<0> &BC, unsigned ThreadId) {
+              LTOLLVMContext Ctx(C);
+              ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
+                  MemoryBufferRef(StringRef(BC.data(), BC.size()), "ld-temp.o"),
+                  Ctx);
+              if (!MOrErr)
+                report_fatal_error("Failed to read bitcode");
+              std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
+
+              std::unique_ptr<TargetMachine> TM =
+                  createTargetMachine(C, MPartInCtx->getTargetTriple(), T);
+              codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx);
+            },
+            // Pass BC using std::move to ensure that it get moved rather than
+            // copied into the thread's context.
+            std::move(BC), ThreadCount++);
+      },
+      false);
+}
+
+Expected<const Target *> initAndLookupTarget(Config &C, Module &M) {
+  if (!C.OverrideTriple.empty())
+    M.setTargetTriple(C.OverrideTriple);
+  else if (M.getTargetTriple().empty())
+    M.setTargetTriple(C.DefaultTriple);
+
+  std::string Msg;
+  const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
+  if (!T)
+    return make_error<StringError>(Msg, inconvertibleErrorCode());
+  return T;
+}
+
+}
+
+Error lto::backend(Config &C, AddStreamFn AddStream,
+                   unsigned ParallelCodeGenParallelismLevel,
+                   std::unique_ptr<Module> M) {
+  Expected<const Target *> TOrErr = initAndLookupTarget(C, *M);
+  if (!TOrErr)
+    return TOrErr.takeError();
+
+  std::unique_ptr<TargetMachine> TM =
+      createTargetMachine(C, M->getTargetTriple(), *TOrErr);
+
+  if (!opt(C, TM.get(), 0, *M, /*IsThinLto=*/false))
+    return Error();
+
+  if (ParallelCodeGenParallelismLevel == 1)
+    codegen(C, TM.get(), AddStream, 0, *M);
+  else
+    splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel,
+                 std::move(M));
+  return Error();
+}
+
+Error lto::thinBackend(Config &C, size_t Task, AddStreamFn AddStream, Module &M,
+                       ModuleSummaryIndex &CombinedIndex,
+                       const FunctionImporter::ImportMapTy &ImportList,
+                       const GVSummaryMapTy &DefinedGlobals,
+                       MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
+  Expected<const Target *> TOrErr = initAndLookupTarget(C, M);
+  if (!TOrErr)
+    return TOrErr.takeError();
+
+  std::unique_ptr<TargetMachine> TM =
+      createTargetMachine(C, M.getTargetTriple(), *TOrErr);
+
+  if (C.PreOptModuleHook && !C.PreOptModuleHook(Task, M))
+    return Error();
+
+  thinLTOResolveWeakForLinkerModule(M, DefinedGlobals);
+
+  renameModuleForThinLTO(M, CombinedIndex);
+
+  if (C.PostPromoteModuleHook && !C.PostPromoteModuleHook(Task, M))
+    return Error();
+
+  if (!DefinedGlobals.empty())
+    thinLTOInternalizeModule(M, DefinedGlobals);
+
+  if (C.PostInternalizeModuleHook && !C.PostInternalizeModuleHook(Task, M))
+    return Error();
+
+  auto ModuleLoader = [&](StringRef Identifier) {
+    return std::move(getLazyBitcodeModule(MemoryBuffer::getMemBuffer(
+                                              ModuleMap[Identifier], false),
+                                          M.getContext(),
+                                          /*ShouldLazyLoadMetadata=*/true)
+                         .get());
+  };
+
+  FunctionImporter Importer(CombinedIndex, ModuleLoader);
+  Importer.importFunctions(M, ImportList);
+
+  if (C.PostImportModuleHook && !C.PostImportModuleHook(Task, M))
+    return Error();
+
+  if (!opt(C, TM.get(), Task, M, /*IsThinLto=*/true))
+    return Error();
+
+  codegen(C, TM.get(), AddStream, Task, M);
+  return Error();
+}

Modified: llvm/trunk/lib/Object/IRObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/IRObjectFile.cpp?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/lib/Object/IRObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/IRObjectFile.cpp Thu Aug 11 07:56:40 2016
@@ -324,5 +324,5 @@ llvm::object::IRObjectFile::create(Memor
     return EC;
 
   std::unique_ptr<Module> &M = MOrErr.get();
-  return llvm::make_unique<IRObjectFile>(Object, std::move(M));
+  return llvm::make_unique<IRObjectFile>(BCOrErr.get(), std::move(M));
 }

Modified: llvm/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CMakeLists.txt?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/CMakeLists.txt (original)
+++ llvm/trunk/test/CMakeLists.txt Thu Aug 11 07:56:40 2016
@@ -43,6 +43,7 @@ set(LLVM_TEST_DEPENDS
           llvm-extract
           llvm-lib
           llvm-link
+          llvm-lto2
           llvm-mc
           llvm-mcmarkup
           llvm-nm

Added: llvm/trunk/test/LTO/Resolution/X86/Inputs/alias-1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/Inputs/alias-1.ll?rev=278330&view=auto
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/Inputs/alias-1.ll (added)
+++ llvm/trunk/test/LTO/Resolution/X86/Inputs/alias-1.ll Thu Aug 11 07:56:40 2016
@@ -0,0 +1,4 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at a = global i32 42

Added: llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll?rev=278330&view=auto
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll (added)
+++ llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll Thu Aug 11 07:56:40 2016
@@ -0,0 +1,28 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$c2 = comdat any
+$c1 = comdat any
+
+; This is only present in this file. The linker will keep $c1 from the first
+; file and this will be undefined.
+ at will_be_undefined = global i32 1, comdat($c1)
+
+ at v1 = weak_odr global i32 41, comdat($c2)
+define weak_odr protected i32 @f1(i8* %this) comdat($c2) {
+bb20:
+  store i8* %this, i8** null
+  br label %bb21
+bb21:
+  ret i32 41
+}
+
+ at r21 = global i32* @v1
+ at r22 = global i32(i8*)* @f1
+
+ at a21 = alias i32, i32* @v1
+ at a22 = alias i16, bitcast (i32* @v1 to i16*)
+
+ at a23 = alias i32(i8*), i32(i8*)* @f1
+ at a24 = alias i16, bitcast (i32(i8*)* @f1 to i16*)
+ at a25 = alias i16, i16* @a24

Added: llvm/trunk/test/LTO/Resolution/X86/alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/alias.ll?rev=278330&view=auto
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/alias.ll (added)
+++ llvm/trunk/test/LTO/Resolution/X86/alias.ll Thu Aug 11 07:56:40 2016
@@ -0,0 +1,22 @@
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/alias-1.ll -o %t2.o
+; RUN: llvm-lto2 -o %t3.o %t2.o %t1.o -r %t2.o,a,px -r %t1.o,a, -r %t1.o,b,px -save-temps
+; RUN: llvm-dis < %t3.o.0.preopt.bc -o - | FileCheck %s
+; RUN: FileCheck --check-prefix=RES %s < %t3.o.resolution.txt
+
+; CHECK-NOT: alias
+; CHECK: @a = global i32 42
+; CHECK-NEXT: @b = global i32 1
+; CHECK-NOT: alias
+
+; RES: 2.o{{$}}
+; RES: {{^}}-r={{.*}}2.o,a,px{{$}}
+; RES: 1.o{{$}}
+; RES: {{^}}-r={{.*}}1.o,b,px{{$}}
+; RES: {{^}}-r={{.*}}1.o,a,{{$}}
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at a = weak alias i32, i32* @b
+ at b = global i32 1

Copied: llvm/trunk/test/LTO/Resolution/X86/comdat.ll (from r278309, llvm/trunk/test/tools/gold/X86/comdat.ll)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/comdat.ll?p2=llvm/trunk/test/LTO/Resolution/X86/comdat.ll&p1=llvm/trunk/test/tools/gold/X86/comdat.ll&r1=278309&r2=278330&rev=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/comdat.ll (original)
+++ llvm/trunk/test/LTO/Resolution/X86/comdat.ll Thu Aug 11 07:56:40 2016
@@ -1,8 +1,29 @@
 ; RUN: llvm-as %s -o %t.o
 ; RUN: llvm-as %p/Inputs/comdat.ll -o %t2.o
-; RUN: %gold -shared -o %t3.o -plugin %llvmshlibdir/LLVMgold.so %t.o %t2.o \
-; RUN:  -plugin-opt=save-temps
-; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
+; RUN: llvm-lto2 -save-temps -o %t3.o %t.o %t2.o \
+; RUN:  -r=%t.o,f1,plx \
+; RUN:  -r=%t.o,v1,px \
+; RUN:  -r=%t.o,r11,px \
+; RUN:  -r=%t.o,r12,px \
+; RUN:  -r=%t.o,a11,px \
+; RUN:  -r=%t.o,a12,px \
+; RUN:  -r=%t.o,a13,px \
+; RUN:  -r=%t.o,a14,px \
+; RUN:  -r=%t.o,a15,px \
+; RUN:  -r=%t2.o,f1,l \
+; RUN:  -r=%t2.o,will_be_undefined, \
+; RUN:  -r=%t2.o,v1, \
+; RUN:  -r=%t2.o,r21,px \
+; RUN:  -r=%t2.o,r22,px \
+; RUN:  -r=%t2.o,a21,px \
+; RUN:  -r=%t2.o,a22,px \
+; RUN:  -r=%t2.o,a23,px \
+; RUN:  -r=%t2.o,a24,px \
+; RUN:  -r=%t2.o,a25,px
+; RUN: llvm-dis %t3.o.2.internalize.bc -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
 
 $c1 = comdat any
 
@@ -49,7 +70,7 @@ bb11:
 ; CHECK-DAG: @a23 = alias i32 (i8*), i32 (i8*)* @f1.2{{$}}
 ; CHECK-DAG: @a24 = alias i16, bitcast (i32 (i8*)* @f1.2 to i16*)
 
-; CHECK:      define weak_odr protected i32 @f1(i8*) comdat($c1) {
+; CHECK:      define weak_odr i32 @f1(i8*) comdat($c1) {
 ; CHECK-NEXT: bb10:
 ; CHECK-NEXT:   br label %bb11{{$}}
 ; CHECK:      bb11:

Added: llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg?rev=278330&view=auto
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg (added)
+++ llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg Thu Aug 11 07:56:40 2016
@@ -0,0 +1,2 @@
+if not 'X86' in config.root.targets:
+  config.unsupported = True

Modified: llvm/trunk/test/lit.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/lit.cfg?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/lit.cfg (original)
+++ llvm/trunk/test/lit.cfg Thu Aug 11 07:56:40 2016
@@ -295,6 +295,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
                 r"\bllvm-lib\b",
                 r"\bllvm-link\b",
                 r"\bllvm-lto\b",
+                r"\bllvm-lto2\b",
                 r"\bllvm-mc\b",
                 r"\bllvm-mcmarkup\b",
                 r"\bllvm-nm\b",

Modified: llvm/trunk/test/tools/gold/X86/coff.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/coff.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/coff.ll (original)
+++ llvm/trunk/test/tools/gold/X86/coff.ll Thu Aug 11 07:56:40 2016
@@ -16,7 +16,7 @@ define hidden void @g() {
   ret void
 }
 
-; CHECK: define internal void @h() local_unnamed_addr {
+; CHECK: define internal void @h() {
 define linkonce_odr void @h() local_unnamed_addr {
   ret void
 }

Modified: llvm/trunk/test/tools/gold/X86/comdat.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/comdat.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/comdat.ll (original)
+++ llvm/trunk/test/tools/gold/X86/comdat.ll Thu Aug 11 07:56:40 2016
@@ -1,8 +1,9 @@
-; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %s -o %t1.o
 ; RUN: llvm-as %p/Inputs/comdat.ll -o %t2.o
-; RUN: %gold -shared -o %t3.o -plugin %llvmshlibdir/LLVMgold.so %t.o %t2.o \
+; RUN: %gold -shared -o %t3.o -plugin %llvmshlibdir/LLVMgold.so %t1.o %t2.o \
 ; RUN:  -plugin-opt=save-temps
-; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
+; RUN: FileCheck --check-prefix=RES %s < %t3.o.resolution.txt
+; RUN: llvm-readobj -t %t3.o | FileCheck --check-prefix=OBJ %s
 
 $c1 = comdat any
 
@@ -24,42 +25,37 @@ bb11:
 @a14 = alias i16, bitcast (i32 (i8*)* @f1 to i16*)
 @a15 = alias i16, i16* @a14
 
-; CHECK: $c1 = comdat any
-; CHECK: $c2 = comdat any
+; gold's resolutions should tell us that our $c1 wins, and the other input's $c2
+; wins. f1 is also local due to having protected visibility in the other object.
 
-; CHECK-DAG: @v1 = weak_odr global i32 42, comdat($c1)
-
-; CHECK-DAG: @r11 = global i32* @v1{{$}}
-; CHECK-DAG: @r12 = global i32 (i8*)* @f1{{$}}
-
-; CHECK-DAG: @r21 = global i32* @v1{{$}}
-; CHECK-DAG: @r22 = global i32 (i8*)* @f1{{$}}
-
-; CHECK-DAG: @v1.1 = internal global i32 41, comdat($c2)
-
-; CHECK-DAG: @a11 = alias i32, i32* @v1{{$}}
-; CHECK-DAG: @a12 = alias i16, bitcast (i32* @v1 to i16*)
-
-; CHECK-DAG: @a13 = alias i32 (i8*), i32 (i8*)* @f1{{$}}
-; CHECK-DAG: @a14 = alias i16, bitcast (i32 (i8*)* @f1 to i16*)
-
-; CHECK-DAG: @a21 = alias i32, i32* @v1.1{{$}}
-; CHECK-DAG: @a22 = alias i16, bitcast (i32* @v1.1 to i16*)
-
-; CHECK-DAG: @a23 = alias i32 (i8*), i32 (i8*)* @f1.2{{$}}
-; CHECK-DAG: @a24 = alias i16, bitcast (i32 (i8*)* @f1.2 to i16*)
-
-; CHECK:      define weak_odr protected i32 @f1(i8*) comdat($c1) {
-; CHECK-NEXT: bb10:
-; CHECK-NEXT:   br label %bb11{{$}}
-; CHECK:      bb11:
-; CHECK-NEXT:   ret i32 42
-; CHECK-NEXT: }
-
-; CHECK:      define internal i32 @f1.2(i8* %this) comdat($c2) {
-; CHECK-NEXT: bb20:
-; CHECK-NEXT:   store i8* %this, i8** null
-; CHECK-NEXT:   br label %bb21
-; CHECK:      bb21:
-; CHECK-NEXT:   ret i32 41
-; CHECK-NEXT: }
+; RES: 1.o,f1,plx{{$}}
+; RES: 1.o,v1,px{{$}}
+; RES: 1.o,r11,px{{$}}
+; RES: 1.o,r12,px{{$}}
+; RES: 1.o,a11,px{{$}}
+; RES: 1.o,a12,px{{$}}
+; RES: 1.o,a13,px{{$}}
+; RES: 1.o,a14,px{{$}}
+; RES: 1.o,a15,px{{$}}
+
+; RES: 2.o,f1,l{{$}}
+; RES: 2.o,will_be_undefined,{{$}}
+; RES: 2.o,v1,{{$}}
+; RES: 2.o,r21,px{{$}}
+; RES: 2.o,r22,px{{$}}
+; RES: 2.o,a21,px{{$}}
+; RES: 2.o,a22,px{{$}}
+; RES: 2.o,a23,px{{$}}
+; RES: 2.o,a24,px{{$}}
+; RES: 2.o,a25,px{{$}}
+
+; f1's protected visibility should be reflected in the DSO.
+
+; OBJ:      Name: f1 (
+; OBJ-NEXT: Value:
+; OBJ-NEXT: Size:
+; OBJ-NEXT: Binding:
+; OBJ-NEXT: Type:
+; OBJ-NEXT: Other [
+; OBJ-NEXT:   STV_PROTECTED
+; OBJ-NEXT: ]

Modified: llvm/trunk/test/tools/gold/X86/common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/common.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/common.ll (original)
+++ llvm/trunk/test/tools/gold/X86/common.ll Thu Aug 11 07:56:40 2016
@@ -11,7 +11,7 @@
 ; RUN: llvm-dis %t3.o -o - | FileCheck %s --check-prefix=A
 
 ; Shared library case, we merge @a as common and keep it for the symbol table.
-; A: @a = common global i32 0, align 8
+; A: @a = common global [4 x i8] zeroinitializer, align 8
 
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=emit-llvm \
@@ -19,7 +19,7 @@
 ; RUN: llvm-dis %t3.o -o - | FileCheck %s --check-prefix=B
 
 ; (i16 align 8) + (i8 align 16) = i16 align 16
-; B: @a = common global i16 0, align 16
+; B: @a = common global [2 x i8] zeroinitializer, align 16
 
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=emit-llvm \
@@ -27,7 +27,7 @@
 ; RUN: llvm-dis %t3.o -o - | FileCheck %s --check-prefix=C
 
 ; (i16 align 8) + (i8 align 1) = i16 align 8.
-; C: @a = common global i16 0, align 8
+; C: @a = common global [2 x i8] zeroinitializer, align 8
 
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=emit-llvm \
@@ -35,7 +35,7 @@
 ; RUN: llvm-dis %t3.o -o - | FileCheck --check-prefix=EXEC %s
 
 ; All IR case, we internalize a after merging.
-; EXEC: @a = internal global i32 0, align 8
+; EXEC: @a = internal global [4 x i8] zeroinitializer, align 8
 
 ; RUN: llc %p/Inputs/common.ll -o %t2native.o -filetype=obj
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
@@ -44,4 +44,4 @@
 ; RUN: llvm-dis %t3.o -o - | FileCheck --check-prefix=MIXED %s
 
 ; Mixed ELF and IR. We keep ours as common so the linker will finish the merge.
-; MIXED: @a = common global i16 0, align 8
+; MIXED: @a = common global [2 x i8] zeroinitializer, align 8

Modified: llvm/trunk/test/tools/gold/X86/emit-llvm.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/emit-llvm.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/emit-llvm.ll (original)
+++ llvm/trunk/test/tools/gold/X86/emit-llvm.ll Thu Aug 11 07:56:40 2016
@@ -2,17 +2,16 @@
 
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=emit-llvm \
-; RUN:    --plugin-opt=generate-api-file \
 ; RUN:    -shared %t.o -o %t2.o
 ; RUN: llvm-dis %t2.o -o - | FileCheck %s
-; RUN: FileCheck --check-prefix=API %s < %T/../apifile.txt
 
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:     -m elf_x86_64 --plugin-opt=save-temps \
 ; RUN:    -shared %t.o -o %t3.o
-; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
-; RUN: llvm-dis %t3.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
-; RUN: llvm-dis %t3.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
+; RUN: FileCheck --check-prefix=RES %s < %t3.o.resolution.txt
+; RUN: llvm-dis %t3.o.2.internalize.bc -o - | FileCheck %s
+; RUN: llvm-dis %t3.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
+; RUN: llvm-dis %t3.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
 ; RUN: llvm-nm %t3.o.o | FileCheck --check-prefix=NM %s
 
 ; RUN: rm -f %t4.o
@@ -25,19 +24,19 @@
 
 target triple = "x86_64-unknown-linux-gnu"
 
-; CHECK-DAG: @g1 = linkonce_odr constant i32 32
+; CHECK-DAG: @g1 = weak_odr constant i32 32
 @g1 = linkonce_odr constant i32 32
 
-; CHECK-DAG: @g2 = internal local_unnamed_addr constant i32 32
+; CHECK-DAG: @g2 = internal constant i32 32
 @g2 = linkonce_odr local_unnamed_addr constant i32 32
 
 ; CHECK-DAG: @g3 = internal unnamed_addr constant i32 32
 @g3 = linkonce_odr unnamed_addr constant i32 32
 
-; CHECK-DAG: @g4 = linkonce_odr global i32 32
+; CHECK-DAG: @g4 = weak_odr global i32 32
 @g4 = linkonce_odr global i32 32
 
-; CHECK-DAG: @g5 = linkonce_odr local_unnamed_addr global i32 32
+; CHECK-DAG: @g5 = weak_odr global i32 32
 @g5 = linkonce_odr local_unnamed_addr global i32 32
 
 ; CHECK-DAG: @g6 = internal unnamed_addr global i32 32
@@ -75,8 +74,8 @@ define linkonce_odr void @f4() local_unn
   ret void
 }
 
-; CHECK-DAG: define linkonce_odr void @f5()
-; OPT-DAG: define linkonce_odr void @f5()
+; CHECK-DAG: define weak_odr void @f5()
+; OPT-DAG: define weak_odr void @f5()
 define linkonce_odr void @f5() {
   ret void
 }
@@ -97,15 +96,21 @@ define i32* @f8() {
   ret i32* @g8
 }
 
-; API: f1 PREVAILING_DEF_IRONLY
-; API: f2 PREVAILING_DEF_IRONLY
-; API: f3 PREVAILING_DEF_IRONLY_EXP
-; API: f4 PREVAILING_DEF_IRONLY_EXP
-; API: f5 PREVAILING_DEF_IRONLY_EXP
-; API: f6 PREVAILING_DEF_IRONLY_EXP
-; API: f7 PREVAILING_DEF_IRONLY_EXP
-; API: f8 PREVAILING_DEF_IRONLY_EXP
-; API: g7 UNDEF
-; API: g8 UNDEF
-; API: g9 PREVAILING_DEF_IRONLY_EXP
-; API: g10 PREVAILING_DEF_IRONLY_EXP
+; RES: .o,f1,pl{{$}}
+; RES: .o,f2,pl{{$}}
+; RES: .o,f3,px{{$}}
+; RES: .o,f4,p{{$}}
+; RES: .o,f5,px{{$}}
+; RES: .o,f6,p{{$}}
+; RES: .o,f7,px{{$}}
+; RES: .o,f8,px{{$}}
+; RES: .o,g1,px{{$}}
+; RES: .o,g2,p{{$}}
+; RES: .o,g3,p{{$}}
+; RES: .o,g4,px{{$}}
+; RES: .o,g5,px{{$}}
+; RES: .o,g6,p{{$}}
+; RES: .o,g7,{{$}}
+; RES: .o,g8,{{$}}
+; RES: .o,g9,px{{$}}
+; RES: .o,g10,px{{$}}

Modified: llvm/trunk/test/tools/gold/X86/opt-level.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/opt-level.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/opt-level.ll (original)
+++ llvm/trunk/test/tools/gold/X86/opt-level.ll Thu Aug 11 07:56:40 2016
@@ -1,13 +1,13 @@
 ; RUN: llvm-as -o %t.bc %s
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
 ; RUN:    -plugin-opt=O0 -r -o %t.o %t.bc
-; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O0 %s
+; RUN: llvm-dis < %t.o.4.opt.bc -o - | FileCheck --check-prefix=CHECK-O0 %s
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
 ; RUN:    -plugin-opt=O1 -r -o %t.o %t.bc
-; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O1 %s
+; RUN: llvm-dis < %t.o.4.opt.bc -o - | FileCheck --check-prefix=CHECK-O1 %s
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so -plugin-opt=save-temps \
 ; RUN:    -plugin-opt=O2 -r -o %t.o %t.bc
-; RUN: llvm-dis < %t.o.opt.bc -o - | FileCheck --check-prefix=CHECK-O2 %s
+; RUN: llvm-dis < %t.o.4.opt.bc -o - | FileCheck --check-prefix=CHECK-O2 %s
 
 ; CHECK-O0: define internal void @foo(
 ; CHECK-O1: define internal void @foo(

Modified: llvm/trunk/test/tools/gold/X86/parallel.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/parallel.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/parallel.ll (original)
+++ llvm/trunk/test/tools/gold/X86/parallel.ll Thu Aug 11 07:56:40 2016
@@ -1,7 +1,8 @@
 ; RUN: llvm-as -o %t.bc %s
+; RUN: rm -f %t.opt.bc0 %t.opt.bc1 %t.o0 %t.o1
 ; RUN: env LD_PRELOAD=%llvmshlibdir/LLVMgold.so %gold -plugin %llvmshlibdir/LLVMgold.so -u foo -u bar -plugin-opt jobs=2 -plugin-opt save-temps -m elf_x86_64 -o %t %t.bc
-; RUN: llvm-dis %t.opt.bc0 -o - | FileCheck --check-prefix=CHECK-BC0 %s
-; RUN: llvm-dis %t.opt.bc1 -o - | FileCheck --check-prefix=CHECK-BC1 %s
+; RUN: llvm-dis %t.5.precodegen.bc -o - | FileCheck --check-prefix=CHECK-BC0 %s
+; RUN: llvm-dis %t.1.5.precodegen.bc -o - | FileCheck --check-prefix=CHECK-BC1 %s
 ; RUN: llvm-nm %t.o0 | FileCheck --check-prefix=CHECK0 %s
 ; RUN: llvm-nm %t.o1 | FileCheck --check-prefix=CHECK1 %s
 

Modified: llvm/trunk/test/tools/gold/X86/slp-vectorize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/slp-vectorize.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/slp-vectorize.ll (original)
+++ llvm/trunk/test/tools/gold/X86/slp-vectorize.ll Thu Aug 11 07:56:40 2016
@@ -3,7 +3,7 @@
 ; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=save-temps \
 ; RUN:    -shared %t.o -o %t2.o
-; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck %s
+; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s
 
 ; test that the vectorizer is run.
 ; CHECK: fadd <4 x float>

Modified: llvm/trunk/test/tools/gold/X86/start-lib-common.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/start-lib-common.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/start-lib-common.ll (original)
+++ llvm/trunk/test/tools/gold/X86/start-lib-common.ll Thu Aug 11 07:56:40 2016
@@ -19,4 +19,4 @@
 
 ; Check that the common symbol is not dropped completely, which was a regression
 ; in r262676.
-; CHECK: @x = common global i32 0
+; CHECK: @x = common global [4 x i8] zeroinitializer

Modified: llvm/trunk/test/tools/gold/X86/strip_names.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/strip_names.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/strip_names.ll (original)
+++ llvm/trunk/test/tools/gold/X86/strip_names.ll Thu Aug 11 07:56:40 2016
@@ -3,7 +3,7 @@
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=save-temps \
 ; RUN:    -shared %t.o -o %t2.o
-; RUN: llvm-dis %t2.o.bc -o - | FileCheck %s
+; RUN: llvm-dis %t2.o.2.internalize.bc -o - | FileCheck %s
 
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=emit-llvm \

Modified: llvm/trunk/test/tools/gold/X86/thinlto.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/thinlto.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/thinlto.ll (original)
+++ llvm/trunk/test/tools/gold/X86/thinlto.ll Thu Aug 11 07:56:40 2016
@@ -25,21 +25,23 @@
 ; RUN: llvm-bcanalyzer -dump %t2.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND2
 ; RUN: not test -e %t3
 
-; Ensure gold generates an index as well as a binary by default in ThinLTO mode.
+; Ensure gold generates an index as well as a binary with save-temps in ThinLTO mode.
 ; First force single-threaded mode
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
+; RUN:    --plugin-opt=save-temps \
 ; RUN:    --plugin-opt=thinlto \
 ; RUN:    --plugin-opt=jobs=1 \
 ; RUN:    -shared %t.o %t2.o -o %t4
-; RUN: llvm-bcanalyzer -dump %t4.thinlto.bc | FileCheck %s --check-prefix=COMBINED
+; RUN: llvm-bcanalyzer -dump %t4.index.bc | FileCheck %s --check-prefix=COMBINED
 ; RUN: llvm-nm %t4 | FileCheck %s --check-prefix=NM
 
 ; Next force multi-threaded mode
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
+; RUN:    --plugin-opt=save-temps \
 ; RUN:    --plugin-opt=thinlto \
 ; RUN:    --plugin-opt=jobs=2 \
 ; RUN:    -shared %t.o %t2.o -o %t4
-; RUN: llvm-bcanalyzer -dump %t4.thinlto.bc | FileCheck %s --check-prefix=COMBINED
+; RUN: llvm-bcanalyzer -dump %t4.index.bc | FileCheck %s --check-prefix=COMBINED
 ; RUN: llvm-nm %t4 | FileCheck %s --check-prefix=NM
 
 ; Test --plugin-opt=obj-path to ensure unique object files generated.
@@ -48,8 +50,8 @@
 ; RUN:    --plugin-opt=jobs=2 \
 ; RUN:    --plugin-opt=obj-path=%t5.o \
 ; RUN:    -shared %t.o %t2.o -o %t4
-; RUN: llvm-nm %t5.o0 | FileCheck %s --check-prefix=NM2
 ; RUN: llvm-nm %t5.o1 | FileCheck %s --check-prefix=NM2
+; RUN: llvm-nm %t5.o2 | FileCheck %s --check-prefix=NM2
 
 ; NM: T f
 ; NM2: T {{f|g}}

Modified: llvm/trunk/test/tools/gold/X86/thinlto_alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/thinlto_alias.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/thinlto_alias.ll (original)
+++ llvm/trunk/test/tools/gold/X86/thinlto_alias.ll Thu Aug 11 07:56:40 2016
@@ -14,8 +14,14 @@
 ; RUN:     --plugin-opt=save-temps \
 ; RUN:     -o %t3.o %t2.o %t.o
 ; RUN: llvm-nm %t3.o | FileCheck %s
-; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
-; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
+; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
+; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
+
+; This does not currently pass because the gold plugin now uses the
+; combined summary rather than the IRMover to change the module's linkage
+; during the ThinLTO backend. The internalization step implemented by IRMover
+; for preempted symbols has not yet been implemented for the combined summary.
+; XFAIL: *
 
 ; CHECK-NOT: U f
 ; OPT: define hidden void @weakfunc.llvm.0()

Modified: llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll (original)
+++ llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll Thu Aug 11 07:56:40 2016
@@ -6,7 +6,7 @@
 ; RUN:     --plugin-opt=-import-instr-limit=0 \
 ; RUN:     --plugin-opt=save-temps \
 ; RUN:     -o %t3.o %t2.o %t.o
-; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck %s
+; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s
 
 ; f() should be internalized and eliminated after inlining
 ; CHECK-NOT: @f()

Modified: llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll (original)
+++ llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll Thu Aug 11 07:56:40 2016
@@ -14,13 +14,13 @@
 ; RUN:     -shared \
 ; RUN:     -o %t3.o %t2.o %t.o
 ; RUN: llvm-nm %t3.o | FileCheck %s
-; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
-; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
+; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
+; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
 
 ; Ensure that f() is defined in resulting object file, and also
 ; confirm the weak linkage directly in the saved opt bitcode files.
 ; CHECK-NOT: U f
-; OPT: declare hidden void @f()
+; OPT-NOT: @f()
 ; OPT2: define weak_odr hidden void @f()
 
 target triple = "x86_64-unknown-linux-gnu"

Modified: llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll (original)
+++ llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll Thu Aug 11 07:56:40 2016
@@ -13,12 +13,17 @@
 ; RUN: llvm-nm %t3.o | FileCheck %s
 ; CHECK: weakfunc
 
-; All of the preempted functions should have been eliminated (the plugin will
-; not link them in).
-; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
+; Most of the preempted functions should have been eliminated (the plugin will
+; set linkage of odr functions to available_externally and linkonce functions
+; are removed by globaldce). FIXME: Need to introduce combined index linkage
+; that means "drop this function" so we can avoid importing linkonce functions
+; and drop weak functions.
+; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
+; OPT2-NOT: @
+; OPT2: @weakfunc
 ; OPT2-NOT: @
 
-; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
+; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
 
 target triple = "x86_64-unknown-linux-gnu"
 

Modified: llvm/trunk/test/tools/gold/X86/type-merge2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/type-merge2.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/type-merge2.ll (original)
+++ llvm/trunk/test/tools/gold/X86/type-merge2.ll Thu Aug 11 07:56:40 2016
@@ -3,7 +3,7 @@
 ; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=save-temps \
 ; RUN:    -shared %t.o %t2.o -o %t3.o
-; RUN: llvm-dis %t3.o.bc -o - | FileCheck %s
+; RUN: llvm-dis %t3.o.2.internalize.bc -o - | FileCheck %s
 
 %zed = type { i8 }
 define void @foo()  {

Modified: llvm/trunk/test/tools/gold/X86/vectorize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/vectorize.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/vectorize.ll (original)
+++ llvm/trunk/test/tools/gold/X86/vectorize.ll Thu Aug 11 07:56:40 2016
@@ -3,7 +3,7 @@
 ; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
 ; RUN:    --plugin-opt=save-temps \
 ; RUN:    -shared %t.o -o %t2.o
-; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck %s
+; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s
 
 ; test that the vectorizer is run.
 ; CHECK: fadd <4 x float>

Modified: llvm/trunk/test/tools/gold/X86/visibility.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/gold/X86/visibility.ll?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/test/tools/gold/X86/visibility.ll (original)
+++ llvm/trunk/test/tools/gold/X86/visibility.ll Thu Aug 11 07:56:40 2016
@@ -5,7 +5,7 @@
 ; RUN:    --plugin-opt=save-temps \
 ; RUN:    -shared %t.o %t2.o -o %t.so
 ; RUN: llvm-readobj -t %t.so | FileCheck %s
-; RUN: llvm-dis %t.so.bc -o - | FileCheck --check-prefix=IR %s
+; RUN: llvm-dis %t.so.2.internalize.bc -o - | FileCheck --check-prefix=IR %s
 
 ; CHECK:      Name: foo
 ; CHECK-NEXT: Value:
@@ -16,7 +16,7 @@
 ; CHECK-NEXT:   STV_PROTECTED
 ; CHECK-NEXT: ]
 
-; IR: define protected void @foo
+; IR: define void @foo
 
 define weak protected void @foo() {
   ret void

Added: llvm/trunk/test/tools/llvm-lto2/errors.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-lto2/errors.ll?rev=278330&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-lto2/errors.ll (added)
+++ llvm/trunk/test/tools/llvm-lto2/errors.ll Thu Aug 11 07:56:40 2016
@@ -0,0 +1,11 @@
+; RUN: llvm-as %s -o %t.bc
+; RUN: not llvm-lto2 -o %t2.o %t.bc 2>&1 | FileCheck --check-prefix=ERR1 %s
+; RUN: not llvm-lto2 -o %t2.o -r %t.bc,foo,p -r %t.bc,bar,p %t.bc 2>&1 | FileCheck --check-prefix=ERR2 %s
+; RUN: not llvm-lto2 -o %t2.o -r %t.bc,foo,q %t.bc 2>&1 | FileCheck --check-prefix=ERR3 %s
+; RUN: not llvm-lto2 -o %t2.o -r foo %t.bc 2>&1 | FileCheck --check-prefix=ERR4 %s
+
+; ERR1: missing symbol resolution for {{.*}}.bc,foo
+; ERR2: unused symbol resolution for {{.*}}.bc,bar
+; ERR3: invalid character q in resolution: {{.*}}.bc,foo
+; ERR4: invalid resolution: foo
+ at foo = global i32 0

Modified: llvm/trunk/tools/gold/gold-plugin.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/gold/gold-plugin.cpp?rev=278330&r1=278329&r2=278330&view=diff
==============================================================================
--- llvm/trunk/tools/gold/gold-plugin.cpp (original)
+++ llvm/trunk/tools/gold/gold-plugin.cpp Thu Aug 11 07:56:40 2016
@@ -12,44 +12,22 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ADT/StringSet.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Bitcode/ReaderWriter.h"
-#include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/CodeGen/ParallelCG.h"
 #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
-#include "llvm/IR/AutoUpgrade.h"
 #include "llvm/IR/Constants.h"
-#include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Verifier.h"
 #include "llvm/LTO/LTO.h"
-#include "llvm/Linker/IRMover.h"
-#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Object/IRObjectFile.h"
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
-#include "llvm/Support/Host.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/thread.h"
-#include "llvm/Transforms/IPO.h"
-#include "llvm/Transforms/IPO/FunctionImport.h"
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include "llvm/Transforms/Utils/FunctionImportUtils.h"
-#include "llvm/Transforms/Utils/GlobalStatus.h"
-#include "llvm/Transforms/Utils/ValueMapper.h"
 #include <list>
+#include <map>
 #include <plugin-api.h>
+#include <string>
 #include <system_error>
 #include <utility>
 #include <vector>
@@ -61,6 +39,7 @@
 #define LDPT_GET_SYMBOLS_V3 28
 
 using namespace llvm;
+using namespace lto;
 
 static ld_plugin_status discard_message(int level, const char *format, ...) {
   // Die loudly. Recent versions of Gold pass ld_plugin_message as the first
@@ -106,38 +85,17 @@ struct PluginInputFile {
 };
 
 struct ResolutionInfo {
-  uint64_t CommonSize = 0;
-  unsigned CommonAlign = 0;
-  bool IsLinkonceOdr = true;
-  GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::Global;
-  GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
-  bool CommonInternal = false;
-  bool UseCommon = false;
+  bool CanOmitFromDynSym = true;
+  bool DefaultVisibility = true;
 };
 
-/// Class to own information used by a task or during its cleanup for a
-/// ThinLTO backend instantiation.
-class ThinLTOTaskInfo {
-  /// The output stream the task will codegen into.
-  std::unique_ptr<raw_fd_ostream> OS;
-
-  /// The file name corresponding to the output stream, used during cleanup.
-  std::string Filename;
-
-  /// Flag indicating whether the output file is a temp file that must be
-  /// added to the cleanup list during cleanup.
-  bool TempOutFile;
-
-public:
-  ThinLTOTaskInfo(std::unique_ptr<raw_fd_ostream> OS, std::string Filename,
-                  bool TempOutFile)
-      : OS(std::move(OS)), Filename(std::move(Filename)),
-        TempOutFile(TempOutFile) {}
-
-  /// Performs task related cleanup activities that must be done
-  /// single-threaded (i.e. call backs to gold).
-  void cleanup();
+struct CommonResolution {
+  bool Prevailing = false;
+  bool VisibleToRegularObj = false;
+  uint64_t Size = 0;
+  unsigned Align = 0;
 };
+
 }
 
 static ld_plugin_add_symbols add_symbols = nullptr;
@@ -145,14 +103,16 @@ static ld_plugin_get_symbols get_symbols
 static ld_plugin_add_input_file add_input_file = nullptr;
 static ld_plugin_set_extra_library_path set_extra_library_path = nullptr;
 static ld_plugin_get_view get_view = nullptr;
+static bool IsExecutable = false;
 static Optional<Reloc::Model> RelocationModel;
 static std::string output_name = "";
 static std::list<claimed_file> Modules;
 static DenseMap<int, void *> FDToLeaderHandle;
 static StringMap<ResolutionInfo> ResInfo;
+static std::map<std::string, CommonResolution> Commons;
 static std::vector<std::string> Cleanup;
 static llvm::TargetOptions TargetOpts;
-static std::string DefaultTriple = sys::getDefaultTargetTriple();
+static size_t MaxTasks;
 
 namespace options {
   enum OutputType {
@@ -161,7 +121,6 @@ namespace options {
     OT_BC_ONLY,
     OT_SAVE_TEMPS
   };
-  static bool generate_api_file = false;
   static OutputType TheOutputType = OT_NORMAL;
   static unsigned OptLevel = 2;
   // Default parallelism of 0 used to indicate that user did not specify.
@@ -213,8 +172,6 @@ namespace options {
   // Additional options to pass into the code generator.
   // Note: This array will contain all plugin options which are not claimed
   // as plugin exclusive to pass to the code generator.
-  // For example, "generate-api-file" and "as"options are for the plugin
-  // use only and will not be passed.
   static std::vector<const char *> extra;
 
   static void process_plugin_option(const char *opt_)
@@ -223,9 +180,7 @@ namespace options {
       return;
     llvm::StringRef opt = opt_;
 
-    if (opt == "generate-api-file") {
-      generate_api_file = true;
-    } else if (opt.startswith("mcpu=")) {
+    if (opt.startswith("mcpu=")) {
       mcpu = opt.substr(strlen("mcpu="));
     } else if (opt.startswith("extra-library-path=")) {
       extra_library_path = opt.substr(strlen("extra_library_path="));
@@ -307,10 +262,15 @@ ld_plugin_status onload(ld_plugin_tv *tv
       switch (tv->tv_u.tv_val) {
       case LDPO_REL: // .o
       case LDPO_DYN: // .so
+        IsExecutable = false;
+        RelocationModel = Reloc::PIC_;
+        break;
       case LDPO_PIE: // position independent executable
+        IsExecutable = true;
         RelocationModel = Reloc::PIC_;
         break;
       case LDPO_EXEC: // .exe
+        IsExecutable = true;
         RelocationModel = Reloc::Static;
         break;
       default:
@@ -404,20 +364,6 @@ ld_plugin_status onload(ld_plugin_tv *tv
   return LDPS_OK;
 }
 
-static const GlobalObject *getBaseObject(const GlobalValue &GV) {
-  if (auto *GA = dyn_cast<GlobalAlias>(&GV))
-    return GA->getBaseObject();
-  return cast<GlobalObject>(&GV);
-}
-
-static bool shouldSkip(uint32_t Symflags) {
-  if (!(Symflags & object::BasicSymbolRef::SF_Global))
-    return true;
-  if (Symflags & object::BasicSymbolRef::SF_FormatSpecific)
-    return true;
-  return false;
-}
-
 static void diagnosticHandler(const DiagnosticInfo &DI) {
   if (const auto *BDI = dyn_cast<BitcodeDiagnosticInfo>(&DI)) {
     std::error_code EC = BDI->getError();
@@ -447,21 +393,18 @@ static void diagnosticHandler(const Diag
   message(Level, "LLVM gold plugin: %s",  ErrStorage.c_str());
 }
 
-static void diagnosticHandlerForContext(const DiagnosticInfo &DI,
-                                        void *Context) {
-  diagnosticHandler(DI);
+static void check(Error E, std::string Msg = "LLVM gold plugin") {
+  handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
+    message(LDPL_FATAL, "%s: %s", Msg.c_str(), EIB.message().c_str());
+    return Error::success();
+  });
 }
 
-static GlobalValue::VisibilityTypes
-getMinVisibility(GlobalValue::VisibilityTypes A,
-                 GlobalValue::VisibilityTypes B) {
-  if (A == GlobalValue::HiddenVisibility)
-    return A;
-  if (B == GlobalValue::HiddenVisibility)
-    return B;
-  if (A == GlobalValue::ProtectedVisibility)
-    return A;
-  return B;
+template <typename T> static T check(Expected<T> E) {
+  if (E)
+    return std::move(*E);
+  check(E.takeError());
+  return T();
 }
 
 /// Called by gold to see whether this file is one that our plugin can handle.
@@ -469,7 +412,6 @@ getMinVisibility(GlobalValue::Visibility
 /// possible.
 static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
                                         int *claimed) {
-  LLVMContext Context;
   MemoryBufferRef BufferRef;
   std::unique_ptr<MemoryBuffer> Buffer;
   if (get_view) {
@@ -498,22 +440,25 @@ static ld_plugin_status claim_file_hook(
     BufferRef = Buffer->getMemBufferRef();
   }
 
-  Context.setDiagnosticHandler(diagnosticHandlerForContext);
-  ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
-      object::IRObjectFile::create(BufferRef, Context);
-  std::error_code EC = ObjOrErr.getError();
-  if (EC == object::object_error::invalid_file_type ||
-      EC == object::object_error::bitcode_section_not_found)
-    return LDPS_OK;
-
   *claimed = 1;
 
-  if (EC) {
-    message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s",
-            EC.message().c_str());
-    return LDPS_ERR;
+  Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
+  if (!ObjOrErr) {
+    handleAllErrors(ObjOrErr.takeError(), [&](const ErrorInfoBase &EI) {
+      std::error_code EC = EI.convertToErrorCode();
+      if (EC == object::object_error::invalid_file_type ||
+          EC == object::object_error::bitcode_section_not_found)
+        *claimed = 0;
+      else
+        message(LDPL_ERROR,
+                "LLVM gold plugin has failed to create LTO module: %s",
+                EI.message().c_str());
+    });
+
+    return *claimed ? LDPS_ERR : LDPS_OK;
   }
-  std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr);
+
+  std::unique_ptr<InputFile> Obj = std::move(*ObjOrErr);
 
   Modules.resize(Modules.size() + 1);
   claimed_file &cf = Modules.back();
@@ -535,72 +480,52 @@ static ld_plugin_status claim_file_hook(
   cf.name = file->name;
   if (file->offset)
     cf.name += ".llvm." + std::to_string(file->offset) + "." +
-               sys::path::filename(Obj->getModule().getSourceFileName()).str();
+               sys::path::filename(Obj->getSourceFileName()).str();
 
   for (auto &Sym : Obj->symbols()) {
     uint32_t Symflags = Sym.getFlags();
-    if (shouldSkip(Symflags))
-      continue;
 
     cf.syms.push_back(ld_plugin_symbol());
     ld_plugin_symbol &sym = cf.syms.back();
     sym.version = nullptr;
+    StringRef Name = Sym.getName();
+    sym.name = strdup(Name.str().c_str());
 
-    SmallString<64> Name;
-    {
-      raw_svector_ostream OS(Name);
-      Sym.printName(OS);
-    }
-    sym.name = strdup(Name.c_str());
-
-    const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
+    ResolutionInfo &Res = ResInfo[Name];
 
-    ResolutionInfo &Res = ResInfo[sym.name];
+    Res.CanOmitFromDynSym &= Sym.canBeOmittedFromSymbolTable();
 
     sym.visibility = LDPV_DEFAULT;
-    if (GV) {
-      Res.UnnamedAddr =
-          GlobalValue::getMinUnnamedAddr(Res.UnnamedAddr, GV->getUnnamedAddr());
-      Res.IsLinkonceOdr &= GV->hasLinkOnceLinkage();
-      Res.Visibility = getMinVisibility(Res.Visibility, GV->getVisibility());
-      switch (GV->getVisibility()) {
-      case GlobalValue::DefaultVisibility:
-        break;
-      case GlobalValue::HiddenVisibility:
-        sym.visibility = LDPV_HIDDEN;
-        break;
-      case GlobalValue::ProtectedVisibility:
-        sym.visibility = LDPV_PROTECTED;
-        break;
-      }
+    GlobalValue::VisibilityTypes Vis = Sym.getVisibility();
+    if (Vis != GlobalValue::DefaultVisibility)
+      Res.DefaultVisibility = false;
+    switch (Vis) {
+    case GlobalValue::DefaultVisibility:
+      break;
+    case GlobalValue::HiddenVisibility:
+      sym.visibility = LDPV_HIDDEN;
+      break;
+    case GlobalValue::ProtectedVisibility:
+      sym.visibility = LDPV_PROTECTED;
+      break;
     }
 
     if (Symflags & object::BasicSymbolRef::SF_Undefined) {
       sym.def = LDPK_UNDEF;
-      if (GV && GV->hasExternalWeakLinkage())
+      if (Symflags & object::BasicSymbolRef::SF_Weak)
         sym.def = LDPK_WEAKUNDEF;
-    } else {
+    } else if (Symflags & object::BasicSymbolRef::SF_Common)
+      sym.def = LDPK_COMMON;
+    else if (Symflags & object::BasicSymbolRef::SF_Weak)
+      sym.def = LDPK_WEAKDEF;
+    else
       sym.def = LDPK_DEF;
-      if (GV) {
-        assert(!GV->hasExternalWeakLinkage() &&
-               !GV->hasAvailableExternallyLinkage() && "Not a declaration!");
-        if (GV->hasCommonLinkage())
-          sym.def = LDPK_COMMON;
-        else if (GV->isWeakForLinker())
-          sym.def = LDPK_WEAKDEF;
-      }
-    }
 
     sym.size = 0;
     sym.comdat_key = nullptr;
-    if (GV) {
-      const GlobalObject *Base = getBaseObject(*GV);
-      if (!Base)
-        message(LDPL_FATAL, "Unable to determine comdat of alias!");
-      const Comdat *C = Base->getComdat();
-      if (C)
-        sym.comdat_key = strdup(C->getName().str().c_str());
-    }
+    const Comdat *C = check(Sym.getComdat());
+    if (C)
+      sym.comdat_key = strdup(C->getName().str().c_str());
 
     sym.resolution = LDPR_UNKNOWN;
   }
@@ -615,39 +540,6 @@ static ld_plugin_status claim_file_hook(
   return LDPS_OK;
 }
 
-static void internalize(GlobalValue &GV) {
-  if (GV.isDeclarationForLinker())
-    return; // We get here if there is a matching asm definition.
-  if (!GV.hasLocalLinkage())
-    GV.setLinkage(GlobalValue::InternalLinkage);
-}
-
-static const char *getResolutionName(ld_plugin_symbol_resolution R) {
-  switch (R) {
-  case LDPR_UNKNOWN:
-    return "UNKNOWN";
-  case LDPR_UNDEF:
-    return "UNDEF";
-  case LDPR_PREVAILING_DEF:
-    return "PREVAILING_DEF";
-  case LDPR_PREVAILING_DEF_IRONLY:
-    return "PREVAILING_DEF_IRONLY";
-  case LDPR_PREEMPTED_REG:
-    return "PREEMPTED_REG";
-  case LDPR_PREEMPTED_IR:
-    return "PREEMPTED_IR";
-  case LDPR_RESOLVED_IR:
-    return "RESOLVED_IR";
-  case LDPR_RESOLVED_EXEC:
-    return "RESOLVED_EXEC";
-  case LDPR_RESOLVED_DYN:
-    return "RESOLVED_DYN";
-  case LDPR_PREVAILING_DEF_IRONLY_EXP:
-    return "PREVAILING_DEF_IRONLY_EXP";
-  }
-  llvm_unreachable("Unknown resolution");
-}
-
 static void freeSymName(ld_plugin_symbol &Sym) {
   free(Sym.name);
   free(Sym.comdat_key);
@@ -671,120 +563,27 @@ static const void *getSymbolsAndView(cla
   return View;
 }
 
-static std::unique_ptr<ModuleSummaryIndex>
-getModuleSummaryIndexForFile(claimed_file &F) {
-  const void *View = getSymbolsAndView(F);
-  if (!View)
-    return nullptr;
-
+static void addModule(LTO &Lto, claimed_file &F, const void *View) {
   MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), F.name);
+  Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
 
-  // Don't bother trying to build an index if there is no summary information
-  // in this bitcode file.
-  if (!object::ModuleSummaryIndexObjectFile::hasGlobalValueSummaryInMemBuffer(
-          BufferRef, diagnosticHandler))
-    return std::unique_ptr<ModuleSummaryIndex>(nullptr);
-
-  ErrorOr<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr =
-      object::ModuleSummaryIndexObjectFile::create(BufferRef,
-                                                   diagnosticHandler);
-
-  if (std::error_code EC = ObjOrErr.getError())
-    message(LDPL_FATAL,
-            "Could not read module summary index bitcode from file : %s",
-            EC.message().c_str());
-
-  object::ModuleSummaryIndexObjectFile &Obj = **ObjOrErr;
-
-  return Obj.takeIndex();
-}
-
-static std::unique_ptr<Module>
-getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View,
-                 StringRef Name, raw_fd_ostream *ApiFile,
-                 StringSet<> &Internalize, std::vector<GlobalValue *> &Keep,
-                 StringMap<unsigned> &Realign) {
-  MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), Name);
-  ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
-      object::IRObjectFile::create(BufferRef, Context);
-
-  if (std::error_code EC = ObjOrErr.getError())
+  if (!ObjOrErr)
     message(LDPL_FATAL, "Could not read bitcode from file : %s",
-            EC.message().c_str());
-
-  object::IRObjectFile &Obj = **ObjOrErr;
+            toString(ObjOrErr.takeError()).c_str());
 
-  Module &M = Obj.getModule();
-
-  M.materializeMetadata();
-  UpgradeDebugInfo(M);
-
-  SmallPtrSet<GlobalValue *, 8> Used;
-  collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+  InputFile &Obj = **ObjOrErr;
 
   unsigned SymNum = 0;
+  std::vector<SymbolResolution> Resols(F.syms.size());
   for (auto &ObjSym : Obj.symbols()) {
-    GlobalValue *GV = Obj.getSymbolGV(ObjSym.getRawDataRefImpl());
-    if (GV && GV->hasAppendingLinkage())
-      Keep.push_back(GV);
-
-    if (shouldSkip(ObjSym.getFlags()))
-      continue;
     ld_plugin_symbol &Sym = F.syms[SymNum];
+    SymbolResolution &R = Resols[SymNum];
     ++SymNum;
 
     ld_plugin_symbol_resolution Resolution =
         (ld_plugin_symbol_resolution)Sym.resolution;
 
-    if (options::generate_api_file)
-      *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n';
-
-    if (!GV) {
-      freeSymName(Sym);
-      continue; // Asm symbol.
-    }
-
     ResolutionInfo &Res = ResInfo[Sym.name];
-    if (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP && !Res.IsLinkonceOdr)
-      Resolution = LDPR_PREVAILING_DEF;
-
-    GV->setUnnamedAddr(Res.UnnamedAddr);
-    GV->setVisibility(Res.Visibility);
-
-    // Override gold's resolution for common symbols. We want the largest
-    // one to win.
-    if (GV->hasCommonLinkage()) {
-      if (Resolution == LDPR_PREVAILING_DEF_IRONLY)
-        Res.CommonInternal = true;
-
-      if (Resolution == LDPR_PREVAILING_DEF_IRONLY ||
-          Resolution == LDPR_PREVAILING_DEF)
-        Res.UseCommon = true;
-
-      const DataLayout &DL = GV->getParent()->getDataLayout();
-      uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType());
-      unsigned Align = GV->getAlignment();
-
-      if (Res.UseCommon && Size >= Res.CommonSize) {
-        // Take GV.
-        if (Res.CommonInternal)
-          Resolution = LDPR_PREVAILING_DEF_IRONLY;
-        else
-          Resolution = LDPR_PREVAILING_DEF;
-        cast<GlobalVariable>(GV)->setAlignment(
-            std::max(Res.CommonAlign, Align));
-      } else {
-        // Do not take GV, it's smaller than what we already have in the
-        // combined module.
-        Resolution = LDPR_PREEMPTED_IR;
-        if (Align > Res.CommonAlign)
-          // Need to raise the alignment though.
-          Realign[Sym.name] = Align;
-      }
-
-      Res.CommonSize = std::max(Res.CommonSize, Size);
-      Res.CommonAlign = std::max(Res.CommonAlign, Align);
-    }
 
     switch (Resolution) {
     case LDPR_UNKNOWN:
@@ -795,57 +594,48 @@ getModuleForFile(LLVMContext &Context, c
     case LDPR_RESOLVED_DYN:
     case LDPR_PREEMPTED_IR:
     case LDPR_PREEMPTED_REG:
-      break;
-
     case LDPR_UNDEF:
-      if (!GV->isDeclarationForLinker())
-        assert(GV->hasComdat());
       break;
 
-    case LDPR_PREVAILING_DEF_IRONLY: {
-      Keep.push_back(GV);
-      // The IR linker has to be able to map this value to a declaration,
-      // so we can only internalize after linking.
-      if (!Used.count(GV))
-        Internalize.insert(GV->getName());
+    case LDPR_PREVAILING_DEF_IRONLY:
+      R.Prevailing = true;
       break;
-    }
 
     case LDPR_PREVAILING_DEF:
-      Keep.push_back(GV);
-      // There is a non IR use, so we have to force optimizations to keep this.
-      switch (GV->getLinkage()) {
-      default:
-        break;
-      case GlobalValue::LinkOnceAnyLinkage:
-        GV->setLinkage(GlobalValue::WeakAnyLinkage);
-        break;
-      case GlobalValue::LinkOnceODRLinkage:
-        GV->setLinkage(GlobalValue::WeakODRLinkage);
-        break;
-      }
+      R.Prevailing = true;
+      R.VisibleToRegularObj = true;
       break;
 
-    case LDPR_PREVAILING_DEF_IRONLY_EXP: {
-      Keep.push_back(GV);
-      if (canBeOmittedFromSymbolTable(GV))
-        Internalize.insert(GV->getName());
+    case LDPR_PREVAILING_DEF_IRONLY_EXP:
+      R.Prevailing = true;
+      if (!Res.CanOmitFromDynSym)
+        R.VisibleToRegularObj = true;
       break;
     }
+
+    if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF &&
+        (IsExecutable || !Res.DefaultVisibility))
+      R.FinalDefinitionInLinkageUnit = true;
+
+    if (ObjSym.getFlags() & object::BasicSymbolRef::SF_Common) {
+      // We ignore gold's resolution for common symbols. A common symbol with
+      // the correct size and alignment is added to the module by the pre-opt
+      // module hook if any common symbol prevailed.
+      CommonResolution &CommonRes = Commons[ObjSym.getIRName()];
+      if (R.Prevailing) {
+        CommonRes.Prevailing = true;
+        CommonRes.VisibleToRegularObj = R.VisibleToRegularObj;
+      }
+      CommonRes.Size = std::max(CommonRes.Size, ObjSym.getCommonSize());
+      CommonRes.Align = std::max(CommonRes.Align, ObjSym.getCommonAlignment());
+      R.Prevailing = false;
     }
 
     freeSymName(Sym);
   }
 
-  return Obj.takeModule();
-}
-
-static void saveBCFile(StringRef Path, Module &M) {
-  std::error_code EC;
-  raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
-  if (EC)
-    message(LDPL_FATAL, "Failed to write the output file.");
-  WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ false);
+  check(Lto.add(std::move(*ObjOrErr), Resols),
+        std::string("Failed to link module ") + F.name);
 }
 
 static void recordFile(std::string Filename, bool TempOutFile) {
@@ -857,190 +647,6 @@ static void recordFile(std::string Filen
     Cleanup.push_back(Filename.c_str());
 }
 
-void ThinLTOTaskInfo::cleanup() {
-  // Close the output file descriptor before we pass it to gold.
-  OS->close();
-
-  recordFile(Filename, TempOutFile);
-}
-
-namespace {
-/// Class to manage optimization and code generation for a module, possibly
-/// in a thread (ThinLTO).
-class CodeGen {
-  /// The module for which this will generate code.
-  std::unique_ptr<llvm::Module> M;
-
-  /// The output stream to generate code into.
-  raw_fd_ostream *OS;
-
-  /// The task ID when this was invoked in a thread (ThinLTO).
-  int TaskID;
-
-  /// The module summary index for ThinLTO tasks.
-  const ModuleSummaryIndex *CombinedIndex;
-
-  /// The target machine for generating code for this module.
-  std::unique_ptr<TargetMachine> TM;
-
-  /// Filename to use as base when save-temps is enabled, used to get
-  /// a unique and identifiable save-temps output file for each ThinLTO backend.
-  std::string SaveTempsFilename;
-
-  /// Map from a module name to the corresponding buffer holding a view of the
-  /// bitcode provided via the get_view gold callback.
-  StringMap<MemoryBufferRef> *ModuleMap;
-
-  // Functions to import into this module.
-  FunctionImporter::ImportMapTy *ImportList;
-
-  // Map of globals defined in this module to their summary.
-  std::map<GlobalValue::GUID, GlobalValueSummary *> *DefinedGlobals;
-
-public:
-  /// Constructor used by full LTO.
-  CodeGen(std::unique_ptr<llvm::Module> M)
-      : M(std::move(M)), OS(nullptr), TaskID(-1), CombinedIndex(nullptr),
-        ModuleMap(nullptr) {
-    initTargetMachine();
-  }
-  /// Constructor used by ThinLTO.
-  CodeGen(std::unique_ptr<llvm::Module> M, raw_fd_ostream *OS, int TaskID,
-          const ModuleSummaryIndex *CombinedIndex, std::string Filename,
-          StringMap<MemoryBufferRef> *ModuleMap,
-          FunctionImporter::ImportMapTy *ImportList,
-          std::map<GlobalValue::GUID, GlobalValueSummary *> *DefinedGlobals)
-      : M(std::move(M)), OS(OS), TaskID(TaskID), CombinedIndex(CombinedIndex),
-        SaveTempsFilename(std::move(Filename)), ModuleMap(ModuleMap),
-        ImportList(ImportList), DefinedGlobals(DefinedGlobals) {
-    assert(options::thinlto == !!CombinedIndex &&
-           "Expected module summary index iff performing ThinLTO");
-    initTargetMachine();
-  }
-
-  /// Invoke LTO passes and the code generator for the module.
-  void runAll();
-
-  /// Invoke the actual code generation to emit Module's object to file.
-  void runCodegenPasses();
-
-private:
-  const Target *TheTarget;
-  std::string TripleStr;
-  std::string FeaturesString;
-  TargetOptions Options;
-
-  /// Create a target machine for the module. Must be unique for each
-  /// module/task.
-  void initTargetMachine();
-
-  std::unique_ptr<TargetMachine> createTargetMachine();
-
-  /// Run all LTO passes on the module.
-  void runLTOPasses();
-
-  /// Sets up output files necessary to perform optional multi-threaded
-  /// split code generation, and invokes the code generation implementation.
-  /// If BCFileName is not empty, saves bitcode for module partitions into
-  /// {BCFileName}0 .. {BCFileName}N.
-  void runSplitCodeGen(const SmallString<128> &BCFilename);
-};
-}
-
-static SubtargetFeatures getFeatures(Triple &TheTriple) {
-  SubtargetFeatures Features;
-  Features.getDefaultSubtargetFeatures(TheTriple);
-  for (const std::string &A : MAttrs)
-    Features.AddFeature(A);
-  return Features;
-}
-
-static CodeGenOpt::Level getCGOptLevel() {
-  switch (options::OptLevel) {
-  case 0:
-    return CodeGenOpt::None;
-  case 1:
-    return CodeGenOpt::Less;
-  case 2:
-    return CodeGenOpt::Default;
-  case 3:
-    return CodeGenOpt::Aggressive;
-  }
-  llvm_unreachable("Invalid optimization level");
-}
-
-void CodeGen::initTargetMachine() {
-  TripleStr = M->getTargetTriple();
-  Triple TheTriple(TripleStr);
-
-  std::string ErrMsg;
-  TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
-  if (!TheTarget)
-    message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());
-
-  SubtargetFeatures Features = getFeatures(TheTriple);
-  FeaturesString = Features.getString();
-  Options = InitTargetOptionsFromCodeGenFlags();
-
-  // Disable the new X86 relax relocations since gold might not support them.
-  // FIXME: Check the gold version or add a new option to enable them.
-  Options.RelaxELFRelocations = false;
-
-  TM = createTargetMachine();
-}
-
-std::unique_ptr<TargetMachine> CodeGen::createTargetMachine() {
-  CodeGenOpt::Level CGOptLevel = getCGOptLevel();
-
-  return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
-      TripleStr, options::mcpu, FeaturesString, Options, RelocationModel,
-      CodeModel::Default, CGOptLevel));
-}
-
-void CodeGen::runLTOPasses() {
-  M->setDataLayout(TM->createDataLayout());
-
-  if (CombinedIndex) {
-    // Apply summary-based LinkOnce/Weak resolution decisions.
-    thinLTOResolveWeakForLinkerModule(*M, *DefinedGlobals);
-
-    // Apply summary-based internalization decisions. Skip if there are no
-    // defined globals from the summary since not only is it unnecessary, but
-    // if this module did not have a summary section the internalizer will
-    // assert if it finds any definitions in this module that aren't in the
-    // DefinedGlobals set.
-    if (!DefinedGlobals->empty())
-      thinLTOInternalizeModule(*M, *DefinedGlobals);
-
-    // Create a loader that will parse the bitcode from the buffers
-    // in the ModuleMap.
-    ModuleLoader Loader(M->getContext(), *ModuleMap);
-
-    // Perform function importing.
-    FunctionImporter Importer(*CombinedIndex, Loader);
-    Importer.importFunctions(*M, *ImportList);
-  }
-
-  legacy::PassManager passes;
-  passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
-
-  PassManagerBuilder PMB;
-  PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()));
-  PMB.Inliner = createFunctionInliningPass();
-  // Unconditionally verify input since it is not verified before this
-  // point and has unknown origin.
-  PMB.VerifyInput = true;
-  PMB.VerifyOutput = !options::DisableVerify;
-  PMB.LoopVectorize = true;
-  PMB.SLPVectorize = true;
-  PMB.OptLevel = options::OptLevel;
-  if (options::thinlto)
-    PMB.populateThinLTOPassManager(passes);
-  else
-    PMB.populateLTOPassManager(passes);
-  passes.run(*M);
-}
-
 /// Open a file and return the new file descriptor given a base input
 /// file name, a flag indicating whether a temp file should be generated,
 /// and an optional task id. The new filename generated is
@@ -1066,220 +672,44 @@ static int openOutputFile(SmallString<12
   return FD;
 }
 
-void CodeGen::runCodegenPasses() {
-  assert(OS && "Output stream must be set before emitting to file");
-  legacy::PassManager CodeGenPasses;
-  if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
-                              TargetMachine::CGFT_ObjectFile))
-    report_fatal_error("Failed to setup codegen");
-  CodeGenPasses.run(*M);
-}
-
-void CodeGen::runSplitCodeGen(const SmallString<128> &BCFilename) {
-  SmallString<128> Filename;
-  // Note that openOutputFile will append a unique ID for each task
-  if (!options::obj_path.empty())
-    Filename = options::obj_path;
-  else if (options::TheOutputType == options::OT_SAVE_TEMPS)
-    Filename = output_name + ".o";
-
-  // Note that the default parallelism is 1 instead of the
-  // hardware_concurrency, as there are behavioral differences between
-  // parallelism levels (e.g. symbol ordering will be different, and some uses
-  // of inline asm currently have issues with parallelism >1).
-  unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1;
-
-  std::vector<SmallString<128>> Filenames(MaxThreads);
-  std::vector<SmallString<128>> BCFilenames(MaxThreads);
-  bool TempOutFile = Filename.empty();
-  {
-    // Open a file descriptor for each backend task. This is done in a block
-    // so that the output file descriptors are closed before gold opens them.
-    std::list<llvm::raw_fd_ostream> OSs;
-    std::vector<llvm::raw_pwrite_stream *> OSPtrs(MaxThreads);
-    for (unsigned I = 0; I != MaxThreads; ++I) {
-      int FD = openOutputFile(Filename, TempOutFile, Filenames[I],
-                              // Only append ID if there are multiple tasks.
-                              MaxThreads > 1 ? I : -1);
-      OSs.emplace_back(FD, true);
-      OSPtrs[I] = &OSs.back();
-    }
-
-    std::list<llvm::raw_fd_ostream> BCOSs;
-    std::vector<llvm::raw_pwrite_stream *> BCOSPtrs;
-    if (!BCFilename.empty() && MaxThreads > 1) {
-      for (unsigned I = 0; I != MaxThreads; ++I) {
-        int FD = openOutputFile(BCFilename, false, BCFilenames[I], I);
-        BCOSs.emplace_back(FD, true);
-        BCOSPtrs.push_back(&BCOSs.back());
-      }
-    }
-
-    // Run backend tasks.
-    splitCodeGen(std::move(M), OSPtrs, BCOSPtrs,
-                 [&]() { return createTargetMachine(); });
-  }
-
-  for (auto &Filename : Filenames)
-    recordFile(Filename.c_str(), TempOutFile);
-}
-
-void CodeGen::runAll() {
-  runLTOPasses();
-
-  SmallString<128> OptFilename;
-  if (options::TheOutputType == options::OT_SAVE_TEMPS) {
-    OptFilename = output_name;
-    // If the CodeGen client provided a filename, use it. Always expect
-    // a provided filename if we are in a task (i.e. ThinLTO backend).
-    assert(!SaveTempsFilename.empty() || TaskID == -1);
-    if (!SaveTempsFilename.empty())
-      OptFilename = SaveTempsFilename;
-    OptFilename += ".opt.bc";
-    saveBCFile(OptFilename, *M);
-  }
-
-  // If we are already in a thread (i.e. ThinLTO), just perform
-  // codegen passes directly.
-  if (TaskID >= 0)
-    runCodegenPasses();
-  // Otherwise attempt split code gen.
-  else
-    runSplitCodeGen(OptFilename);
-}
-
-/// Links the module in \p View from file \p F into the combined module
-/// saved in the IRMover \p L.
-static void linkInModule(LLVMContext &Context, IRMover &L, claimed_file &F,
-                         const void *View, StringRef Name,
-                         raw_fd_ostream *ApiFile, StringSet<> &Internalize,
-                         bool SetName = false) {
-  std::vector<GlobalValue *> Keep;
-  StringMap<unsigned> Realign;
-  std::unique_ptr<Module> M = getModuleForFile(Context, F, View, Name, ApiFile,
-                                               Internalize, Keep, Realign);
-  if (!M.get())
-    return;
-  if (!options::triple.empty())
-    M->setTargetTriple(options::triple.c_str());
-  else if (M->getTargetTriple().empty()) {
-    M->setTargetTriple(DefaultTriple);
-  }
-
-  // For ThinLTO we want to propagate the source file name to ensure
-  // we can create the correct global identifiers matching those in the
-  // original module.
-  if (SetName)
-    L.getModule().setSourceFileName(M->getSourceFileName());
-
-  if (Error E = L.move(std::move(M), Keep,
-                       [](GlobalValue &, IRMover::ValueAdder) {})) {
-    handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) {
-      message(LDPL_FATAL, "Failed to link module %s: %s", Name.str().c_str(),
-              EIB.message().c_str());
-    });
-  }
-
-  for (const auto &I : Realign) {
-    GlobalValue *Dst = L.getModule().getNamedValue(I.first());
-    if (!Dst)
+/// Add all required common symbols to M, which is expected to be the first
+/// combined module.
+static void addCommons(Module &M) {
+  for (auto &I : Commons) {
+    if (!I.second.Prevailing)
       continue;
-    cast<GlobalVariable>(Dst)->setAlignment(I.second);
+    ArrayType *Ty =
+        ArrayType::get(Type::getInt8Ty(M.getContext()), I.second.Size);
+    GlobalVariable *OldGV = M.getNamedGlobal(I.first);
+    auto *GV = new GlobalVariable(M, Ty, false, GlobalValue::CommonLinkage,
+                                  ConstantAggregateZero::get(Ty), "");
+    GV->setAlignment(I.second.Align);
+    if (OldGV) {
+      OldGV->replaceAllUsesWith(ConstantExpr::getBitCast(GV, OldGV->getType()));
+      GV->takeName(OldGV);
+      OldGV->eraseFromParent();
+    } else {
+      GV->setName(I.first);
+    }
+    // We may only internalize commons if there is a single LTO task because
+    // other native object files may require the common.
+    if (MaxTasks == 1 && !I.second.VisibleToRegularObj)
+      GV->setLinkage(GlobalValue::InternalLinkage);
   }
 }
 
-/// Perform the ThinLTO backend on a single module, invoking the LTO and codegen
-/// pipelines.
-static void thinLTOBackendTask(claimed_file &F, const void *View,
-                               StringRef Name, raw_fd_ostream *ApiFile,
-                               const ModuleSummaryIndex &CombinedIndex,
-                               raw_fd_ostream *OS, unsigned TaskID,
-                               StringMap<MemoryBufferRef> &ModuleMap,
-                               FunctionImporter::ImportMapTy &ImportList,
-                               std::map<GlobalValue::GUID, GlobalValueSummary *> &DefinedGlobals) {
-  // Need to use a separate context for each task
-  LLVMContext Context;
-  Context.setDiscardValueNames(options::TheOutputType !=
-                               options::OT_SAVE_TEMPS);
-  Context.enableDebugTypeODRUniquing(); // Merge debug info types.
-  Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);
-
-  std::unique_ptr<llvm::Module> NewModule(new llvm::Module(Name, Context));
-  IRMover L(*NewModule.get());
-
-  StringSet<> Dummy;
-  linkInModule(Context, L, F, View, Name, ApiFile, Dummy, true);
-  if (renameModuleForThinLTO(*NewModule, CombinedIndex))
-    message(LDPL_FATAL, "Failed to rename module for ThinLTO");
-
-  CodeGen codeGen(std::move(NewModule), OS, TaskID, &CombinedIndex, Name,
-                  &ModuleMap, &ImportList, &DefinedGlobals);
-  codeGen.runAll();
-}
-
-/// Launch each module's backend pipeline in a separate task in a thread pool.
-static void
-thinLTOBackends(raw_fd_ostream *ApiFile,
-                const ModuleSummaryIndex &CombinedIndex,
-                StringMap<MemoryBufferRef> &ModuleMap,
-                StringMap<FunctionImporter::ImportMapTy> &ImportLists,
-  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
-      &ModuleToDefinedGVSummaries) {
-  unsigned TaskCount = 0;
-  std::vector<ThinLTOTaskInfo> Tasks;
-  Tasks.reserve(Modules.size());
-  unsigned int MaxThreads = options::Parallelism
-                                ? options::Parallelism
-                                : thread::hardware_concurrency();
-
-  // Create ThreadPool in nested scope so that threads will be joined
-  // on destruction.
-  {
-    ThreadPool ThinLTOThreadPool(MaxThreads);
-    for (claimed_file &F : Modules) {
-      // Do all the gold callbacks in the main thread, since gold is not thread
-      // safe by default.
-      const void *View = getSymbolsAndView(F);
-      if (!View)
-        continue;
-
-      SmallString<128> Filename;
-      if (!options::obj_path.empty())
-        // Note that openOutputFile will append a unique ID for each task
-        Filename = options::obj_path;
-      else if (options::TheOutputType == options::OT_SAVE_TEMPS) {
-        // Use the input file name so that we get a unique and identifiable
-        // output file for each ThinLTO backend task.
-        Filename = F.name;
-        Filename += ".thinlto.o";
-      }
-      bool TempOutFile = Filename.empty();
-
-      SmallString<128> NewFilename;
-      int FD = openOutputFile(Filename, TempOutFile, NewFilename,
-                              // Only append the TaskID if we will use the
-                              // non-unique obj_path.
-                              !options::obj_path.empty() ? TaskCount : -1);
-      TaskCount++;
-      std::unique_ptr<raw_fd_ostream> OS =
-          llvm::make_unique<raw_fd_ostream>(FD, true);
-
-      // Enqueue the task
-      ThinLTOThreadPool.async(thinLTOBackendTask, std::ref(F), View, F.name,
-                              ApiFile, std::ref(CombinedIndex), OS.get(),
-                              TaskCount, std::ref(ModuleMap),
-                              std::ref(ImportLists[F.name]),
-                              std::ref(ModuleToDefinedGVSummaries[F.name]));
-
-      // Record the information needed by the task or during its cleanup
-      // to a ThinLTOTaskInfo instance. For information needed by the task
-      // the unique_ptr ownership is transferred to the ThinLTOTaskInfo.
-      Tasks.emplace_back(std::move(OS), NewFilename.c_str(), TempOutFile);
-    }
+static CodeGenOpt::Level getCGOptLevel() {
+  switch (options::OptLevel) {
+  case 0:
+    return CodeGenOpt::None;
+  case 1:
+    return CodeGenOpt::Less;
+  case 2:
+    return CodeGenOpt::Default;
+  case 3:
+    return CodeGenOpt::Aggressive;
   }
-
-  for (auto &Task : Tasks)
-    Task.cleanup();
+  llvm_unreachable("Invalid optimization level");
 }
 
 /// Parse the thinlto_prefix_replace option into the \p OldPrefix and
@@ -1293,266 +723,130 @@ static void getThinLTOOldAndNewPrefix(st
   NewPrefix = Split.second.str();
 }
 
-/// Given the original \p Path to an output file, replace any path
-/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
-/// resulting directory if it does not yet exist.
-static std::string getThinLTOOutputFile(const std::string &Path,
-                                        const std::string &OldPrefix,
-                                        const std::string &NewPrefix) {
-  if (OldPrefix.empty() && NewPrefix.empty())
-    return Path;
-  SmallString<128> NewPath(Path);
-  llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
-  StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
-  if (!ParentPath.empty()) {
-    // Make sure the new directory exists, creating it if necessary.
-    if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
-      llvm::errs() << "warning: could not create directory '" << ParentPath
-                   << "': " << EC.message() << '\n';
-  }
-  return NewPath.str();
-}
-
-/// Perform ThinLTO link, which creates the combined index file.
-/// Also, either launch backend threads or (under thinlto-index-only)
-/// emit individual index files for distributed backends and exit.
-static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
-  // Map from a module name to the corresponding buffer holding a view of the
-  // bitcode provided via the get_view gold callback.
-  StringMap<MemoryBufferRef> ModuleMap;
-  // Map to own RAII objects that manage the file opening and releasing
-  // interfaces with gold.
-  DenseMap<void *, std::unique_ptr<PluginInputFile>> HandleToInputFile;
-
-  // Keep track of symbols that must not be internalized because they
-  // are referenced outside of a single IR module.
-  DenseSet<GlobalValue::GUID> Preserve;
-
-  // Keep track of the prevailing copy for each GUID, for use in resolving
-  // weak linkages.
-  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
-
-  ModuleSummaryIndex CombinedIndex;
-  uint64_t NextModuleId = 0;
-  for (claimed_file &F : Modules) {
-    if (!HandleToInputFile.count(F.leader_handle))
-      HandleToInputFile.insert(std::make_pair(
-          F.leader_handle, llvm::make_unique<PluginInputFile>(F.handle)));
-    // Pass this into getModuleSummaryIndexForFile
-    const void *View = getSymbolsAndView(F);
-    if (!View)
-      continue;
-
-    MemoryBufferRef ModuleBuffer(StringRef((const char *)View, F.filesize),
-                                 F.name);
-    assert(ModuleMap.find(ModuleBuffer.getBufferIdentifier()) ==
-               ModuleMap.end() &&
-           "Expect unique Buffer Identifier");
-    ModuleMap[ModuleBuffer.getBufferIdentifier()] = ModuleBuffer;
-
-    std::unique_ptr<ModuleSummaryIndex> Index = getModuleSummaryIndexForFile(F);
-
-    // Use gold's symbol resolution information to identify symbols referenced
-    // by more than a single IR module (i.e. referenced by multiple IR modules
-    // or by a non-IR module). Cross references introduced by importing are
-    // checked separately via the export lists. Also track the prevailing copy
-    // for later symbol resolution.
-    for (auto &Sym : F.syms) {
-      ld_plugin_symbol_resolution Resolution =
-          (ld_plugin_symbol_resolution)Sym.resolution;
-      GlobalValue::GUID SymGUID = GlobalValue::getGUID(Sym.name);
-      if (Resolution != LDPR_PREVAILING_DEF_IRONLY)
-        Preserve.insert(SymGUID);
-
-      if (Index && (Resolution == LDPR_PREVAILING_DEF ||
-                    Resolution == LDPR_PREVAILING_DEF_IRONLY ||
-                    Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP))
-        PrevailingCopy[SymGUID] = Index->getGlobalValueSummary(SymGUID);
-    }
-
-    // Skip files without a module summary.
-    if (Index)
-      CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
-  }
-
-  // Collect for each module the list of function it defines (GUID ->
-  // Summary).
-  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
-      ModuleToDefinedGVSummaries(NextModuleId);
-  CombinedIndex.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
-
-  StringMap<FunctionImporter::ImportMapTy> ImportLists(NextModuleId);
-  StringMap<FunctionImporter::ExportSetTy> ExportLists(NextModuleId);
-  ComputeCrossModuleImport(CombinedIndex, ModuleToDefinedGVSummaries,
-                           ImportLists, ExportLists);
-
-  auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
-    const auto &Prevailing = PrevailingCopy.find(GUID);
-    assert(Prevailing != PrevailingCopy.end());
-    return Prevailing->second == S;
-  };
+static std::unique_ptr<LTO> createLTO() {
+  Config Conf;
+  ThinBackend Backend;
+  unsigned ParallelCodeGenParallelismLevel = 1;
 
-  // Callback for internalization, to prevent internalization of symbols
-  // that were not candidates initially, and those that are being imported
-  // (which introduces new cross references).
-  auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
-    const auto &ExportList = ExportLists.find(ModuleIdentifier);
-    return (ExportList != ExportLists.end() &&
-            ExportList->second.count(GUID)) ||
-           Preserve.count(GUID);
-  };
+  Conf.CPU = options::mcpu;
+  Conf.Options = InitTargetOptionsFromCodeGenFlags();
 
-  thinLTOResolveWeakForLinkerInIndex(
-      CombinedIndex, isPrevailing,
-      [](StringRef ModuleIdentifier, GlobalValue::GUID GUID,
-         GlobalValue::LinkageTypes NewLinkage) {});
-
-  // Use global summary-based analysis to identify symbols that can be
-  // internalized (because they aren't exported or preserved as per callback).
-  // Changes are made in the index, consumed in the ThinLTO backends.
-  thinLTOInternalizeAndPromoteInIndex(CombinedIndex, isExported);
-
-  if (options::thinlto_emit_imports_files && !options::thinlto_index_only)
-    message(LDPL_WARNING,
-            "thinlto-emit-imports-files ignored unless thinlto-index-only");
+  // Disable the new X86 relax relocations since gold might not support them.
+  // FIXME: Check the gold version or add a new option to enable them.
+  Conf.Options.RelaxELFRelocations = false;
 
+  Conf.MAttrs = MAttrs;
+  Conf.RelocModel = *RelocationModel;
+  Conf.CGOptLevel = getCGOptLevel();
+  Conf.DisableVerify = options::DisableVerify;
+  Conf.OptLevel = options::OptLevel;
+  if (options::Parallelism) {
+    if (options::thinlto)
+      Backend = createInProcessThinBackend(options::Parallelism);
+    else
+      ParallelCodeGenParallelismLevel = options::Parallelism;
+  }
   if (options::thinlto_index_only) {
-    // If the thinlto-prefix-replace option was specified, parse it and
-    // extract the old and new prefixes.
     std::string OldPrefix, NewPrefix;
     getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
+    Backend = createWriteIndexesThinBackend(
+        OldPrefix, NewPrefix, options::thinlto_emit_imports_files,
+        options::thinlto_linked_objects_file);
+  }
 
-    // If the user requested a list of objects gold included in the link,
-    // create and open the requested file.
-    raw_fd_ostream *ObjFileOS = nullptr;
-    if (!options::thinlto_linked_objects_file.empty()) {
-      std::error_code EC;
-      ObjFileOS = new raw_fd_ostream(options::thinlto_linked_objects_file, EC,
-                                     sys::fs::OpenFlags::F_None);
-      if (EC)
-        message(LDPL_FATAL, "Unable to open %s for writing: %s",
-                options::thinlto_linked_objects_file.c_str(),
-                EC.message().c_str());
-    }
-    // For each input bitcode file, generate an individual index that
-    // contains summaries only for its own global values, and for any that
-    // should be imported.
-    for (claimed_file &F : Modules) {
-      std::error_code EC;
+  Conf.OverrideTriple = options::triple;
+  Conf.DefaultTriple = sys::getDefaultTargetTriple();
 
-      std::string NewModulePath =
-          getThinLTOOutputFile(F.name, OldPrefix, NewPrefix);
+  Conf.DiagHandler = diagnosticHandler;
 
-      if (!options::thinlto_linked_objects_file.empty()) {
-        // If gold included any symbols from ths file in the link, emit path
-        // to the final object file, which should be included in the final
-        // native link.
-        if (get_symbols(F.handle, F.syms.size(), F.syms.data()) !=
-            LDPS_NO_SYMS) {
-          assert(ObjFileOS);
-          *ObjFileOS << NewModulePath << "\n";
-        }
-      }
+  Conf.PreOptModuleHook = [](size_t Task, Module &M) {
+    if (Task == 0)
+      addCommons(M);
+    return true;
+  };
 
-      raw_fd_ostream OS((Twine(NewModulePath) + ".thinlto.bc").str(), EC,
-                        sys::fs::OpenFlags::F_None);
-      if (EC)
-        message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
-                NewModulePath.c_str(), EC.message().c_str());
-      // Build a map of module to the GUIDs and summary objects that should
-      // be written to its index.
-      std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
-      gatherImportedSummariesForModule(F.name, ModuleToDefinedGVSummaries,
-                                       ImportLists, ModuleToSummariesForIndex);
-      WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex);
-
-      if (options::thinlto_emit_imports_files) {
-        if ((EC = EmitImportsFiles(F.name,
-                                   (Twine(NewModulePath) + ".imports").str(),
-                                   ImportLists)))
-          message(LDPL_FATAL, "Unable to open %s.imports",
-                  NewModulePath.c_str(), EC.message().c_str());
-      }
-    }
+  switch (options::TheOutputType) {
+  case options::OT_NORMAL:
+    break;
 
-    if (ObjFileOS)
-      ObjFileOS->close();
+  case options::OT_DISABLE:
+    Conf.PreOptModuleHook = [](size_t Task, Module &M) { return false; };
+    break;
 
-    cleanup_hook();
-    exit(0);
-  }
+  case options::OT_BC_ONLY:
+    Conf.PostInternalizeModuleHook = [](size_t Task, Module &M) {
+      std::error_code EC;
+      raw_fd_ostream OS(output_name, EC, sys::fs::OpenFlags::F_None);
+      if (EC)
+        message(LDPL_FATAL, "Failed to write the output file.");
+      WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ false);
+      return false;
+    };
+    break;
 
-  // Create OS in nested scope so that it will be closed on destruction.
-  {
-    std::error_code EC;
-    raw_fd_ostream OS(output_name + ".thinlto.bc", EC,
-                      sys::fs::OpenFlags::F_None);
-    if (EC)
-      message(LDPL_FATAL, "Unable to open %s.thinlto.bc for writing: %s",
-              output_name.data(), EC.message().c_str());
-    WriteIndexToFile(CombinedIndex, OS);
+  case options::OT_SAVE_TEMPS:
+    check(Conf.addSaveTemps(output_name));
+    break;
   }
 
-  thinLTOBackends(ApiFile, CombinedIndex, ModuleMap, ImportLists,
-                  ModuleToDefinedGVSummaries);
-  return LDPS_OK;
+  return make_unique<LTO>(std::move(Conf), Backend,
+                          ParallelCodeGenParallelismLevel);
 }
 
 /// gold informs us that all symbols have been read. At this point, we use
 /// get_symbols to see if any of our definitions have been overridden by a
 /// native object file. Then, perform optimization and codegen.
-static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
+static ld_plugin_status allSymbolsReadHook() {
   if (Modules.empty())
     return LDPS_OK;
 
   if (unsigned NumOpts = options::extra.size())
     cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
 
-  if (options::thinlto)
-    return thinLTOLink(ApiFile);
+  std::unique_ptr<LTO> Lto = createLTO();
 
-  LLVMContext Context;
-  Context.setDiscardValueNames(options::TheOutputType !=
-                               options::OT_SAVE_TEMPS);
-  Context.enableDebugTypeODRUniquing(); // Merge debug info types.
-  Context.setDiagnosticHandler(diagnosticHandlerForContext, nullptr, true);
-
-  std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));
-  IRMover L(*Combined);
-
-  StringSet<> Internalize;
   for (claimed_file &F : Modules) {
-    // RAII object to manage the file opening and releasing interfaces with
-    // gold.
     PluginInputFile InputFile(F.handle);
     const void *View = getSymbolsAndView(F);
     if (!View)
       continue;
-    linkInModule(Context, L, F, View, F.name, ApiFile, Internalize);
+    addModule(*Lto, F, View);
   }
 
-  for (const auto &Name : Internalize) {
-    GlobalValue *GV = Combined->getNamedValue(Name.first());
-    if (GV)
-      internalize(*GV);
-  }
+  SmallString<128> Filename;
+  // Note that openOutputFile will append a unique ID for each task
+  if (!options::obj_path.empty())
+    Filename = options::obj_path;
+  else if (options::TheOutputType == options::OT_SAVE_TEMPS)
+    Filename = output_name + ".o";
+  bool SaveTemps = !Filename.empty();
 
-  if (options::TheOutputType == options::OT_DISABLE)
+  MaxTasks = Lto->getMaxTasks();
+  std::vector<uintptr_t> IsTemporary(MaxTasks);
+  std::vector<SmallString<128>> Filenames(MaxTasks);
+
+  auto AddStream = [&](size_t Task) {
+    int FD = openOutputFile(Filename, /*TempOutFile=*/!SaveTemps,
+                            Filenames[Task], MaxTasks > 1 ? Task : -1);
+    IsTemporary[Task] = !SaveTemps;
+
+    return make_unique<llvm::raw_fd_ostream>(FD, true);
+  };
+
+  check(Lto->run(AddStream));
+
+  if (options::TheOutputType == options::OT_DISABLE ||
+      options::TheOutputType == options::OT_BC_ONLY)
     return LDPS_OK;
 
-  if (options::TheOutputType != options::OT_NORMAL) {
-    std::string path;
-    if (options::TheOutputType == options::OT_BC_ONLY)
-      path = output_name;
-    else
-      path = output_name + ".bc";
-    saveBCFile(path, *Combined);
-    if (options::TheOutputType == options::OT_BC_ONLY)
-      return LDPS_OK;
+  if (options::thinlto_index_only) {
+    cleanup_hook();
+    exit(0);
   }
 
-  CodeGen codeGen(std::move(Combined));
-  codeGen.runAll();
+  for (unsigned I = 0; I != MaxTasks; ++I)
+    if (!Filenames[I].empty())
+      recordFile(Filenames[I].str(), IsTemporary[I]);
 
   if (!options::extra_library_path.empty() &&
       set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK)
@@ -1562,18 +856,7 @@ static ld_plugin_status allSymbolsReadHo
 }
 
 static ld_plugin_status all_symbols_read_hook(void) {
-  ld_plugin_status Ret;
-  if (!options::generate_api_file) {
-    Ret = allSymbolsReadHook(nullptr);
-  } else {
-    std::error_code EC;
-    raw_fd_ostream ApiFile("apifile.txt", EC, sys::fs::F_None);
-    if (EC)
-      message(LDPL_FATAL, "Unable to open apifile.txt for writing: %s",
-              EC.message().c_str());
-    Ret = allSymbolsReadHook(&ApiFile);
-  }
-
+  ld_plugin_status Ret = allSymbolsReadHook();
   llvm_shutdown();
 
   if (options::TheOutputType == options::OT_BC_ONLY ||

Added: llvm/trunk/tools/llvm-lto2/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto2/CMakeLists.txt?rev=278330&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-lto2/CMakeLists.txt (added)
+++ llvm/trunk/tools/llvm-lto2/CMakeLists.txt Thu Aug 11 07:56:40 2016
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  LTO
+  Object
+  Support
+  )
+
+add_llvm_tool(llvm-lto2
+  llvm-lto2.cpp
+  )

Copied: llvm/trunk/tools/llvm-lto2/LLVMBuild.txt (from r278309, llvm/trunk/lib/LTO/LLVMBuild.txt)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto2/LLVMBuild.txt?p2=llvm/trunk/tools/llvm-lto2/LLVMBuild.txt&p1=llvm/trunk/lib/LTO/LLVMBuild.txt&r1=278309&r2=278330&rev=278330&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/LLVMBuild.txt (original)
+++ llvm/trunk/tools/llvm-lto2/LLVMBuild.txt Thu Aug 11 07:56:40 2016
@@ -1,4 +1,4 @@
-;===- ./lib/LTO/LLVMBuild.txt ----------------------------------*- Conf -*--===;
+;===- ./tools/llvm-lto2/LLVMBuild.txt --------------------------*- Conf -*--===;
 ;
 ;                     The LLVM Compiler Infrastructure
 ;
@@ -16,22 +16,7 @@
 ;===------------------------------------------------------------------------===;
 
 [component_0]
-type = Library
-name = LTO
-parent = Libraries
-required_libraries =
- Analysis
- BitReader
- BitWriter
- CodeGen
- Core
- IPO
- InstCombine
- Linker
- MC
- ObjCARC
- Object
- Scalar
- Support
- Target
- TransformUtils
\ No newline at end of file
+type = Tool
+name = llvm-lto2
+parent = Tools
+required_libraries = LTO Object all-targets

Added: llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp?rev=278330&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp (added)
+++ llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp Thu Aug 11 07:56:40 2016
@@ -0,0 +1,168 @@
+//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program takes in a list of bitcode files, links them and performs
+// link-time optimization according to the provided symbol resolutions using the
+// resolution-based LTO interface, and outputs one or more object files.
+//
+// This program is intended to eventually replace llvm-lto which uses the legacy
+// LTO interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/LTO/LTO.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace llvm;
+using namespace lto;
+using namespace object;
+
+static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
+                                            cl::desc("<input bitcode files>"));
+
+static cl::opt<std::string> OutputFilename("o", cl::Required,
+                                           cl::desc("Output filename"),
+                                           cl::value_desc("filename"));
+
+static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
+
+static cl::list<std::string> SymbolResolutions(
+    "r",
+    cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
+             "where \"resolution\" is a sequence (which may be empty) of the\n"
+             "following characters:\n"
+             " p - prevailing: the linker has chosen this definition of the\n"
+             "     symbol\n"
+             " l - local: the definition of this symbol is unpreemptable at\n"
+             "     runtime and is known to be in this linkage unit\n"
+             " x - externally visible: the definition of this symbol is\n"
+             "     visible outside of the LTO unit\n"
+             "A resolution for each symbol must be specified."),
+    cl::ZeroOrMore);
+
+static void check(Error E, std::string Msg) {
+  if (!E)
+    return;
+  handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
+    errs() << "llvm-lto: " << Msg << ": " << EIB.message().c_str() << '\n';
+  });
+  exit(1);
+}
+
+template <typename T> static T check(Expected<T> E, std::string Msg) {
+  if (E)
+    return std::move(*E);
+  check(E.takeError(), Msg);
+  return T();
+}
+
+static void check(std::error_code EC, std::string Msg) {
+  check(errorCodeToError(EC), Msg);
+}
+
+template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
+  if (E)
+    return std::move(*E);
+  check(E.getError(), Msg);
+  return T();
+}
+
+int main(int argc, char **argv) {
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmPrinters();
+  InitializeAllAsmParsers();
+
+  cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
+
+  std::map<std::pair<std::string, std::string>, SymbolResolution>
+      CommandLineResolutions;
+  for (std::string R : SymbolResolutions) {
+    StringRef Rest = R;
+    StringRef FileName, SymbolName;
+    std::tie(FileName, Rest) = Rest.split(',');
+    if (Rest.empty()) {
+      llvm::errs() << "invalid resolution: " << R << '\n';
+      return 1;
+    }
+    std::tie(SymbolName, Rest) = Rest.split(',');
+    SymbolResolution Res;
+    for (char C : Rest) {
+      if (C == 'p')
+        Res.Prevailing = true;
+      else if (C == 'l')
+        Res.FinalDefinitionInLinkageUnit = true;
+      else if (C == 'x')
+        Res.VisibleToRegularObj = true;
+      else
+        llvm::errs() << "invalid character " << C << " in resolution: " << R
+                     << '\n';
+    }
+    CommandLineResolutions[{FileName, SymbolName}] = Res;
+  }
+
+  std::vector<std::unique_ptr<MemoryBuffer>> MBs;
+
+  Config Conf;
+  Conf.DiagHandler = [](const DiagnosticInfo &) {
+    exit(1);
+  };
+
+  if (SaveTemps)
+    check(Conf.addSaveTemps(OutputFilename), "Config::addSaveTemps failed");
+
+  LTO Lto(std::move(Conf));
+
+  bool HasErrors = false;
+  for (std::string F : InputFilenames) {
+    std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
+    std::unique_ptr<InputFile> Input =
+        check(InputFile::create(MB->getMemBufferRef()), F);
+
+    std::vector<SymbolResolution> Res;
+    for (const InputFile::Symbol &Sym : Input->symbols()) {
+      auto I = CommandLineResolutions.find({F, Sym.getName()});
+      if (I == CommandLineResolutions.end()) {
+        llvm::errs() << argv[0] << ": missing symbol resolution for " << F
+                     << ',' << Sym.getName() << '\n';
+        HasErrors = true;
+      } else {
+        Res.push_back(I->second);
+        CommandLineResolutions.erase(I);
+      }
+    }
+
+    if (HasErrors)
+      continue;
+
+    MBs.push_back(std::move(MB));
+    check(Lto.add(std::move(Input), Res), F);
+  }
+
+  if (!CommandLineResolutions.empty()) {
+    HasErrors = true;
+    for (auto UnusedRes : CommandLineResolutions)
+      llvm::errs() << argv[0] << ": unused symbol resolution for "
+                   << UnusedRes.first.first << ',' << UnusedRes.first.second
+                   << '\n';
+  }
+  if (HasErrors)
+    return 1;
+
+  auto AddStream = [&](size_t Task) {
+    std::string Path = OutputFilename + "." + utostr(Task);
+    std::error_code EC;
+    auto S = make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
+    check(EC, Path);
+    return S;
+  };
+
+  check(Lto.run(AddStream), "LTO::run failed");
+}




More information about the llvm-commits mailing list