diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/ReplaceStackPointer.cpp | 103 | ||||
-rw-r--r-- | src/passes/pass.cpp | 4 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | src/tools/wasm-emscripten-finalize.cpp | 4 | ||||
-rw-r--r-- | src/wasm-emscripten.h | 4 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 57 |
7 files changed, 112 insertions, 62 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index 654c1c797..a3eede8ff 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -61,6 +61,7 @@ set(passes_SOURCES RemoveImports.cpp RemoveMemory.cpp RemoveNonJSOps.cpp + ReplaceStackPointer.cpp RemoveUnusedBrs.cpp RemoveUnusedNames.cpp RemoveUnusedModuleElements.cpp diff --git a/src/passes/ReplaceStackPointer.cpp b/src/passes/ReplaceStackPointer.cpp new file mode 100644 index 000000000..d6a85c3e2 --- /dev/null +++ b/src/passes/ReplaceStackPointer.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Convert llvm's stack pointer usage from from global.get/global.set into +// cals to external stackSave/stackRestore. +// This is needed to emscripten SIDE_MODULE code where mutable global imports +// are not yet permitted by default. +// + +#include "abi/js.h" +#include "ir/import-utils.h" +#include "pass.h" +#include "support/debug.h" +#include "wasm-emscripten.h" + +#define DEBUG_TYPE "binary" + +namespace wasm { + +static Name STACK_SAVE("stackSave"); +static Name STACK_RESTORE("stackRestore"); + +struct ReplaceStackPointer + : public WalkerPass<PostWalker<ReplaceStackPointer>> { + void visitGlobalGet(GlobalGet* curr) { + if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { + needStackSave = true; + if (!builder) { + builder = make_unique<Builder>(*getModule()); + } + replaceCurrent(builder->makeCall(STACK_SAVE, {}, Type::i32)); + } + } + + void visitGlobalSet(GlobalSet* curr) { + if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { + needStackRestore = true; + if (!builder) { + builder = make_unique<Builder>(*getModule()); + } + replaceCurrent( + builder->makeCall(STACK_RESTORE, {curr->value}, Type::none)); + } + } + + void doWalkModule(Module* module) { + stackPointer = getStackPointerGlobal(*module); + if (!stackPointer) { + BYN_DEBUG(std::cerr << "no stack pointer found\n"); + return; + } + BYN_DEBUG(std::cerr << "stack pointer found\n"); + super::doWalkModule(module); + if (needStackSave) { + ensureFunctionImport( + module, STACK_SAVE, Signature(Type::none, Type::i32)); + } + if (needStackRestore) { + ensureFunctionImport( + module, STACK_RESTORE, Signature(Type::i32, Type::none)); + } + // Finally remove the stack pointer global itself. This avoids importing + // a mutable global. + module->removeGlobal(stackPointer->name); + } + + void ensureFunctionImport(Module* module, Name name, Signature sig) { + ImportInfo info(*module); + if (info.getImportedFunction(ENV, name)) { + return; + } + auto import = new Function; + import->name = name; + import->module = ENV; + import->base = name; + import->sig = sig; + module->addFunction(import); + } + +private: + std::unique_ptr<Builder> builder; + Global* stackPointer = nullptr; + bool needStackSave = false; + bool needStackRestore = false; +}; + +Pass* createReplaceStackPointerPass() { return new ReplaceStackPointer; } + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 4b023a46e..78717568e 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -285,6 +285,10 @@ void PassRegistry::registerPasses() { registerPass("rereloop", "re-optimize control flow using the relooper algorithm", createReReloopPass); + registerPass("replace-stack-pointer", + "Replace llvm-generated stack pointer global with calls with " + "imported functions.", + createReplaceStackPointerPass); registerPass( "rse", "remove redundant local.sets", createRedundantSetEliminationPass); registerPass("roundtrip", diff --git a/src/passes/passes.h b/src/passes/passes.h index 7683bf8c6..c844b5acc 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -95,6 +95,7 @@ Pass* createRemoveUnusedNonFunctionModuleElementsPass(); Pass* createRemoveUnusedNamesPass(); Pass* createReorderFunctionsPass(); Pass* createReorderLocalsPass(); +Pass* createReplaceStackPointerPass(); Pass* createReReloopPass(); Pass* createRedundantSetEliminationPass(); Pass* createRoundTripPass(); diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp index c01fb00bf..a92b0806b 100644 --- a/src/tools/wasm-emscripten-finalize.cpp +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -247,7 +247,9 @@ int main(int argc, const char* argv[]) { if (sideModule) { BYN_TRACE("finalizing as side module\n"); - generator.replaceStackPointerGlobal(); + PassRunner passRunner(&wasm); + passRunner.add("replace-stack-pointer"); + passRunner.run(); generator.generatePostInstantiateFunction(); } else { BYN_TRACE("finalizing as regular module\n"); diff --git a/src/wasm-emscripten.h b/src/wasm-emscripten.h index 6343c13d7..b541e60b4 100644 --- a/src/wasm-emscripten.h +++ b/src/wasm-emscripten.h @@ -44,10 +44,6 @@ public: // signature in the indirect function table. void generateDynCallThunks(); - // Convert stack pointer access from global.get/global.set to calling save - // and restore functions. - void replaceStackPointerGlobal(); - // Remove the import of a mutable __stack_pointer and instead initialize the // stack pointer from an immutable import. void internalizeStackPointerGlobal(); diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 2fcabb3b2..8e0c15aeb 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -37,8 +37,6 @@ namespace wasm { cashew::IString EM_ASM_PREFIX("emscripten_asm_const"); cashew::IString EM_JS_PREFIX("__em_js__"); -static Name STACK_SAVE("stackSave"); -static Name STACK_RESTORE("stackRestore"); static Name STACK_INIT("stack$init"); static Name STACK_LIMIT("__stack_limit"); static Name SET_STACK_LIMIT("__set_stack_limit"); @@ -361,47 +359,6 @@ void EmscriptenGlueGenerator::generateDynCallThunks() { } } -struct RemoveStackPointer : public PostWalker<RemoveStackPointer> { - RemoveStackPointer(Global* stackPointer) : stackPointer(stackPointer) {} - - void visitGlobalGet(GlobalGet* curr) { - if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { - needStackSave = true; - if (!builder) { - builder = make_unique<Builder>(*getModule()); - } - replaceCurrent(builder->makeCall(STACK_SAVE, {}, Type::i32)); - } - } - - void visitGlobalSet(GlobalSet* curr) { - if (getModule()->getGlobalOrNull(curr->name) == stackPointer) { - needStackRestore = true; - if (!builder) { - builder = make_unique<Builder>(*getModule()); - } - replaceCurrent( - builder->makeCall(STACK_RESTORE, {curr->value}, Type::none)); - } - } - - void visitModule(Module* curr) { - if (needStackSave) { - ensureFunctionImport(curr, STACK_SAVE, Signature(Type::none, Type::i32)); - } - if (needStackRestore) { - ensureFunctionImport( - curr, STACK_RESTORE, Signature(Type::i32, Type::none)); - } - } - -private: - std::unique_ptr<Builder> builder; - Global* stackPointer; - bool needStackSave = false; - bool needStackRestore = false; -}; - // lld can sometimes produce a build with an imported mutable __stack_pointer // (i.e. when linking with -fpie). This method internalizes the // __stack_pointer and initializes it from an immutable global instead. @@ -428,20 +385,6 @@ void EmscriptenGlueGenerator::internalizeStackPointerGlobal() { wasm.addGlobal(sp); } -void EmscriptenGlueGenerator::replaceStackPointerGlobal() { - Global* stackPointer = getStackPointerGlobal(wasm); - if (!stackPointer) { - return; - } - - // Replace all uses of stack pointer global - RemoveStackPointer(stackPointer).walkModule(&wasm); - - // Finally remove the stack pointer global itself. This avoids importing - // a mutable global. - wasm.removeGlobal(stackPointer->name); -} - struct StackLimitEnforcer : public WalkerPass<PostWalker<StackLimitEnforcer>> { StackLimitEnforcer(Global* stackPointer, Global* stackLimit, |