[llvm] r278338 - Restore "Resolution-based LTO API."
Teresa Johnson via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 11 07:58:13 PDT 2016
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");
+}
More information about the llvm-commits
mailing list