diff options
Diffstat (limited to 'test/lit/passes/code-pushing_into_if.wast')
-rw-r--r-- | test/lit/passes/code-pushing_into_if.wast | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/test/lit/passes/code-pushing_into_if.wast b/test/lit/passes/code-pushing_into_if.wast new file mode 100644 index 000000000..e856f446c --- /dev/null +++ b/test/lit/passes/code-pushing_into_if.wast @@ -0,0 +1,651 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --code-pushing -S -o - | filecheck %s + +(module + ;; CHECK: (func $if-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-nop (param $p i32) + (local $x i32) + ;; The set local is not used in any if arm; do nothing. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + ) + ) + + ;; CHECK: (func $if-nop-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-nop-nop (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + (nop) ;; add a nop here compared to the last testcase (no output change) + ) + ) + + ;; CHECK: (func $if-use (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use (param $p i32) + (local $x i32) + ;; The set local is used in one arm and nowhere else; push it there. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-use-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-nop (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (nop) ;; add a nop here compared to the last testcase (no output change) + ) + ) + + ;; CHECK: (func $if-else-use (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-else-use (param $p i32) + (local $x i32) + ;; The set local is used in one arm and nowhere else; push it there. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $unpushed-interference (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $unpushed-interference (param $p i32) + (local $x i32) + (local $y i32) + (local.set $x (i32.const 1)) + ;; This set is not pushed (as it is not used in the if) and it will then + ;; prevent the previous set of $x from being pushed, since we can't push a + ;; set of $x past a get of it. + (local.set $y (local.get $x)) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-use-use (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-use (param $p i32) + (local $x i32) + ;; The set local is used in both arms, so we can't do anything. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-use-after (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after (param $p i32) + (local $x i32) + ;; The use after the if prevents optimization. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-use-after-nop (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after-nop (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (nop) ;; add a nop here compared to the last testcase (no output change) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-else-use-after (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-else-use-after (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (nop) + (drop (local.get $x)) ;; now the use in the if is in the else arm + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-use-after-unreachable (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after-unreachable (param $p i32) + (local $x i32) + ;; A use after the if is ok as the other arm is unreachable. + (local.set $x (i32.const 1)) + (if + (local.get $p) + (drop (local.get $x)) + (return) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $if-use-after-unreachable-else (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-use-after-unreachable-else (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (local.get $p) + (return) ;; as above, but with arms flipped + (drop (local.get $x)) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $optimize-many (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local $z i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $z + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $z) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $optimize-many (param $p i32) + (local $x i32) + (local $y i32) + (local $z i32) + ;; Multiple things we can push, to various arms. + (local.set $x (i32.const 1)) + (local.set $y (i32.const 2)) + (local.set $z (i32.const 3)) + (if + (local.get $p) + (block + (drop (local.get $x)) + (drop (local.get $z)) + ) + (drop (local.get $y)) + ) + ) + + ;; CHECK: (func $past-other (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-other (param $p i32) + (local $x i32) + (local $t i32) + ;; We can push this past the drop after it. + (local.set $x (local.get $t)) + (drop (i32.const 2)) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-other-no (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $t + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-other-no (param $p i32) + (local $x i32) + (local $t i32) + ;; We cannot push this due to the tee, which interferes with us. + (local.set $x (local.get $t)) + (drop (local.tee $t (i32.const 2))) + (if + (local.get $p) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-condition-no (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.tee $t + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-condition-no (param $p i32) + (local $x i32) + (local $t i32) + ;; We cannot push this due to the tee in the if condition. + (local.set $x (local.get $t)) + (if + (local.tee $t (local.get $p)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-condition-no-2 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-condition-no-2 + (local $x i32) + (local $t i32) + ;; We cannot push this due to the read of $x in the if condition. + (local.set $x (local.get $t)) + (if + (local.get $x) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $past-condition-no-3 (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $t i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (local.get $t) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.tee $x + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $past-condition-no-3 (param $p i32) + (local $x i32) + (local $t i32) + ;; We cannot push this due to the write of $x in the if condition. + (local.set $x (local.get $t)) + (if + (local.tee $x (local.get $p)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-condition-return (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-condition-return (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + (if + (block (result i32) + (return) ;; This return does not prevent us from optimizing; if it + ;; happens then we don't need the local.set to execute + ;; anyhow. + (local.get $p) + ) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $if-condition-break-used (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (br $out) + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $if-condition-break-used (param $p i32) + (local $x i32) + (local.set $x (i32.const 1)) + ;; As above, but the return is replaced with a break. The break goes to a + ;; location with a use of the local, which prevents optimization. + (block $out + (if + (block (result i32) + (br $out) + (local.get $p) + ) + (drop (local.get $x)) + ) + (return) + ) + (drop (local.get $x)) + ) + + ;; CHECK: (func $one-push-prevents-another (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $one-push-prevents-another (param $p i32) + (local $x i32) + (local $y i32) + ;; We will push $y into one arm, and as a result both arms will have a get + ;; of $x, which prevents pushing $x. + (local.set $x (i32.const 1)) + (local.set $y (local.get $x)) + (if + (local.get $p) + (drop (local.get $x)) + (drop (local.get $y)) + ) + ) + + ;; CHECK: (func $one-push-prevents-another-flipped (param $p i32) + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local $y i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (if + ;; CHECK-NEXT: (local.get $p) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $one-push-prevents-another-flipped (param $p i32) + (local $x i32) + (local $y i32) + ;; As above but with if arms flipped. The result should be similar, with + ;; only $y pushed. + (local.set $x (i32.const 1)) + (local.set $y (local.get $x)) + (if + (local.get $p) + (drop (local.get $y)) + (drop (local.get $x)) + ) + ) +) |