diff options
-rw-r--r-- | src/passes/Asyncify.cpp | 146 | ||||
-rw-r--r-- | src/passes/pass.cpp | 7 | ||||
-rw-r--r-- | src/passes/passes.h | 2 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt | 516 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast | 20 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt | 88 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast | 24 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-never-unwind.txt | 534 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-never-unwind.wast | 20 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-never-unwind_O.txt | 103 | ||||
-rw-r--r-- | test/passes/asyncify_mod-asyncify-never-unwind_O.wast | 24 |
11 files changed, 1483 insertions, 1 deletions
diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index 56c294b21..c4e1c58bd 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -253,6 +253,7 @@ // #include "ir/effects.h" +#include "ir/find_all.h" #include "ir/literal-utils.h" #include "ir/memory-utils.h" #include "ir/module-utils.h" @@ -1169,6 +1170,10 @@ private: } // anonymous namespace +static std::string getFullImportName(Name module, Name base) { + return std::string(module.str) + '.' + base.str; +} + struct Asyncify : public Pass { void run(PassRunner* runner, Module* module) override { bool optimize = runner->options.optimizeLevel > 0; @@ -1209,7 +1214,7 @@ struct Asyncify : public Pass { if (allImportsCanChangeState) { return true; } - std::string full = std::string(module.str) + '.' + base.str; + auto full = getFullImportName(module, base); for (auto& listedImport : listedImports) { if (String::wildcardMatch(listedImport, full)) { return true; @@ -1341,4 +1346,143 @@ private: Pass* createAsyncifyPass() { return new Asyncify(); } +// Helper passes that can be run after Asyncify. + +template<bool neverRewind, bool neverUnwind, bool importsAlwaysUnwind> +struct ModAsyncify + : public WalkerPass<LinearExecutionWalker< + ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>>> { + bool isFunctionParallel() override { return true; } + + ModAsyncify* create() override { + return new ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>(); + } + + void doWalkFunction(Function* func) { + // Find the asyncify state name. + auto* unwind = this->getModule()->getExport(ASYNCIFY_STOP_UNWIND); + auto* unwindFunc = this->getModule()->getFunction(unwind->value); + FindAll<GlobalSet> sets(unwindFunc->body); + assert(sets.list.size() == 1); + asyncifyStateName = sets.list[0]->name; + // Walk and optimize. + this->walk(func->body); + } + + // Note that we don't just implement GetGlobal as we may know the value is + // *not* 0, 1, or 2, but not know the actual value. So what we can say depends + // on the comparison being done on it, and so we implement Binary and + // Select. + + void visitBinary(Binary* curr) { + // Check if this is a comparison of the asyncify state to a specific + // constant, which we may know is impossible. + bool flip = false; + if (curr->op == NeInt32) { + flip = true; + } else if (curr->op != EqInt32) { + return; + } + auto* c = curr->right->dynCast<Const>(); + if (!c) { + return; + } + auto* get = curr->left->dynCast<GlobalGet>(); + if (!get || get->name != asyncifyStateName) { + return; + } + // This is a comparison of the state to a constant, check if we know the + // value. + int32_t value; + auto checkedValue = c->value.geti32(); + if ((checkedValue == int(State::Unwinding) && neverUnwind) || + (checkedValue == int(State::Rewinding) && neverRewind)) { + // We know the state is checked against an impossible value. + value = 0; + } else if (checkedValue == int(State::Unwinding) && this->unwinding) { + // We know we are in fact unwinding right now. + value = 1; + unsetUnwinding(); + } else { + return; + } + if (flip) { + value = 1 - value; + } + Builder builder(*this->getModule()); + this->replaceCurrent(builder.makeConst(Literal(int32_t(value)))); + } + + void visitSelect(Select* curr) { + auto* get = curr->condition->dynCast<GlobalGet>(); + if (!get || get->name != asyncifyStateName) { + return; + } + // This is a comparison of the state to zero, which means we are checking + // "if running normally, run this code, but if rewinding, ignore it". If + // we know we'll never rewind, we can optimize this. + if (neverRewind) { + Builder builder(*this->getModule()); + curr->condition = builder.makeConst(Literal(int32_t(0))); + } + } + + void visitCall(Call* curr) { + unsetUnwinding(); + if (!importsAlwaysUnwind) { + return; + } + auto* target = this->getModule()->getFunction(curr->target); + if (!target->imported()) { + return; + } + // This is an import that definitely unwinds. Await the next check of + // the state in this linear execution trace, which we can turn into a + // constant. + this->unwinding = true; + } + + void visitCallIndirect(CallIndirect* curr) { unsetUnwinding(); } + + static void doNoteNonLinear( + ModAsyncify<neverRewind, neverUnwind, importsAlwaysUnwind>* self, + Expression**) { + // When control flow branches, stop tracking an unwinding. + self->unsetUnwinding(); + } + + void visitGlobalSet(GlobalSet* set) { + // TODO: this could be more precise + unsetUnwinding(); + } + +private: + Name asyncifyStateName; + + // Whether we just did a call to an import that indicates we are unwinding. + bool unwinding = false; + + void unsetUnwinding() { this->unwinding = false; } +}; + +// +// Assume imports that may unwind will always unwind, and that rewinding never +// happens. +// + +Pass* createModAsyncifyAlwaysOnlyUnwindPass() { + return new ModAsyncify<true, false, true>(); +} + +// +// Assume that we never unwind, but may still rewind. +// +struct ModAsyncifyNeverUnwind : public Pass { + void run(PassRunner* runner, Module* module) override {} +}; + +Pass* createModAsyncifyNeverUnwindPass() { + return new ModAsyncify<false, true, false>(); +} + } // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 7d17510fc..0ac70aa59 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -180,6 +180,13 @@ void PassRegistry::registerPasses() { "minifies both import and export names, and emits a mapping to " "the minified ones", createMinifyImportsAndExportsPass); + registerPass("mod-asyncify-always-and-only-unwind", + "apply the assumption that asyncify imports always unwind, " + "and we never rewind", + createModAsyncifyAlwaysOnlyUnwindPass); + registerPass("mod-asyncify-never-unwind", + "apply the assumption that asyncify never unwinds", + createModAsyncifyNeverUnwindPass); registerPass("nm", "name list", createNameListPass); registerPass("no-exit-runtime", "removes calls to atexit(), which is valid if the C runtime " diff --git a/src/passes/passes.h b/src/passes/passes.h index 6342ea15b..6732f1114 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -69,6 +69,8 @@ Pass* createOptimizeAddedConstantsPropagatePass(); Pass* createOptimizeInstructionsPass(); Pass* createOptimizeStackIRPass(); Pass* createPickLoadSignsPass(); +Pass* createModAsyncifyAlwaysOnlyUnwindPass(); +Pass* createModAsyncifyNeverUnwindPass(); Pass* createPostEmscriptenPass(); Pass* createPrecomputePass(); Pass* createPrecomputePropagatePass(); diff --git a/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt b/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt new file mode 100644 index 000000000..c7e35c2f8 --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt @@ -0,0 +1,516 @@ +(module + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (memory $0 1 2) + (global $__asyncify_state (mut i32) (i32.const 0)) + (global $__asyncify_data (mut i32) (i32.const 0)) + (export "asyncify_start_unwind" (func $asyncify_start_unwind)) + (export "asyncify_stop_unwind" (func $asyncify_stop_unwind)) + (export "asyncify_start_rewind" (func $asyncify_start_rewind)) + (export "asyncify_stop_rewind" (func $asyncify_stop_rewind)) + (func $calls-import (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.const 0) + (nop) + ) + (local.set $0 + (block $__asyncify_unwind (result i32) + (block + (block + (if + (i32.const 0) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.const 1) + (br $__asyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (nop) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $calls-import2 (; 4 ;) (type $FUNCSIG$i) (result i32) + (local $temp i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (if + (i32.const 0) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -20) + ) + ) + (local.set $8 + (i32.load + (global.get $__asyncify_data) + ) + ) + (local.set $temp + (i32.load + (local.get $8) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $8) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $8) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $8) + ) + ) + (local.set $4 + (i32.load offset=16 + (local.get $8) + ) + ) + ) + ) + (local.set $5 + (block $__asyncify_unwind (result i32) + (block + (block + (if + (i32.const 0) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $6 + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $6) + (i32.const 0) + ) + ) + (block + (local.set $7 + (call $import2) + ) + (if + (i32.const 1) + (br $__asyncify_unwind + (i32.const 0) + ) + (local.set $1 + (local.get $7) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (block + (local.set $temp + (local.get $1) + ) + (nop) + (local.set $2 + (local.get $temp) + ) + (return + (local.get $2) + ) + ) + ) + (nop) + (nop) + (nop) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $5) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $9 + (i32.load + (global.get $__asyncify_data) + ) + ) + (i32.store + (local.get $9) + (local.get $temp) + ) + (i32.store offset=4 + (local.get $9) + (local.get $1) + ) + (i32.store offset=8 + (local.get $9) + (local.get $2) + ) + (i32.store offset=12 + (local.get $9) + (local.get $3) + ) + (i32.store offset=16 + (local.get $9) + (local.get $4) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 20) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-drop (; 5 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.const 0) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $4 + (i32.load + (global.get $__asyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $4) + ) + ) + ) + ) + (local.set $1 + (block $__asyncify_unwind (result i32) + (block + (block + (if + (i32.const 0) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $2) + (i32.const 0) + ) + ) + (block + (local.set $3 + (call $import2) + ) + (if + (i32.const 1) + (br $__asyncify_unwind + (i32.const 0) + ) + (local.set $0 + (local.get $3) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (block + (drop + (local.get $0) + ) + (nop) + ) + ) + (nop) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__asyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $0) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + ) + (func $calls-nothing (; 6 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (i32.eqz + (i32.const 17) + ) + ) + (drop + (local.get $0) + ) + (nop) + ) + (func $asyncify_start_unwind (; 7 ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 1) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_stop_unwind (; 8 ;) + (global.set $__asyncify_state + (i32.const 0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_start_rewind (; 9 ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 2) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_stop_rewind (; 10 ;) + (global.set $__asyncify_state + (i32.const 0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast b/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast new file mode 100644 index 000000000..70cb7e8fb --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-always-and-only-unwind.wast @@ -0,0 +1,20 @@ +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt b/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt new file mode 100644 index 000000000..3f83675e8 --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.txt @@ -0,0 +1,88 @@ +(module + (type $FUNCSIG$v (func)) + (import "env" "import" (func $import)) + (memory $0 1 2) + (global $__asyncify_state (mut i32) (i32.const 0)) + (global $__asyncify_data (mut i32) (i32.const 0)) + (export "calls-import" (func $calls-import)) + (export "calls-import2" (func $calls-import)) + (export "calls-import2-drop" (func $calls-import)) + (export "calls-nothing" (func $calls-import)) + (export "asyncify_start_unwind" (func $asyncify_start_unwind)) + (export "asyncify_stop_unwind" (func $asyncify_stop_unwind)) + (export "asyncify_start_rewind" (func $asyncify_start_rewind)) + (export "asyncify_stop_rewind" (func $asyncify_stop_unwind)) + (func $calls-import (; 1 ;) (; has Stack IR ;) (type $FUNCSIG$v) + (local $0 i32) + (call $import) + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (func $asyncify_start_unwind (; 2 ;) (; has Stack IR ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 1) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_stop_unwind (; 3 ;) (; has Stack IR ;) + (global.set $__asyncify_state + (i32.const 0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_start_rewind (; 4 ;) (; has Stack IR ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 2) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast b/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast new file mode 100644 index 000000000..5d8f2e4b7 --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-always-and-only-unwind_O.wast @@ -0,0 +1,24 @@ +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (export "calls-import" (func $calls-import)) + (export "calls-import2" (func $calls-import)) + (export "calls-import2-drop" (func $calls-import)) + (export "calls-nothing" (func $calls-import)) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-never-unwind.txt b/test/passes/asyncify_mod-asyncify-never-unwind.txt new file mode 100644 index 000000000..8647f5426 --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-never-unwind.txt @@ -0,0 +1,534 @@ +(module + (type $FUNCSIG$v (func)) + (type $FUNCSIG$i (func (result i32))) + (type $FUNCSIG$vi (func (param i32))) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (memory $0 1 2) + (global $__asyncify_state (mut i32) (i32.const 0)) + (global $__asyncify_data (mut i32) (i32.const 0)) + (export "asyncify_start_unwind" (func $asyncify_start_unwind)) + (export "asyncify_stop_unwind" (func $asyncify_stop_unwind)) + (export "asyncify_start_rewind" (func $asyncify_start_rewind)) + (export "asyncify_stop_rewind" (func $asyncify_stop_rewind)) + (func $calls-import (; 3 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (nop) + ) + (local.set $0 + (block $__asyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $1 + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $1) + (i32.const 0) + ) + ) + (block + (call $import) + (if + (i32.const 0) + (br $__asyncify_unwind + (i32.const 0) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (nop) + ) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $0) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (nop) + ) + (func $calls-import2 (; 4 ;) (type $FUNCSIG$i) (result i32) + (local $temp i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + (local $7 i32) + (local $8 i32) + (local $9 i32) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -20) + ) + ) + (local.set $8 + (i32.load + (global.get $__asyncify_data) + ) + ) + (local.set $temp + (i32.load + (local.get $8) + ) + ) + (local.set $1 + (i32.load offset=4 + (local.get $8) + ) + ) + (local.set $2 + (i32.load offset=8 + (local.get $8) + ) + ) + (local.set $3 + (i32.load offset=12 + (local.get $8) + ) + ) + (local.set $4 + (i32.load offset=16 + (local.get $8) + ) + ) + ) + ) + (local.set $5 + (block $__asyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $6 + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $6) + (i32.const 0) + ) + ) + (block + (local.set $7 + (call $import2) + ) + (if + (i32.const 0) + (br $__asyncify_unwind + (i32.const 0) + ) + (local.set $1 + (local.get $7) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (block + (local.set $temp + (local.get $1) + ) + (nop) + (local.set $2 + (local.get $temp) + ) + (return + (local.get $2) + ) + ) + ) + (nop) + (nop) + (nop) + ) + (unreachable) + ) + (unreachable) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $5) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $9 + (i32.load + (global.get $__asyncify_data) + ) + ) + (i32.store + (local.get $9) + (local.get $temp) + ) + (i32.store offset=4 + (local.get $9) + (local.get $1) + ) + (i32.store offset=8 + (local.get $9) + (local.get $2) + ) + (i32.store offset=12 + (local.get $9) + (local.get $3) + ) + (i32.store offset=16 + (local.get $9) + (local.get $4) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 20) + ) + ) + ) + (i32.const 0) + ) + (func $calls-import2-drop (; 5 ;) (type $FUNCSIG$v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $4 + (i32.load + (global.get $__asyncify_data) + ) + ) + (local.set $0 + (i32.load + (local.get $4) + ) + ) + ) + ) + (local.set $1 + (block $__asyncify_unwind (result i32) + (block + (block + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (block + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (local.set $2 + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + ) + ) + (block + (if + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (i32.const 1) + (i32.eq + (local.get $2) + (i32.const 0) + ) + ) + (block + (local.set $3 + (call $import2) + ) + (if + (i32.const 0) + (br $__asyncify_unwind + (i32.const 0) + ) + (local.set $0 + (local.get $3) + ) + ) + ) + ) + (if + (i32.eq + (global.get $__asyncify_state) + (i32.const 0) + ) + (block + (drop + (local.get $0) + ) + (nop) + ) + ) + (nop) + ) + ) + (return) + ) + ) + ) + (block + (i32.store + (i32.load + (global.get $__asyncify_data) + ) + (local.get $1) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + (block + (local.set $5 + (i32.load + (global.get $__asyncify_data) + ) + ) + (i32.store + (local.get $5) + (local.get $0) + ) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const 4) + ) + ) + ) + ) + (func $calls-nothing (; 6 ;) (type $FUNCSIG$v) + (local $0 i32) + (local.set $0 + (i32.eqz + (i32.const 17) + ) + ) + (drop + (local.get $0) + ) + (nop) + ) + (func $asyncify_start_unwind (; 7 ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 1) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_stop_unwind (; 8 ;) + (global.set $__asyncify_state + (i32.const 0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_start_rewind (; 9 ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 2) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_stop_rewind (; 10 ;) + (global.set $__asyncify_state + (i32.const 0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-never-unwind.wast b/test/passes/asyncify_mod-asyncify-never-unwind.wast new file mode 100644 index 000000000..70cb7e8fb --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-never-unwind.wast @@ -0,0 +1,20 @@ +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-never-unwind_O.txt b/test/passes/asyncify_mod-asyncify-never-unwind_O.txt new file mode 100644 index 000000000..b185f5c6b --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-never-unwind_O.txt @@ -0,0 +1,103 @@ +(module + (type $FUNCSIG$v (func)) + (import "env" "import" (func $import)) + (memory $0 1 2) + (global $__asyncify_state (mut i32) (i32.const 0)) + (global $__asyncify_data (mut i32) (i32.const 0)) + (export "calls-import" (func $calls-import)) + (export "calls-import2" (func $calls-import)) + (export "calls-import2-drop" (func $calls-import)) + (export "calls-nothing" (func $calls-import)) + (export "asyncify_start_unwind" (func $asyncify_start_unwind)) + (export "asyncify_stop_unwind" (func $asyncify_stop_unwind)) + (export "asyncify_start_rewind" (func $asyncify_start_rewind)) + (export "asyncify_stop_rewind" (func $asyncify_stop_unwind)) + (func $calls-import (; 1 ;) (; has Stack IR ;) (type $FUNCSIG$v) + (if + (select + (i32.eqz + (if (result i32) + (i32.eq + (global.get $__asyncify_state) + (i32.const 2) + ) + (block (result i32) + (i32.store + (global.get $__asyncify_data) + (i32.add + (i32.load + (global.get $__asyncify_data) + ) + (i32.const -4) + ) + ) + (i32.load + (i32.load + (global.get $__asyncify_data) + ) + ) + ) + (i32.const 0) + ) + ) + (i32.const 1) + (global.get $__asyncify_state) + ) + (call $import) + ) + ) + (func $asyncify_start_unwind (; 2 ;) (; has Stack IR ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 1) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_stop_unwind (; 3 ;) (; has Stack IR ;) + (global.set $__asyncify_state + (i32.const 0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) + (func $asyncify_start_rewind (; 4 ;) (; has Stack IR ;) (param $0 i32) + (global.set $__asyncify_state + (i32.const 2) + ) + (global.set $__asyncify_data + (local.get $0) + ) + (if + (i32.gt_u + (i32.load + (global.get $__asyncify_data) + ) + (i32.load offset=4 + (global.get $__asyncify_data) + ) + ) + (unreachable) + ) + ) +) diff --git a/test/passes/asyncify_mod-asyncify-never-unwind_O.wast b/test/passes/asyncify_mod-asyncify-never-unwind_O.wast new file mode 100644 index 000000000..5d8f2e4b7 --- /dev/null +++ b/test/passes/asyncify_mod-asyncify-never-unwind_O.wast @@ -0,0 +1,24 @@ +(module + (memory 1 2) + (import "env" "import" (func $import)) + (import "env" "import2" (func $import2 (result i32))) + (import "env" "import3" (func $import3 (param i32))) + (export "calls-import" (func $calls-import)) + (export "calls-import2" (func $calls-import)) + (export "calls-import2-drop" (func $calls-import)) + (export "calls-nothing" (func $calls-import)) + (func $calls-import + (call $import) + ) + (func $calls-import2 (result i32) + (local $temp i32) + (local.set $temp (call $import2)) + (return (local.get $temp)) + ) + (func $calls-import2-drop + (drop (call $import2)) + ) + (func $calls-nothing + (drop (i32.eqz (i32.const 17))) + ) +) |