diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 9065f998f73c4..6a069659ebb8d 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -12,6 +12,10 @@ set(LLVM_LINK_COMPONENTS TargetParser ) +if (EMSCRIPTEN AND "lld" IN_LIST LLVM_ENABLE_PROJECTS) + set(WASM_SRC Wasm.cpp) +endif() + add_clang_library(clangInterpreter DeviceOffload.cpp CodeCompletion.cpp @@ -20,6 +24,8 @@ add_clang_library(clangInterpreter Interpreter.cpp InterpreterUtils.cpp Value.cpp + ${WASM_SRC} + PARTIAL_SOURCES_INTENDED DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 6f036107c14a9..1824a5b4570a9 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -36,6 +36,8 @@ LLVM_ATTRIBUTE_USED void linkComponents() { } namespace clang { +IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC) + : TSCtx(TSC) {} llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>> IncrementalExecutor::createDefaultJITBuilder( diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index b4347209e14fe..7954cde36588b 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -43,16 +43,19 @@ class IncrementalExecutor { llvm::DenseMap<const PartialTranslationUnit *, llvm::orc::ResourceTrackerSP> ResourceTrackers; +protected: + IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC); + public: enum SymbolNameKind { IRName, LinkerName }; IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err); - ~IncrementalExecutor(); + virtual ~IncrementalExecutor(); - llvm::Error addModule(PartialTranslationUnit &PTU); - llvm::Error removeModule(PartialTranslationUnit &PTU); - llvm::Error runCtors() const; + virtual llvm::Error addModule(PartialTranslationUnit &PTU); + virtual llvm::Error removeModule(PartialTranslationUnit &PTU); + virtual llvm::Error runCtors() const; llvm::Error cleanUp(); llvm::Expected<llvm::orc::ExecutorAddr> getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const; diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 7a95278914276..49dc92d60233a 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -15,6 +15,9 @@ #include "IncrementalExecutor.h" #include "IncrementalParser.h" #include "InterpreterUtils.h" +#ifdef __EMSCRIPTEN__ +#include "Wasm.h" +#endif // __EMSCRIPTEN__ #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" @@ -186,6 +189,12 @@ IncrementalCompilerBuilder::CreateCpp() { std::vector<const char *> Argv; Argv.reserve(5 + 1 + UserArgs.size()); Argv.push_back("-xc++"); +#ifdef __EMSCRIPTEN__ + Argv.push_back("-target"); + Argv.push_back("wasm32-unknown-emscripten"); + Argv.push_back("-pie"); + Argv.push_back("-shared"); +#endif Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end()); std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple(); @@ -426,8 +435,12 @@ llvm::Error Interpreter::CreateExecutor() { } llvm::Error Err = llvm::Error::success(); +#ifdef __EMSCRIPTEN__ + auto Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx); +#else auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Err); +#endif if (!Err) IncrExecutor = std::move(Executor); diff --git a/clang/lib/Interpreter/Wasm.cpp b/clang/lib/Interpreter/Wasm.cpp new file mode 100644 index 0000000000000..1001410aa0f27 --- /dev/null +++ b/clang/lib/Interpreter/Wasm.cpp @@ -0,0 +1,114 @@ +//===----------------- Wasm.cpp - Wasm Interpreter --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements interpreter support for code execution in WebAssembly. +// +//===----------------------------------------------------------------------===// + +#include "Wasm.h" +#include "IncrementalExecutor.h" + +#include <llvm/IR/LegacyPassManager.h> +#include <llvm/IR/Module.h> +#include <llvm/MC/TargetRegistry.h> +#include <llvm/Target/TargetMachine.h> + +#include <clang/Interpreter/Interpreter.h> + +#include <string> + +namespace lld { +namespace wasm { +bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +} // namespace wasm +} // namespace lld + +#include <dlfcn.h> + +namespace clang { + +WasmIncrementalExecutor::WasmIncrementalExecutor( + llvm::orc::ThreadSafeContext &TSC) + : IncrementalExecutor(TSC) {} + +llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { + std::string ErrorString; + + const llvm::Target *Target = llvm::TargetRegistry::lookupTarget( + PTU.TheModule->getTargetTriple(), ErrorString); + if (!Target) { + return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ", + llvm::inconvertibleErrorCode()); + } + + llvm::TargetOptions TO = llvm::TargetOptions(); + llvm::TargetMachine *TargetMachine = Target->createTargetMachine( + PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_); + PTU.TheModule->setDataLayout(TargetMachine->createDataLayout()); + std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm"; + + std::error_code Error; + llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error); + + llvm::legacy::PassManager PM; + if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr, + llvm::CodeGenFileType::ObjectFile)) { + return llvm::make_error<llvm::StringError>( + "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode()); + } + + if (!PM.run(*PTU.TheModule)) { + + return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.", + llvm::inconvertibleErrorCode()); + } + + OutputFile.close(); + + std::vector<const char *> LinkerArgs = {"wasm-ld", + "-pie", + "--import-memory", + "--no-entry", + "--export-all", + "--experimental-pic", + "--no-export-dynamic", + "--stack-first", + OutputFileName.c_str(), + "-o", + OutputFileName.c_str()}; + int Result = + lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false); + if (!Result) + return llvm::make_error<llvm::StringError>( + "Failed to link incremental module", llvm::inconvertibleErrorCode()); + + void *LoadedLibModule = + dlopen(OutputFileName.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (LoadedLibModule == nullptr) { + llvm::errs() << dlerror() << '\n'; + return llvm::make_error<llvm::StringError>( + "Failed to load incremental module", llvm::inconvertibleErrorCode()); + } + + return llvm::Error::success(); +} + +llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) { + return llvm::make_error<llvm::StringError>("Not implemented yet", + llvm::inconvertibleErrorCode()); +} + +llvm::Error WasmIncrementalExecutor::runCtors() const { + // This seems to be automatically done when using dlopen() + return llvm::Error::success(); +} + +WasmIncrementalExecutor::~WasmIncrementalExecutor() = default; + +} // namespace clang diff --git a/clang/lib/Interpreter/Wasm.h b/clang/lib/Interpreter/Wasm.h new file mode 100644 index 0000000000000..b1fd88024f14d --- /dev/null +++ b/clang/lib/Interpreter/Wasm.h @@ -0,0 +1,37 @@ +//===------------------ Wasm.h - Wasm Interpreter ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements interpreter support for code execution in WebAssembly. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INTERPRETER_WASM_H +#define LLVM_CLANG_LIB_INTERPRETER_WASM_H + +#ifndef __EMSCRIPTEN__ +#error "This requires emscripten." +#endif // __EMSCRIPTEN__ + +#include "IncrementalExecutor.h" + +namespace clang { + +class WasmIncrementalExecutor : public IncrementalExecutor { +public: + WasmIncrementalExecutor(llvm::orc::ThreadSafeContext &TSC); + + llvm::Error addModule(PartialTranslationUnit &PTU) override; + llvm::Error removeModule(PartialTranslationUnit &PTU) override; + llvm::Error runCtors() const override; + + ~WasmIncrementalExecutor() override; +}; + +} // namespace clang + +#endif // LLVM_CLANG_LIB_INTERPRETER_WASM_H