diff options
author | Sam Clegg <sbc@chromium.org> | 2018-05-30 18:07:52 +0000 |
---|---|---|
committer | Sam Clegg <sbc@chromium.org> | 2018-05-30 18:07:52 +0000 |
commit | 6d5090ee80a0e3b49cc6f1c28de86db670a197ad (patch) | |
tree | ebc59a632c78205293cd07334c466ddf5507b590 /lld/wasm/LTO.cpp | |
parent | 98ea1af48c504308ae328bfb6033bc30b9c2809c (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.cpp | 151 |
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; +} |