diff options
Diffstat (limited to 'include/lld')
20 files changed, 350 insertions, 22 deletions
diff --git a/include/lld/Common/Args.h b/include/lld/Common/Args.h new file mode 100644 index 0000000000000..c49a6a7e17e75 --- /dev/null +++ b/include/lld/Common/Args.h @@ -0,0 +1,35 @@ +//===- Args.h ---------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ARGS_H +#define LLD_ARGS_H + +#include "lld/Common/LLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include <vector> + +namespace llvm { +namespace opt { +class InputArgList; +} +} // namespace llvm + +namespace lld { +namespace args { +int getInteger(llvm::opt::InputArgList &Args, unsigned Key, int Default); +std::vector<StringRef> getStrings(llvm::opt::InputArgList &Args, int Id); + +uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key, + uint64_t Default); + +std::vector<StringRef> getLines(MemoryBufferRef MB); +} // namespace args +} // namespace lld + +#endif diff --git a/include/lld/Driver/Driver.h b/include/lld/Common/Driver.h index 4ba0994e88b9b..15ec3cd44cb55 100644 --- a/include/lld/Driver/Driver.h +++ b/include/lld/Common/Driver.h @@ -1,4 +1,4 @@ -//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===// +//===- lld/Common/Driver.h - Linker Driver Emulator -----------------------===// // // The LLVM Linker // @@ -7,14 +7,19 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_DRIVER_DRIVER_H -#define LLD_DRIVER_DRIVER_H +#ifndef LLD_COMMON_DRIVER_H +#define LLD_COMMON_DRIVER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/raw_ostream.h" namespace lld { namespace coff { +bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, + llvm::raw_ostream &Diag = llvm::errs()); +} + +namespace mingw { bool link(llvm::ArrayRef<const char *> Args, llvm::raw_ostream &Diag = llvm::errs()); } @@ -28,6 +33,11 @@ namespace mach_o { bool link(llvm::ArrayRef<const char *> Args, llvm::raw_ostream &Diag = llvm::errs()); } + +namespace wasm { +bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, + llvm::raw_ostream &Diag = llvm::errs()); +} } #endif diff --git a/include/lld/Common/ErrorHandler.h b/include/lld/Common/ErrorHandler.h new file mode 100644 index 0000000000000..8ae6f46ac59e1 --- /dev/null +++ b/include/lld/Common/ErrorHandler.h @@ -0,0 +1,112 @@ +//===- ErrorHandler.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// In LLD, we have three levels of errors: fatal, error or warn. +// +// Fatal makes the program exit immediately with an error message. +// You shouldn't use it except for reporting a corrupted input file. +// +// Error prints out an error message and increment a global variable +// ErrorCount to record the fact that we met an error condition. It does +// not exit, so it is safe for a lld-as-a-library use case. It is generally +// useful because it can report more than one error in a single run. +// +// Warn doesn't do anything but printing out a given message. +// +// It is not recommended to use llvm::outs() or llvm::errs() directly +// in LLD because they are not thread-safe. The functions declared in +// this file are mutually excluded, so you want to use them instead. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COMMON_ERRORHANDLER_H +#define LLD_COMMON_ERRORHANDLER_H + +#include "lld/Common/LLVM.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" + +namespace lld { + +class ErrorHandler { +public: + uint64_t ErrorCount = 0; + uint64_t ErrorLimit = 20; + StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now"; + StringRef LogName = "lld"; + llvm::raw_ostream *ErrorOS = &llvm::errs(); + bool ColorDiagnostics = llvm::errs().has_colors(); + bool ExitEarly = true; + bool FatalWarnings = false; + bool Verbose = false; + + void error(const Twine &Msg); + LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); + void log(const Twine &Msg); + void message(const Twine &Msg); + void warn(const Twine &Msg); + + std::unique_ptr<llvm::FileOutputBuffer> OutputBuffer; + +private: + void print(StringRef S, raw_ostream::Colors C); +}; + +/// Returns the default error handler. +ErrorHandler &errorHandler(); + +inline void error(const Twine &Msg) { errorHandler().error(Msg); } +inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) { + errorHandler().fatal(Msg); +} +inline void log(const Twine &Msg) { errorHandler().log(Msg); } +inline void message(const Twine &Msg) { errorHandler().message(Msg); } +inline void warn(const Twine &Msg) { errorHandler().warn(Msg); } +inline uint64_t errorCount() { return errorHandler().ErrorCount; } + +LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); + +// check functions are convenient functions to strip errors +// from error-or-value objects. +template <class T> T check(ErrorOr<T> E) { + if (auto EC = E.getError()) + fatal(EC.message()); + return std::move(*E); +} + +template <class T> T check(Expected<T> E) { + if (!E) + fatal(llvm::toString(E.takeError())); + return std::move(*E); +} + +template <class T> +T check2(ErrorOr<T> E, llvm::function_ref<std::string()> Prefix) { + if (auto EC = E.getError()) + fatal(Prefix() + ": " + EC.message()); + return std::move(*E); +} + +template <class T> +T check2(Expected<T> E, llvm::function_ref<std::string()> Prefix) { + if (!E) + fatal(Prefix() + ": " + toString(E.takeError())); + return std::move(*E); +} + +inline std::string toString(const Twine &S) { return S.str(); } + +// To evaluate the second argument lazily, we use C macro. +#define CHECK(E, S) check2(E, [&] { return toString(S); }) + +} // namespace lld + +#endif diff --git a/include/lld/Core/LLVM.h b/include/lld/Common/LLVM.h index ccf08859f4aeb..b5d0e2bffb038 100644 --- a/include/lld/Core/LLVM.h +++ b/include/lld/Common/LLVM.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_CORE_LLVM_H -#define LLD_CORE_LLVM_H +#ifndef LLD_COMMON_LLVM_H +#define LLD_COMMON_LLVM_H // This should be the only #include, force #includes of all the others on // clients. diff --git a/include/lld/Common/Memory.h b/include/lld/Common/Memory.h new file mode 100644 index 0000000000000..699f7c1654cd3 --- /dev/null +++ b/include/lld/Common/Memory.h @@ -0,0 +1,60 @@ +//===- Memory.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines arena allocators. +// +// Almost all large objects, such as files, sections or symbols, are +// used for the entire lifetime of the linker once they are created. +// This usage characteristic makes arena allocator an attractive choice +// where the entire linker is one arena. With an arena, newly created +// objects belong to the arena and freed all at once when everything is done. +// Arena allocators are efficient and easy to understand. +// Most objects are allocated using the arena allocators defined by this file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COMMON_MEMORY_H +#define LLD_COMMON_MEMORY_H + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/StringSaver.h" +#include <vector> + +namespace lld { + +// Use this arena if your object doesn't have a destructor. +extern llvm::BumpPtrAllocator BAlloc; +extern llvm::StringSaver Saver; + +void freeArena(); + +// These two classes are hack to keep track of all +// SpecificBumpPtrAllocator instances. +struct SpecificAllocBase { + SpecificAllocBase() { Instances.push_back(this); } + virtual ~SpecificAllocBase() = default; + virtual void reset() = 0; + static std::vector<SpecificAllocBase *> Instances; +}; + +template <class T> struct SpecificAlloc : public SpecificAllocBase { + void reset() override { Alloc.DestroyAll(); } + llvm::SpecificBumpPtrAllocator<T> Alloc; +}; + +// Use this arena if your object has a destructor. +// Your destructor will be invoked from freeArena(). +template <typename T, typename... U> T *make(U &&... Args) { + static SpecificAlloc<T> Alloc; + return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...); +} + +} // namespace lld + +#endif diff --git a/include/lld/Core/Reproduce.h b/include/lld/Common/Reproduce.h index 6e1d36a549160..0f425de269c7f 100644 --- a/include/lld/Core/Reproduce.h +++ b/include/lld/Common/Reproduce.h @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_CORE_REPRODUCE_H -#define LLD_CORE_REPRODUCE_H +#ifndef LLD_COMMON_REPRODUCE_H +#define LLD_COMMON_REPRODUCE_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -33,7 +33,7 @@ std::string quote(StringRef S); std::string rewritePath(StringRef S); // Returns the string form of the given argument. -std::string toString(llvm::opt::Arg *Arg); +std::string toString(const llvm::opt::Arg &Arg); } #endif diff --git a/include/lld/Common/Strings.h b/include/lld/Common/Strings.h new file mode 100644 index 0000000000000..1a63f75f9ecfe --- /dev/null +++ b/include/lld/Common/Strings.h @@ -0,0 +1,23 @@ +//===- Strings.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_STRINGS_H +#define LLD_STRINGS_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace lld { +// Returns a demangled C++ symbol name. If Name is not a mangled +// name, it returns Optional::None. +llvm::Optional<std::string> demangleItanium(llvm::StringRef Name); +} + +#endif diff --git a/include/lld/Core/TargetOptionsCommandFlags.h b/include/lld/Common/TargetOptionsCommandFlags.h index 9ba99d94b9572..9c4ff7cea3fb8 100644 --- a/include/lld/Core/TargetOptionsCommandFlags.h +++ b/include/lld/Common/TargetOptionsCommandFlags.h @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/Optional.h" #include "llvm/Support/CodeGen.h" #include "llvm/Target/TargetOptions.h" namespace lld { llvm::TargetOptions InitTargetOptionsFromCodeGenFlags(); -llvm::CodeModel::Model GetCodeModelFromCMModel(); +llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel(); } diff --git a/include/lld/Common/Threads.h b/include/lld/Common/Threads.h new file mode 100644 index 0000000000000..8545907531433 --- /dev/null +++ b/include/lld/Common/Threads.h @@ -0,0 +1,86 @@ +//===- Threads.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// LLD supports threads to distribute workloads to multiple cores. Using +// multicore is most effective when more than one core are idle. At the +// last step of a build, it is often the case that a linker is the only +// active process on a computer. So, we are naturally interested in using +// threads wisely to reduce latency to deliver results to users. +// +// That said, we don't want to do "too clever" things using threads. +// Complex multi-threaded algorithms are sometimes extremely hard to +// reason about and can easily mess up the entire design. +// +// Fortunately, when a linker links large programs (when the link time is +// most critical), it spends most of the time to work on massive number of +// small pieces of data of the same kind, and there are opportunities for +// large parallelism there. Here are examples: +// +// - We have hundreds of thousands of input sections that need to be +// copied to a result file at the last step of link. Once we fix a file +// layout, each section can be copied to its destination and its +// relocations can be applied independently. +// +// - We have tens of millions of small strings when constructing a +// mergeable string section. +// +// For the cases such as the former, we can just use parallelForEach +// instead of std::for_each (or a plain for loop). Because tasks are +// completely independent from each other, we can run them in parallel +// without any coordination between them. That's very easy to understand +// and reason about. +// +// For the cases such as the latter, we can use parallel algorithms to +// deal with massive data. We have to write code for a tailored algorithm +// for each problem, but the complexity of multi-threading is isolated in +// a single pass and doesn't affect the linker's overall design. +// +// The above approach seems to be working fairly well. As an example, when +// linking Chromium (output size 1.6 GB), using 4 cores reduces latency to +// 75% compared to single core (from 12.66 seconds to 9.55 seconds) on my +// Ivy Bridge Xeon 2.8 GHz machine. Using 40 cores reduces it to 63% (from +// 12.66 seconds to 7.95 seconds). Because of the Amdahl's law, the +// speedup is not linear, but as you add more cores, it gets faster. +// +// On a final note, if you are trying to optimize, keep the axiom "don't +// guess, measure!" in mind. Some important passes of the linker are not +// that slow. For example, resolving all symbols is not a very heavy pass, +// although it would be very hard to parallelize it. You want to first +// identify a slow pass and then optimize it. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COMMON_THREADS_H +#define LLD_COMMON_THREADS_H + +#include "llvm/Support/Parallel.h" +#include <functional> + +namespace lld { + +extern bool ThreadsEnabled; + +template <typename R, class FuncTy> void parallelForEach(R &&Range, FuncTy Fn) { + if (ThreadsEnabled) + for_each(llvm::parallel::par, std::begin(Range), std::end(Range), Fn); + else + for_each(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn); +} + +inline void parallelForEachN(size_t Begin, size_t End, + std::function<void(size_t)> Fn) { + if (ThreadsEnabled) + for_each_n(llvm::parallel::par, Begin, End, Fn); + else + for_each_n(llvm::parallel::seq, Begin, End, Fn); +} + +} // namespace lld + +#endif diff --git a/include/lld/Config/Version.h b/include/lld/Common/Version.h index 1cec3cc7678c4..93de77df5804e 100644 --- a/include/lld/Config/Version.h +++ b/include/lld/Common/Version.h @@ -1,4 +1,4 @@ -//===- lld/Config/Version.h - LLD Version Number ----------------*- C++ -*-===// +//===- lld/Common/Version.h - LLD Version Number ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,7 +14,7 @@ #ifndef LLD_VERSION_H #define LLD_VERSION_H -#include "lld/Config/Version.inc" +#include "lld/Common/Version.inc" #include "llvm/ADT/StringRef.h" namespace lld { diff --git a/include/lld/Config/Version.inc.in b/include/lld/Common/Version.inc.in index 2789a5c460892..2789a5c460892 100644 --- a/include/lld/Config/Version.inc.in +++ b/include/lld/Common/Version.inc.in diff --git a/include/lld/Core/Atom.h b/include/lld/Core/Atom.h index 156a5d4a736fe..149c3d5ee2c57 100644 --- a/include/lld/Core/Atom.h +++ b/include/lld/Core/Atom.h @@ -10,7 +10,7 @@ #ifndef LLD_CORE_ATOM_H #define LLD_CORE_ATOM_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/StringRef.h" namespace lld { diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h index 7f623d2ea5e63..6229d67e25a5e 100644 --- a/include/lld/Core/DefinedAtom.h +++ b/include/lld/Core/DefinedAtom.h @@ -10,9 +10,9 @@ #ifndef LLD_CORE_DEFINED_ATOM_H #define LLD_CORE_DEFINED_ATOM_H +#include "lld/Common/LLVM.h" #include "lld/Core/Atom.h" #include "lld/Core/Reference.h" -#include "lld/Core/LLVM.h" #include "llvm/Support/ErrorHandling.h" namespace lld { diff --git a/include/lld/Core/Error.h b/include/lld/Core/Error.h index b0bf73b1cb7b5..36a36724987a4 100644 --- a/include/lld/Core/Error.h +++ b/include/lld/Core/Error.h @@ -14,7 +14,7 @@ #ifndef LLD_CORE_ERROR_H #define LLD_CORE_ERROR_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Error.h" #include <system_error> diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h index b3a999b00fbd2..eb9510cbd215c 100644 --- a/include/lld/Core/LinkingContext.h +++ b/include/lld/Core/LinkingContext.h @@ -62,7 +62,7 @@ public: /// of DefinedAtoms that should be marked live (along with all Atoms they /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can /// be kept live using this method. - const std::vector<StringRef> &deadStripRoots() const { + ArrayRef<StringRef> deadStripRoots() const { return _deadStripRoots; } @@ -106,7 +106,7 @@ public: /// options which are used to configure LLVM's command line settings. /// For instance the -debug-only XXX option can be used to dynamically /// trace different parts of LLVM and lld. - const std::vector<const char *> &llvmOptions() const { return _llvmOptions; } + ArrayRef<const char *> llvmOptions() const { return _llvmOptions; } /// \name Methods used by Drivers to configure TargetInfo /// @{ diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h index 09b417a2985d6..2ea65ae13aceb 100644 --- a/include/lld/Core/PassManager.h +++ b/include/lld/Core/PassManager.h @@ -10,7 +10,7 @@ #ifndef LLD_CORE_PASS_MANAGER_H #define LLD_CORE_PASS_MANAGER_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "lld/Core/Pass.h" #include "llvm/Support/Error.h" #include <memory> diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h index 32d04249f3784..c7baf86af61fb 100644 --- a/include/lld/Core/Reader.h +++ b/include/lld/Core/Reader.h @@ -10,7 +10,7 @@ #ifndef LLD_CORE_READER_H #define LLD_CORE_READER_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "lld/Core/Reference.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Magic.h" diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h index ba4951e5bd133..9c39a6ed507c3 100644 --- a/include/lld/Core/SymbolTable.h +++ b/include/lld/Core/SymbolTable.h @@ -10,7 +10,7 @@ #ifndef LLD_CORE_SYMBOL_TABLE_H #define LLD_CORE_SYMBOL_TABLE_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringExtras.h" #include <cstring> diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h index 216f934916bc3..1f0ca4cda41f2 100644 --- a/include/lld/Core/Writer.h +++ b/include/lld/Core/Writer.h @@ -10,7 +10,7 @@ #ifndef LLD_CORE_WRITER_H #define LLD_CORE_WRITER_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/Support/Error.h" #include <memory> #include <vector> diff --git a/include/lld/ReaderWriter/YamlContext.h b/include/lld/ReaderWriter/YamlContext.h index b26161a154319..b97d21f68e55b 100644 --- a/include/lld/ReaderWriter/YamlContext.h +++ b/include/lld/ReaderWriter/YamlContext.h @@ -10,7 +10,7 @@ #ifndef LLD_READER_WRITER_YAML_CONTEXT_H #define LLD_READER_WRITER_YAML_CONTEXT_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include <functional> #include <memory> #include <vector> @@ -18,6 +18,7 @@ namespace lld { class File; class LinkingContext; +class Registry; namespace mach_o { namespace normalized { struct NormalizedFile; |
