summaryrefslogtreecommitdiff
path: root/lld/wasm/LTO.cpp
diff options
context:
space:
mode:
authorSam Clegg <sbc@chromium.org>2018-05-30 18:07:52 +0000
committerSam Clegg <sbc@chromium.org>2018-05-30 18:07:52 +0000
commit6d5090ee80a0e3b49cc6f1c28de86db670a197ad (patch)
treeebc59a632c78205293cd07334c466ddf5507b590 /lld/wasm/LTO.cpp
parent98ea1af48c504308ae328bfb6033bc30b9c2809c (diff)
[WebAssembly] Initial support for LTO
Differential Revision: https://reviews.llvm.org/D47162
Diffstat (limited to 'lld/wasm/LTO.cpp')
-rw-r--r--lld/wasm/LTO.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/lld/wasm/LTO.cpp b/lld/wasm/LTO.cpp
new file mode 100644
index 00000000000..58f32aaf244
--- /dev/null
+++ b/lld/wasm/LTO.cpp
@@ -0,0 +1,151 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Strings.h"
+#include "lld/Common/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::wasm;
+
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config C;
+ C.Options = InitTargetOptionsFromCodeGenFlags();
+
+ // Always emit a section per function/datum with LTO.
+ C.Options.FunctionSections = true;
+ C.Options.DataSections = true;
+
+ C.DisableVerify = Config->DisableVerify;
+ C.DiagHandler = diagnosticHandler;
+ C.OptLevel = Config->LTOO;
+
+ if (Config->SaveTemps)
+ checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
+ /*UseInputModulePath*/ true));
+
+ lto::ThinBackend Backend;
+ if (Config->ThinLTOJobs != -1U)
+ Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(C), Backend,
+ Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+ if (isa<DefinedFunction>(S))
+ replaceSymbol<UndefinedFunction>(S, S->getName(), 0);
+ else if (isa<DefinedData>(S))
+ replaceSymbol<UndefinedData>(S, S->getName(), 0);
+ else
+ llvm_unreachable("unexpected symbol kind");
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ ArrayRef<Symbol *> Syms = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(Syms.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ Symbol *Sym = Syms[SymNum];
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F;
+ R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj;
+ if (R.Prevailing)
+ undefine(Sym);
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buf.resize(MaxTasks);
+ Files.resize(MaxTasks);
+
+ // The --thinlto-cache-dir option specifies the path to a directory in which
+ // to cache native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->ThinLTOCacheDir.empty())
+ Cache = check(
+ lto::localCache(Config->ThinLTOCacheDir,
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buf[Task]));
+ },
+ Cache));
+
+ if (!Config->ThinLTOCacheDir.empty())
+ pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
+
+ std::vector<StringRef> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buf[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buf[I], Config->OutputFile + ".lto.o");
+ else
+ saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o");
+ }
+ Ret.emplace_back(Buf[I].data(), Buf[I].size());
+ }
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(File->getBuffer());
+
+ return Ret;
+}