diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -18,6 +18,7 @@ Interpreter.cpp InterpreterUtils.cpp Value.cpp + WASM.cpp DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -41,16 +41,19 @@ llvm::DenseMap 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 getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const; diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -34,6 +34,8 @@ } 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/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -16,6 +16,7 @@ #include "DeviceOffload.h" #include "IncrementalExecutor.h" #include "IncrementalParser.h" +#include "WASM.h" #include "InterpreterUtils.h" #include "clang/AST/ASTContext.h" @@ -185,6 +186,12 @@ std::vector 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()); return IncrementalCompilerBuilder::create(Argv); @@ -250,7 +257,6 @@ // can't find the precise resource directory in unittests so we have to hard // code them. const char *const Runtimes = R"( - void* operator new(__SIZE_TYPE__, void* __p) noexcept; void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*); void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*); void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*); @@ -361,10 +367,14 @@ } llvm::Error Interpreter::CreateExecutor() { + llvm::Error Err = llvm::Error::success(); +#ifdef __EMSCRIPTEN__ + auto Executor = std::make_unique(*TSCtx); +#else const clang::TargetInfo &TI = getCompilerInstance()->getASTContext().getTargetInfo(); - llvm::Error Err = llvm::Error::success(); auto Executor = std::make_unique(*TSCtx, Err, TI); +#endif if (!Err) IncrExecutor = std::move(Executor); diff --git a/clang/lib/Interpreter/WASM.h b/clang/lib/Interpreter/WASM.h new file mode 100644 --- /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 diff --git a/clang/lib/Interpreter/WASM.cpp b/clang/lib/Interpreter/WASM.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Interpreter/WASM.cpp @@ -0,0 +1,107 @@ +//===----------------- 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 +#include +#include +#include + +#include + +#include + +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("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( + "WASM backend cannot produce object.", llvm::inconvertibleErrorCode()); + } + + if (!PM.run(*PTU.TheModule)) { + + return llvm::make_error("Failed to emit WASM object.", + llvm::inconvertibleErrorCode()); + } + + OutputFile.close(); + + std::vector 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( + "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( + "Failed to load incremental module", llvm::inconvertibleErrorCode()); + } + + return llvm::Error::success(); +} + +llvm::Error WASMIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) { + return llvm::make_error("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