[llvm] r278338 - Restore "Resolution-based LTO API."

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 29 11:55:25 PDT 2016


I have just finished reading this patch with an eye on seeing if it
would make sense to use it in lld.

I think it should work (and Davide has a wip patch), I think the only
thing that would be a bit odd is the GlobalResolutions StringMap. In
lld we try to have a single symbol table. Any objections to removing
GlobalResolutions and expecting each linker to track GlobalResolution?

Cheers,
Rafael

On 11 August 2016 at 10:58, Teresa Johnson via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: tejohnson
> Date: Thu Aug 11 09:58:12 2016
> New Revision: 278338
>
> URL: http://llvm.org/viewvc/llvm-project?rev=278338&view=rev
> Log:
> Restore "Resolution-based LTO API."
>
> This restores commit r278330, with fixes for a few bot failures:
> - Fix a late change I had made to the save temps output file that I
>   missed due to existing files sitting on my disk
> - Fix a bunch of Windows bot failures with "ambiguous call to overloaded
>   function" due to confusion between llvm::make_unique vs
>   std::make_unique (preface the new make_unique calls with "llvm::")
> - Attempt to fix a modules bot failure by adding a missing include
>   to LTO/Config.h.
>
> Original change:
>
> 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
>
> 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/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 r278331, llvm/trunk/test/tools/gold/X86/comdat.ll
>     llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg
>     llvm/trunk/test/tools/llvm-lto2/errors.ll
>     llvm/trunk/tools/llvm-lto2/CMakeLists.txt
>     llvm/trunk/tools/llvm-lto2/LLVMBuild.txt
>       - copied, changed from r278331, 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/include/llvm/LTO/Config.h (added)
> +++ llvm/trunk/include/llvm/LTO/Config.h Thu Aug 11 09:58:12 2016
> @@ -0,0 +1,172 @@
> +//===-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/Support/CodeGen.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, when
> +  /// UseInputModulePath is set to true.
> +  ///
> +  /// 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,
> +                     bool UseInputModulePath = false);
> +};
> +
> +/// 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/LTO/LTO.h (original)
> +++ llvm/trunk/include/llvm/LTO/LTO.h Thu Aug 11 09:58:12 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/include/llvm/LTO/LTOBackend.h (added)
> +++ llvm/trunk/include/llvm/LTO/LTOBackend.h Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/lib/LTO/CMakeLists.txt (original)
> +++ llvm/trunk/lib/LTO/CMakeLists.txt Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/lib/LTO/LLVMBuild.txt (original)
> +++ llvm/trunk/lib/LTO/LLVMBuild.txt Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/lib/LTO/LTO.cpp (original)
> +++ llvm/trunk/lib/LTO/LTO.cpp Thu Aug 11 09:58:12 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(llvm::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 llvm::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 = llvm::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 llvm::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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/lib/LTO/LTOBackend.cpp (added)
> +++ llvm/trunk/lib/LTO/LTOBackend.cpp Thu Aug 11 09:58:12 2016
> @@ -0,0 +1,284 @@
> +//===-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,
> +                           bool UseInputModulePath) {
> +  ShouldDiscardValueNames = false;
> +
> +  std::error_code EC;
> +  ResolutionFile = llvm::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;
> +      // If this is the combined module (not a ThinLTO backend compile) or the
> +      // user hasn't requested using the input module's path, emit to a file
> +      // named from the provided OutputFileName with the Task ID appended.
> +      if (M.getModuleIdentifier() == "ld-temp.o" || !UseInputModulePath) {
> +        PathPrefix = OutputFileName;
> +        if (Task != 0)
> +          PathPrefix += "." + utostr(Task);
> +      } else
> +        PathPrefix = M.getModuleIdentifier();
> +      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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Object/IRObjectFile.cpp (original)
> +++ llvm/trunk/lib/Object/IRObjectFile.cpp Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/CMakeLists.txt (original)
> +++ llvm/trunk/test/CMakeLists.txt Thu Aug 11 09:58:12 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=278338&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 09:58:12 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll (added)
> +++ llvm/trunk/test/LTO/Resolution/X86/Inputs/comdat.ll Thu Aug 11 09:58:12 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/test/LTO/Resolution/X86/alias.ll (added)
> +++ llvm/trunk/test/LTO/Resolution/X86/alias.ll Thu Aug 11 09:58:12 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 r278331, 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=278331&r2=278338&rev=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/comdat.ll (original)
> +++ llvm/trunk/test/LTO/Resolution/X86/comdat.ll Thu Aug 11 09:58:12 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg (added)
> +++ llvm/trunk/test/LTO/Resolution/X86/lit.local.cfg Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/lit.cfg (original)
> +++ llvm/trunk/test/lit.cfg Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/coff.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/coff.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/comdat.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/comdat.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/common.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/common.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/emit-llvm.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/emit-llvm.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/opt-level.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/opt-level.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/parallel.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/parallel.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/slp-vectorize.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/slp-vectorize.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&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 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/strip_names.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/strip_names.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/thinlto.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/thinlto.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/thinlto_alias.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/thinlto_alias.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/thinlto_internalize.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/thinlto_linkonceresolution.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&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 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/type-merge2.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/type-merge2.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/vectorize.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/vectorize.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/test/tools/gold/X86/visibility.ll (original)
> +++ llvm/trunk/test/tools/gold/X86/visibility.ll Thu Aug 11 09:58:12 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/test/tools/llvm-lto2/errors.ll (added)
> +++ llvm/trunk/test/tools/llvm-lto2/errors.ll Thu Aug 11 09:58:12 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=278338&r1=278337&r2=278338&view=diff
> ==============================================================================
> --- llvm/trunk/tools/gold/gold-plugin.cpp (original)
> +++ llvm/trunk/tools/gold/gold-plugin.cpp Thu Aug 11 09:58:12 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, /* UseInputModulePath */ true));
> +    break;
>    }
>
> -  thinLTOBackends(ApiFile, CombinedIndex, ModuleMap, ImportLists,
> -                  ModuleToDefinedGVSummaries);
> -  return LDPS_OK;
> +  return llvm::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 llvm::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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-lto2/CMakeLists.txt (added)
> +++ llvm/trunk/tools/llvm-lto2/CMakeLists.txt Thu Aug 11 09:58:12 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 r278331, 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=278331&r2=278338&rev=278338&view=diff
> ==============================================================================
> --- llvm/trunk/lib/LTO/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/llvm-lto2/LLVMBuild.txt Thu Aug 11 09:58:12 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=278338&view=auto
> ==============================================================================
> --- llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp (added)
> +++ llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp Thu Aug 11 09:58:12 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 = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
> +    check(EC, Path);
> +    return S;
> +  };
> +
> +  check(Lto.run(AddStream), "LTO::run failed");
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list