diff options
-rw-r--r-- | src/passes/CodePushing.cpp | 9 | ||||
-rw-r--r-- | test/passes/code-pushing.txt | 60 | ||||
-rw-r--r-- | test/passes/code-pushing.wast | 36 |
3 files changed, 96 insertions, 9 deletions
diff --git a/src/passes/CodePushing.cpp b/src/passes/CodePushing.cpp index 397a20bab..f4beff1a8 100644 --- a/src/passes/CodePushing.cpp +++ b/src/passes/CodePushing.cpp @@ -115,7 +115,14 @@ private: auto* set = curr->dynCast<SetLocal>(); if (!set) return nullptr; auto index = set->index; - return analyzer.isSFA(index) && numGetsSoFar[index] == analyzer.getNumGets(index) ? set : nullptr; + // to be pushable, this must be SFA and the right # of gets, + // but also have no side effects, as it may not execute if pushed. + if (analyzer.isSFA(index) && + numGetsSoFar[index] == analyzer.getNumGets(index) && + !EffectAnalyzer(set->value).hasSideEffects()) { + return set; + } + return nullptr; } // Push past conditional control flow. diff --git a/test/passes/code-pushing.txt b/test/passes/code-pushing.txt index b8c496210..f09d0dfb5 100644 --- a/test/passes/code-pushing.txt +++ b/test/passes/code-pushing.txt @@ -342,15 +342,15 @@ (local $x i32) (local $y i32) (block $out - (br_if $out - (i32.const 2) - ) (set_local $x (call $push-dropped) ) (set_local $y (call $push-dropped) ) + (br_if $out + (i32.const 2) + ) (drop (get_local $x) ) @@ -388,13 +388,13 @@ (local $y i32) (block $out (set_local $x - (call $push-dropped) + (i32.const 1) ) (br_if $out (i32.const 2) ) (set_local $y - (call $push-dropped) + (i32.const 3) ) (drop (get_local $x) @@ -407,4 +407,54 @@ (get_local $x) ) ) + (func $unpushed-ignorable-side-effect (type $0) + (local $x i32) + (local $y i32) + (block $out + (set_local $x + (call $push-dropped) + ) + (br_if $out + (i32.const 2) + ) + (set_local $y + (i32.const 3) + ) + (drop + (get_local $x) + ) + (drop + (get_local $y) + ) + ) + ) + (func $unpushed-side-effect-into-drop (type $0) + (local $x i32) + (block $out + (set_local $x + (call $push-dropped) + ) + (br_if $out + (i32.const 1) + ) + (drop + (get_local $x) + ) + ) + ) + (func $unpushed-side-effect-into-if (type $0) + (local $x i32) + (block $out + (set_local $x + (call $push-dropped) + ) + (br_if $out + (i32.const 1) + ) + (if + (get_local $x) + (nop) + ) + ) + ) ) diff --git a/test/passes/code-pushing.wast b/test/passes/code-pushing.wast index ca973e182..e1cb30f4a 100644 --- a/test/passes/code-pushing.wast +++ b/test/passes/code-pushing.wast @@ -179,7 +179,7 @@ (drop (get_local $x)) ) ) - (func $values-might-interfere ;; but don't, as we keep the order + (func $values-might-interfere ;; they don't, as we keep the order - but here their side effects prevent pushing (local $x i32) (local $y i32) (block $out @@ -206,13 +206,43 @@ (local $x i32) (local $y i32) (block $out - (set_local $x (call $push-dropped)) - (set_local $y (call $push-dropped)) + (set_local $x (i32.const 1)) + (set_local $y (i32.const 3)) (br_if $out (i32.const 2)) (drop (get_local $x)) (drop (get_local $y)) ) (drop (get_local $x)) ;; $x can't be pushed, but y doesn't care ) + (func $unpushed-ignorable-side-effect + (local $x i32) + (local $y i32) + (block $out + (set_local $x (call $push-dropped)) ;; $x can't be pushed, but y doesn't care + (set_local $y (i32.const 3)) + (br_if $out (i32.const 2)) + (drop (get_local $x)) + (drop (get_local $y)) + ) + ) + (func $unpushed-side-effect-into-drop + (local $x i32) + (block $out + (set_local $x (call $push-dropped)) + (br_if $out (i32.const 1)) + (drop (get_local $x)) + ) + ) + (func $unpushed-side-effect-into-if + (local $x i32) + (block $out + (set_local $x (call $push-dropped)) + (br_if $out (i32.const 1)) + (if + (get_local $x) + (nop) + ) + ) + ) ) |