diff options
Diffstat (limited to 'test/lit')
-rw-r--r-- | test/lit/passes/vacuum-tnh-mvp.wast | 33 | ||||
-rw-r--r-- | test/lit/passes/vacuum-tnh.wast | 405 |
2 files changed, 436 insertions, 2 deletions
diff --git a/test/lit/passes/vacuum-tnh-mvp.wast b/test/lit/passes/vacuum-tnh-mvp.wast new file mode 100644 index 000000000..93d9bb203 --- /dev/null +++ b/test/lit/passes/vacuum-tnh-mvp.wast @@ -0,0 +1,33 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --vacuum -tnh -S -o - | filecheck %s + +(module + (memory 1 1) + + ;; CHECK: (func $block-unreachable-but-call + ;; CHECK-NEXT: (i32.store + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $block-unreachable-but-call) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $block-unreachable-but-call + ;; A call cannot be removed, even if it leads to a trap, since it might have + ;; non-trap effects (like mayNotReturn). We can remove the store after it, + ;; though. + ;; + ;; This duplicates a test in vacuum-tnh but in MVP mode (to check for a + ;; possible bug with the throws effect which varies based on features). + (i32.store + (i32.const 0) + (i32.const 1) + ) + (call $block-unreachable-but-call) + (i32.store + (i32.const 2) + (i32.const 3) + ) + (unreachable) + ) +) diff --git a/test/lit/passes/vacuum-tnh.wast b/test/lit/passes/vacuum-tnh.wast index e4ce9765d..bac1c3eb6 100644 --- a/test/lit/passes/vacuum-tnh.wast +++ b/test/lit/passes/vacuum-tnh.wast @@ -6,10 +6,16 @@ ;; RUN: wasm-opt %s --vacuum -all -S -o - | filecheck %s --check-prefix=NO_TNH (module - (memory 1 1) - ;; YESTNH: (type $struct (struct (field (mut i32)))) + + ;; YESTNH: (tag $tag (param i32)) ;; NO_TNH: (type $struct (struct (field (mut i32)))) + + ;; NO_TNH: (tag $tag (param i32)) + (tag $tag (param i32)) + + (memory 1 1) + (type $struct (struct (field (mut i32)))) ;; YESTNH: (func $drop (type $i32_anyref_=>_none) (param $x i32) (param $y anyref) @@ -265,4 +271,399 @@ ) ) ) + + ;; YESTNH: (func $if-unreachable (type $i32_=>_none) (param $p i32) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (block + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (call $if-unreachable + ;; YESTNH-NEXT: (i32.const 0) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (if + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $if-unreachable (type $i32_=>_none) (param $p i32) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (call $if-unreachable + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $if-unreachable (param $p i32) + ;; The if arm can be nopped, as in tnh we assume we never reach it. + (if + (local.get $p) + (unreachable) + ) + ;; This else arm can be removed. + (if + (local.get $p) + (call $if-unreachable + (i32.const 0) + ) + (unreachable) + ) + ;; Both of these can be removed, but we leave this for DCE to handle. + (if + (local.get $p) + (unreachable) + (unreachable) + ) + ) + + ;; YESTNH: (func $if-unreachable-value (type $i32_=>_i32) (param $p i32) (result i32) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (i32.const 1) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $if-unreachable-value (type $i32_=>_i32) (param $p i32) (result i32) + ;; NO_TNH-NEXT: (if (result i32) + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $if-unreachable-value (param $p i32) (result i32) + ;; When removing the unreachable arm we must update the IR properly, as it + ;; cannot have a nop there. + (if (result i32) + (local.get $p) + (unreachable) + (i32.const 1) + ) + ) + + ;; YESTNH: (func $if-unreachable-value-2 (type $i32_=>_i32) (param $p i32) (result i32) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (i32.const 1) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $if-unreachable-value-2 (type $i32_=>_i32) (param $p i32) (result i32) + ;; NO_TNH-NEXT: (if (result i32) + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $if-unreachable-value-2 (param $p i32) (result i32) + ;; As above but in the other arm. + (if (result i32) + (local.get $p) + (i32.const 1) + (unreachable) + ) + ) + + ;; YESTNH: (func $block-unreachable (type $i32_=>_none) (param $p i32) + ;; YESTNH-NEXT: (if + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: (block + ;; YESTNH-NEXT: (i32.store + ;; YESTNH-NEXT: (i32.const 0) + ;; YESTNH-NEXT: (i32.const 1) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (if + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: (return) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $block-unreachable (type $i32_=>_none) (param $p i32) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (block + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (return) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 2) + ;; NO_TNH-NEXT: (i32.const 3) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $block-unreachable (param $p i32) + (if + (local.get $p) + (block + (i32.store + (i32.const 0) + (i32.const 1) + ) + (if + (local.get $p) + (return) + ) + ;; This store can be removed as it leads up to an unreachable which we + ;; assume is never reached. + (i32.store + (i32.const 2) + (i32.const 3) + ) + (unreachable) + ) + ) + ) + + ;; YESTNH: (func $block-unreachable-named (type $i32_=>_none) (param $p i32) + ;; YESTNH-NEXT: (if + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: (block $named + ;; YESTNH-NEXT: (i32.store + ;; YESTNH-NEXT: (i32.const 0) + ;; YESTNH-NEXT: (i32.const 1) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (br_if $named + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $block-unreachable-named (type $i32_=>_none) (param $p i32) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (block $named + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (br_if $named + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 2) + ;; NO_TNH-NEXT: (i32.const 3) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $block-unreachable-named (param $p i32) + (if + (local.get $p) + (block $named + (i32.store + (i32.const 0) + (i32.const 1) + ) + ;; As above, but now the block is named and we use a br_if. We should + ;; again only remove the last store. + (br_if $named + (local.get $p) + ) + (i32.store + (i32.const 2) + (i32.const 3) + ) + (unreachable) + ) + ) + ) + + ;; YESTNH: (func $block-unreachable-all (type $i32_=>_none) (param $p i32) + ;; YESTNH-NEXT: (nop) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $block-unreachable-all (type $i32_=>_none) (param $p i32) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (block + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 2) + ;; NO_TNH-NEXT: (i32.const 3) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $block-unreachable-all (param $p i32) + (if + (local.get $p) + (block + ;; Both stores can be removed, and even the entire if arm and then the + ;; entire if. + (i32.store + (i32.const 0) + (i32.const 1) + ) + (i32.store + (i32.const 2) + (i32.const 3) + ) + (unreachable) + ) + ) + ) + + ;; YESTNH: (func $block-unreachable-but-call (type $none_=>_none) + ;; YESTNH-NEXT: (i32.store + ;; YESTNH-NEXT: (i32.const 0) + ;; YESTNH-NEXT: (i32.const 1) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (call $block-unreachable-but-call) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $block-unreachable-but-call (type $none_=>_none) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (call $block-unreachable-but-call) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 2) + ;; NO_TNH-NEXT: (i32.const 3) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + (func $block-unreachable-but-call + ;; A call cannot be removed, even if it leads to a trap, since it might have + ;; non-trap effects (like mayNotReturn). We can remove the store after it, + ;; though. + (i32.store + (i32.const 0) + (i32.const 1) + ) + (call $block-unreachable-but-call) + (i32.store + (i32.const 2) + (i32.const 3) + ) + (unreachable) + ) + + ;; YESTNH: (func $catch-pop (type $none_=>_none) + ;; YESTNH-NEXT: (try $try + ;; YESTNH-NEXT: (do + ;; YESTNH-NEXT: (call $catch-pop) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (catch $tag + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (pop i32) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $catch-pop (type $none_=>_none) + ;; NO_TNH-NEXT: (try $try + ;; NO_TNH-NEXT: (do + ;; NO_TNH-NEXT: (call $catch-pop) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (catch $tag + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (pop i32) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $catch-pop + (try $try + (do + ;; Put a call here so the entire try-catch is not removed as trivial. + (call $catch-pop) + ) + (catch $tag + ;; A pop on the way to a trap cannot be removed. But the store can. + ;; TODO: The pop can actually be removed since it is valid per the spec + ;; because of the unreachable afterwards. We need to fix our + ;; validation rules to handle that though. + (drop + (pop i32) + ) + (i32.store + (i32.const 0) + (i32.const 1) + ) + (unreachable) + ) + ) + ) + + ;; YESTNH: (func $loop-unreachable (type $i32_=>_none) (param $p i32) + ;; YESTNH-NEXT: (loop $loop + ;; YESTNH-NEXT: (i32.store + ;; YESTNH-NEXT: (i32.const 0) + ;; YESTNH-NEXT: (i32.const 1) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (if + ;; YESTNH-NEXT: (local.get $p) + ;; YESTNH-NEXT: (br $loop) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $loop-unreachable (type $i32_=>_none) (param $p i32) + ;; NO_TNH-NEXT: (loop $loop + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 0) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (if + ;; NO_TNH-NEXT: (local.get $p) + ;; NO_TNH-NEXT: (br $loop) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.store + ;; NO_TNH-NEXT: (i32.const 2) + ;; NO_TNH-NEXT: (i32.const 3) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $loop-unreachable (param $p i32) + (loop $loop + (i32.store + (i32.const 0) + (i32.const 1) + ) + (if + (local.get $p) + (br $loop) + ) + ;; This store can be removed as it leads up to an unreachable which we + ;; assume is never reached. + (i32.store + (i32.const 2) + (i32.const 3) + ) + (unreachable) + ) + ) ) |