diff options
Diffstat (limited to 'src/passes')
-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 |
4 files changed, 109 insertions, 0 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(); |