llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Vassil Vassilev (vgvassilev) <details> <summary>Changes</summary> This commit introduces support for running clang-repl and executing C++ code interactively inside a Javascript engine using WebAssembly when built with Emscripten. This is achieved by producing WASM "shared libraries" that can be loaded by the Emscripten runtime using dlopen() More discussion is available in https://reviews.llvm.org/D158140 --- Full diff: https://github.com/llvm/llvm-project/pull/86402.diff 6 Files Affected: - (modified) clang/lib/Interpreter/CMakeLists.txt (+1) - (modified) clang/lib/Interpreter/IncrementalExecutor.cpp (+2) - (modified) clang/lib/Interpreter/IncrementalExecutor.h (+7-4) - (modified) clang/lib/Interpreter/Interpreter.cpp (+13-2) - (added) clang/lib/Interpreter/Wasm.cpp (+111) - (added) clang/lib/Interpreter/Wasm.h (+33) ``````````diff diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 9065f998f73c47..9d302d995801d5 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -20,6 +20,7 @@ add_clang_library(clangInterpreter Interpreter.cpp InterpreterUtils.cpp Value.cpp + Wasm.cpp DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 40bcef94797d43..5180905c9e6d24 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -35,6 +35,8 @@ LLVM_ATTRIBUTE_USED void linkComponents() { } namespace clang { +IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC) + : TSCtx(TSC) {} IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index dd0a210a061415..958be66efc3281 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -41,16 +41,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::Error &Err, const clang::TargetInfo &TI); - ~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 7fa52f2f15fc49..18c76685636855 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -15,6 +15,7 @@ #include "IncrementalExecutor.h" #include "IncrementalParser.h" #include "InterpreterUtils.h" +#include "Wasm.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" @@ -183,6 +184,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(); @@ -373,14 +380,18 @@ Interpreter::Parse(llvm::StringRef Code) { } llvm::Error Interpreter::CreateExecutor() { - const clang::TargetInfo &TI = - getCompilerInstance()->getASTContext().getTargetInfo(); if (IncrExecutor) return llvm::make_error<llvm::StringError>("Operation failed. " "Execution engine exists", std::error_code()); llvm::Error Err = llvm::Error::success(); + const clang::TargetInfo &TI = + getCompilerInstance()->getASTContext().getTargetInfo(); +#ifdef __EMSCRIPTEN__ + auto Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx, Err, TI); +#else auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI); +#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 00000000000000..cb455f111ea888 --- /dev/null +++ b/clang/lib/Interpreter/Wasm.cpp @@ -0,0 +1,111 @@ +//===----------------- 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. +// +//===----------------------------------------------------------------------===// + +#ifdef __EMSCRIPTEN__ + +#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 <dlfcn.h> + +namespace clang { + +WasmIncrementalExecutor::WasmIncrementalExecutor( + llvm::orc::ThreadSafeContext &TSC) + : IncrementalExecutor(TSC) {} + +llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { + PTU.TheModule->dump(); + + 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::CGFT_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 + +#endif __EMSCRIPTEN__ diff --git a/clang/lib/Interpreter/Wasm.h b/clang/lib/Interpreter/Wasm.h new file mode 100644 index 00000000000000..98acd4c14e240b --- /dev/null +++ b/clang/lib/Interpreter/Wasm.h @@ -0,0 +1,33 @@ +//===------------------ 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 + +#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 `````````` </details> https://github.com/llvm/llvm-project/pull/86402 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits