diff options
author | Heejin Ahn <aheejin@gmail.com> | 2021-06-08 13:15:59 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-08 13:15:59 -0700 |
commit | eac90b56d4a749f10d440e4bb7fd744e4bc756e8 (patch) | |
tree | aeb562b523b3a610cb716962c36cc4ee6367c2dc | |
parent | 28f227fb90d18d8c1fc2c52b592d2934469aef8e (diff) | |
download | binaryen-eac90b56d4a749f10d440e4bb7fd744e4bc756e8.tar.gz binaryen-eac90b56d4a749f10d440e4bb7fd744e4bc756e8.tar.bz2 binaryen-eac90b56d4a749f10d440e4bb7fd744e4bc756e8.zip |
[EH] Convert EH tests into lit tests (#3923)
This converts most EH tests in test/passes into test/lit/passes. Fixed
some files to follow 2-space indentation and improved some comments.
42 files changed, 1857 insertions, 1889 deletions
diff --git a/test/lit/passes/coalesce-locals-eh.wast b/test/lit/passes/coalesce-locals-eh.wast new file mode 100644 index 000000000..f564c2991 --- /dev/null +++ b/test/lit/passes/coalesce-locals-eh.wast @@ -0,0 +1,43 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --coalesce-locals -all -S -o - | filecheck %s + +(module + ;; CHECK: (func $bar (result i32) + ;; CHECK-NEXT: (i32.const 1984) + ;; CHECK-NEXT: ) + (func $bar (result i32) + (i32.const 1984) + ) + + (event $e (attr 0)) + ;; CHECK: (func $bug-cfg-traversal (param $0 i32) (result i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (call $bar) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + (func $bug-cfg-traversal (param $0 i32) (result i32) + (local $x i32) + ;; This is a regrssion test case for a bug in cfg-traversal for EH. + ;; See https://github.com/WebAssembly/binaryen/pull/3594 + (try + (do + (local.set $x + ;; the call may or may not throw, so we may reach the get of $x + (call $bar) + ) + ) + (catch_all + (unreachable) + ) + ) + (local.get $x) + ) +) diff --git a/test/lit/passes/code-folding-eh.wast b/test/lit/passes/code-folding-eh.wast new file mode 100644 index 000000000..6a1a1eb36 --- /dev/null +++ b/test/lit/passes/code-folding-eh.wast @@ -0,0 +1,153 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --remove-unused-names --code-folding -all -S -o - \ +;; RUN: | filecheck %s + +(module + (event $e-i32 (attr 0) (param i32)) + + ;; CHECK: (func $pop-test + ;; CHECK-NEXT: (block $folding-inner0 + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e-i32 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $folding-inner0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e-i32 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $folding-inner0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (return) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 111) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 222) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 333) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $pop-test + (try + (do + (try + (do) + (catch $e-i32 + ;; Expressions containing a pop should NOT be taken out and folded. + (drop (pop i32)) + (drop (i32.const 111)) + (drop (i32.const 222)) + (drop (i32.const 333)) + (unreachable) + ) + ) + ) + (catch $e-i32 + (drop (pop i32)) + (drop (i32.const 111)) + (drop (i32.const 222)) + (drop (i32.const 333)) + (unreachable) + ) + ) + ) + + (func $foo) + ;; CHECK: (func $try-call-optimize-terminating-tails (result i32) + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (return + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + (func $try-call-optimize-terminating-tails (result i32) + (try + (do + ;; Expressions that can throw should NOT be taken out of 'try' scope. + (call $foo) + (call $foo) + (call $foo) + (call $foo) + (return (i32.const 0)) + ) + (catch_all + (call $foo) + (call $foo) + (call $foo) + (call $foo) + (return (i32.const 0)) + ) + ) + (i32.const 0) + ) + + ;; CHECK: (func $try-call-optimize-expression-tails + ;; CHECK-NEXT: (block $x + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (br $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (br $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $try-call-optimize-expression-tails + (block $x + (try + (do + ;; Expressions that can throw should NOT be taken out of 'try' scope. + (call $foo) + (call $foo) + (call $foo) + (br $x) + ) + (catch_all + (call $foo) + (call $foo) + (call $foo) + (br $x) + ) + ) + (unreachable) + ) + ) +) diff --git a/test/lit/passes/code-pushing-eh.wast b/test/lit/passes/code-pushing-eh.wast new file mode 100644 index 000000000..fe406ec2b --- /dev/null +++ b/test/lit/passes/code-pushing-eh.wast @@ -0,0 +1,208 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --code-pushing -all -S -o - | filecheck %s + +(module + (event $e (attr 0) (param i32)) + + ;; CHECK: (func $cant-push-past-call + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $cant-push-past-call) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $out + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cant-push-past-call + (local $x i32) + (block $out + ;; This local.set cannot be pushed down, because the call below can throw + (local.set $x (i32.const 1)) + (call $cant-push-past-call) + (drop (i32.const 1)) + (br_if $out (i32.const 2)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $cant-push-past-throw + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $out + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cant-push-past-throw + (local $x i32) + (block $out + ;; This local.set cannot be pushed down, because there is 'throw' below + (local.set $x (i32.const 1)) + (throw $e (i32.const 0)) + (drop (i32.const 1)) + (br_if $out (i32.const 2)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $can-push-past-try + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $out + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; 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: ) + (func $can-push-past-try + (local $x i32) + (block $out + ;; This local.set can be pushed down, because the 'throw' below is going + ;; to be caught by the inner catch_all + (local.set $x (i32.const 1)) + (try + (do + (throw $e (i32.const 0)) + ) + (catch_all) + ) + (drop (i32.const 1)) + (br_if $out (i32.const 2)) + (drop (local.get $x)) + ) + ) + + (func $foo) + ;; CHECK: (func $cant-push-past-try + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $out + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cant-push-past-try + (local $x i32) + (block $out + ;; This local.set cannot be pushed down, because the exception thrown by + ;; 'call $foo' below may not be caught by 'catch $e' + (local.set $x (i32.const 1)) + (try + (do + (call $foo) + ) + (catch $e + (drop (pop i32)) + ) + ) + (drop (i32.const 1)) + (br_if $out (i32.const 2)) + (drop (local.get $x)) + ) + ) + + ;; CHECK: (func $cant-push-past-rethrow-within-catch + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (block $out + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (try $l0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (rethrow $l0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $out + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $cant-push-past-rethrow-within-catch + (local $x i32) + (block $out + ;; This local.set cannot be pushed down, because there is 'rethrow' within + ;; the inner catch_all + (local.set $x (i32.const 1)) + (try $l0 + (do + (throw $e (i32.const 0)) + ) + (catch_all + (rethrow $l0) + ) + ) + (drop (i32.const 1)) + (br_if $out (i32.const 2)) + (drop (local.get $x)) + ) + ) +) diff --git a/test/lit/passes/dce-eh.wast b/test/lit/passes/dce-eh.wast new file mode 100644 index 000000000..1bb6358dd --- /dev/null +++ b/test/lit/passes/dce-eh.wast @@ -0,0 +1,125 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --dce -all -S -o - | filecheck %s + +;; If either try body or catch body is reachable, the whole try construct is +;; reachable +(module + (func $foo) + (event $e (attr 0)) + + ;; CHECK: (func $try_unreachable + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: ) + (func $try_unreachable + (try + (do + (unreachable) + ) + (catch_all) + ) + (call $foo) ;; shouldn't be dce'd + ) + + ;; CHECK: (func $catch_unreachable + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: ) + (func $catch_unreachable + (try + (do) + (catch_all + (unreachable) + ) + ) + (call $foo) ;; shouldn't be dce'd + ) + + ;; CHECK: (func $both_unreachable + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $both_unreachable + (try + (do + (unreachable) + ) + (catch_all + (unreachable) + ) + ) + (call $foo) ;; should be dce'd + ) + + ;; CHECK: (func $throw + ;; CHECK-NEXT: (block $label$0 + ;; CHECK-NEXT: (block $label$1 + ;; CHECK-NEXT: (throw $e) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $throw + ;; All these wrapping expressions before 'throw' will be dce'd + (drop + (block $label$0 (result externref) + (if + (i32.clz + (block $label$1 (result i32) + (throw $e) + ) + ) + (nop) + ) + (ref.null extern) + ) + ) + ) + + ;; CHECK: (func $rethrow + ;; CHECK-NEXT: (try $l0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (rethrow $l0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $rethrow + (try $l0 + (do) + (catch $e + (drop + ;; This i32.add will be dce'd + (i32.add + (i32.const 0) + (rethrow $l0) + ) + ) + ) + ) + ) +) diff --git a/test/lit/passes/inlining-eh.wast b/test/lit/passes/inlining-eh.wast new file mode 100644 index 000000000..9879978e1 --- /dev/null +++ b/test/lit/passes/inlining-eh.wast @@ -0,0 +1,99 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --inlining -all -S -o - | filecheck %s + +(module + ;; --------------------------------------------------------------------------- + (import "a" "b" (func $foo (result i32))) + (event $event$0 (attr 0) (param i32)) + (func $callee-with-label + (try $label + (do) + (catch $event$0 + (nop) + ) + ) + ) + + ;; Properly ensure unique try labels after an inlining + + ;; CHECK: (func $caller-with-label (param $x i32) + ;; CHECK-NEXT: (loop $label + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block $__inlined_func$callee-with-label + ;; CHECK-NEXT: (try $label0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $event$0 + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $label + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller-with-label (param $x i32) + (loop $label ;; The same label as the try that will be inlined into here + (call $callee-with-label) + (br_if $label + (call $foo) + ) + ) + ) + + ;; --------------------------------------------------------------------------- + ;; CHECK: (func $callee-with-try-delegate + ;; CHECK-NEXT: (try $label$3 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (delegate 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $callee-with-try-delegate + (try $label$3 + (do) + (delegate 0) + ) + ) + + ;; For now, do not inline a try-delegate + + ;; CHECK: (func $caller + ;; CHECK-NEXT: (call $callee-with-try-delegate) + ;; CHECK-NEXT: ) + (func $caller + (call $callee-with-try-delegate) + ) + + ;; --------------------------------------------------------------------------- + (func $callee (result i32) + (i32.const 42) + ) + + ;; Properly support inlining into a function with a try-delegate + + ;; CHECK: (func $caller-with-try-delegate (result i32) + ;; CHECK-NEXT: (try $label$3 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (delegate 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block $__inlined_func$callee (result i32) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller-with-try-delegate (result i32) + (try $label$3 + (do) + (delegate 0) + ) + (call $callee) + ) +) diff --git a/test/lit/passes/instrument-locals-eh.wast b/test/lit/passes/instrument-locals-eh.wast new file mode 100644 index 000000000..99ba94583 --- /dev/null +++ b/test/lit/passes/instrument-locals-eh.wast @@ -0,0 +1,30 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --instrument-locals -all -S -o - | filecheck %s + +(module + (event $e (attr 0) (param i32)) + + ;; CHECK: (func $test + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $test + (local $x i32) + (try + (do) + (catch $e + ;; Pop instructions should not be instrumented + (local.set $x (pop i32)) + ) + ) + ) +) diff --git a/test/lit/passes/optimize-instructions-eh.wast b/test/lit/passes/optimize-instructions-eh.wast new file mode 100644 index 000000000..50ae665e2 --- /dev/null +++ b/test/lit/passes/optimize-instructions-eh.wast @@ -0,0 +1,249 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --remove-unused-names --optimize-instructions -all -S -o - \ +;; RUN: | filecheck %s + +(module + (func $dummy) + (event $e (attr 0) (param i32)) + + ;; The following are the unit tests for Properties::getFallthrough for EH + ;; instructions, which are used in one of binary optimizations in + ;; OptimizeInstructions::visitBinary(). + + ;; When a pattern of (i32.add (expr) (expr with all 1s)) is detected and + ;; 'expr' is guaranteed to take equal or less bits than the number of bits in + ;; the second expression, the i32.add can be dropped and we can only leave + ;; (expr). For example: + ;; (i32.add (local.get $x) (i32.const 7)) can be just (local.get $x) when $x + ;; is guaranteed to contain a value equal to or less than 7. + + ;; CHECK: (func $getFallthrough-try-no-throw + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (try (result i32) + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $getFallthrough-try-no-throw + (local $x i32) + (local.set $x + (try (result i32) + (do + (i32.const 1) + ) + (catch_all + (i32.const 3) + ) + ) + ) + ;; The 'try' above is guaranteed not to throw, so we can be sure the $x + ;; contains 1 at this point, which is smaller than 7 (0b111), so we know the + ;; masking with 0b111 is not ncessary and we can only leave (local.set $x). + (drop (i32.and (local.get $x) (i32.const 7))) + ) + + ;; CHECK: (func $getFallthrough-try-may-throw + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (try (result i32) + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $dummy) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 7) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $getFallthrough-try-may-throw + (local $x i32) + (local.set $x + (try (result i32) + (do + (call $dummy) + (i32.const 1) + ) + (catch_all + (i32.const 3) + ) + ) + ) + ;; The 'try' body above may throw because of the call, so we are not sure + ;; what $x contains at this point, so we can't remove the masking here. + (drop (i32.and (local.get $x) (i32.const 7))) + ) + + ;; CHECK: (func $getFallthrough-nested-try-0 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (try (result i32) + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $dummy) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 7) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $getFallthrough-nested-try-0 + (local $x i32) + (local.set $x + (try (result i32) + (do + (try + (do + (call $dummy) + ) + (catch $e + (drop (pop i32)) + ) + ) + (i32.const 1) + ) + (catch $e + (drop (pop i32)) + (i32.const 3) + ) + ) + ) + ;; The inner 'try' may throw and it may not be caught by both the inner and + ;; outer catches, so we are not sure what $x contains at this point, which + ;; prevents the masking optimization. + (drop (i32.and (local.get $x) (i32.const 7))) + ) + + ;; CHECK: (func $getFallthrough-nested-try-1 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (try (result i32) + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $dummy) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $getFallthrough-nested-try-1 + (local $x i32) + (local.set $x + (try (result i32) + (do + (try + (do + (call $dummy) + ) + (catch_all) + ) + (i32.const 1) + ) + (catch_all + (i32.const 3) + ) + ) + ) + ;; The inner try may throw, but it will caught by the inner catch_all, and + ;; $x will be set to 1. So we can do the masking optimization and remove + ;; i32.and here. + (drop (i32.and (local.get $x) (i32.const 7))) + ) + + ;; CHECK: (func $getFallthrough-nested-try-2 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (try (result i32) + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (call $dummy) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.and + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 7) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $getFallthrough-nested-try-2 + (local $x i32) + (local.set $x + (try (result i32) + (do + (try + (do) + (catch_all + (call $dummy) + ) + ) + (i32.const 3) + ) + (catch_all + (i32.const 1) + ) + ) + ) + ;; Depending on whether (call $dummy) throws or not, we are not sure whether + ;; $x will contain 1 or 3 at this point, which prevents the masking + ;; optimization. + (drop (i32.and (local.get $x) (i32.const 7))) + ) +) diff --git a/test/lit/passes/remove-unused-module-elements-eh.wast b/test/lit/passes/remove-unused-module-elements-eh.wast new file mode 100644 index 000000000..7e0c66af4 --- /dev/null +++ b/test/lit/passes/remove-unused-module-elements-eh.wast @@ -0,0 +1,30 @@ +;; RUN: wasm-opt %s --remove-unused-module-elements -all -S -o - | filecheck %s + +;; Non-exported and unused events can be removed +(module + (type $0 (func (param i32))) + + ;; CHECK-NOT: (event $e-remove + ;; CHECK: (event $e-export + ;; CHECK: (event $e-throw + ;; CHECK: (event $e-catch + (event $e-remove (attr 0) (type $0)) ;; can be removed + (event $e-export (attr 0) (param i64)) ;; cannot be removed (exported) + (event $e-throw (attr 0) (type $0)) ;; cannot be removed (used in throw) + (event $e-catch (attr 0) (type $0)) ;; cannot be removed (used in catch) + + (export "e-export" (event $e-export)) + (import "env" "e" (event $e-import (attr 0) (param i32))) + + (start $start) + (func $start + (try + (do + (throw $e-throw (i32.const 0)) + ) + (catch $e-catch + (drop (pop i32)) + ) + ) + ) +) diff --git a/test/lit/passes/remove-unused-names-eh.wast b/test/lit/passes/remove-unused-names-eh.wast new file mode 100644 index 000000000..fd20c07e4 --- /dev/null +++ b/test/lit/passes/remove-unused-names-eh.wast @@ -0,0 +1,70 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --remove-unused-names -all -S -o - | filecheck %s + +(module + (event $event$0 (attr 0) (param i32)) + + ;; CHECK: (func $func0 + ;; CHECK-NEXT: (try $label$9 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $event$0 + ;; CHECK-NEXT: (try $label$8 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (rethrow $label$9) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (delegate $label$8) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $event$0 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $func0 + (try $label$9 ;; needed due to a rethrow + (do) + (catch $event$0 + (try $label$8 ;; needed due to a delegate + (do + (try $label$6 ;; this one is not needed + (do + (rethrow $label$9) + ) + (delegate $label$8) + ) + ) + (catch $event$0 + (drop + (pop i32) + ) + ) + ) + ) + ) + ) + + ;; CHECK: (func $func1 + ;; CHECK-NEXT: (try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (delegate 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $func1 + (try $label$3 ;; this one is not needed + (do + (nop) + ) + (delegate 0) ;; delegates to the caller + ) + ) +) diff --git a/test/lit/passes/rse-eh.wast b/test/lit/passes/rse-eh.wast new file mode 100644 index 000000000..d6f7074e7 --- /dev/null +++ b/test/lit/passes/rse-eh.wast @@ -0,0 +1,449 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --rse -all -S -o - | filecheck %s + +(module + (event $e (attr 0) (param i32)) + (event $e2 (attr 0)) + + ;; CHECK: (func $try1 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $try1 + (local $x i32) + (try + (do) + (catch_all + (local.set $x (i32.const 1)) + ) + ) + ;; try will not throw. So this should NOT be dropped + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $try2 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $try2 + (local $x i32) + (try + (do + (throw $e (i32.const 0)) + (local.set $x (i32.const 1)) + ) + (catch_all) + ) + ;; local.set is after 'throw' so it will not run. This should NOT be + ;; dropped. + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $try3 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $try3 + (local $x i32) + (try + (do + (throw $e (i32.const 0)) + ) + (catch_all + (local.set $x (i32.const 1)) + ) + ) + ;; try body will throw and catch_all contains the same local.set. This + ;; should be dropped. + (local.set $x (i32.const 1)) + ) + + (func $foo) + ;; CHECK: (func $try4 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $try4 + (local $x i32) + (try + (do + (call $foo) + (local.set $x (i32.const 1)) + ) + (catch_all) + ) + ;; (call $foo) may throw and the local.set may not run, so this should NOT + ;; be dropped + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $try5 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $try5 + (local $x i32) + (try + (do + (local.set $x (i32.const 1)) + (call $foo) + ) + (catch_all) + ) + ;; Even if (call $foo) throws, local.set runs before it, so this should be + ;; dropped + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $nested-try1 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try $l0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (rethrow $l0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $nested-try1 + (local $x i32) + (try + (do + (try $l0 + (do + (throw $e (i32.const 0)) + ) + (catch_all + (rethrow $l0) + ) + ) + ) + (catch_all + (local.set $x (i32.const 1)) + ) + ) + ;; The exception is caught by the inner catch_all and rethrown and again + ;; caught by the outer catch_all, which runs the local.set. So this should + ;; be dropped. + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $nested-try2 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try $l0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (rethrow $l0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $nested-try2 + (local $x i32) + (try + (do + (try $l0 + (do + (throw $e (i32.const 0)) + ) + (catch_all + (local.set $x (i32.const 1)) + (rethrow $l0) + ) + ) + ) + (catch_all) + ) + ;; The exception is caught by the inner catch_all, which runs the local.set, + ;; so this should be dropped + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $nested-try3 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try $l0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (rethrow $l0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $nested-try3 + (local $x i32) + (try + (do + (try $l0 + (do + (throw $e (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + (local.set $x (i32.const 1)) + (rethrow $l0) + ) + ) + ) + (catch_all) + ) + ;; Unlike nested-try2, the exception may not be caught by the inner catch, + ;; so the local.set may not run. So this should NOT be dropped. + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $nested-catch1 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e2 + ;; CHECK-NEXT: (try $try0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e2 + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $nested-catch1 + (local $x i32) + (try + (do + (throw $e (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + ) + (catch $e2 + (try + (do + (throw $e (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + ) + (catch $e2 + (local.set $x (i32.const 1)) + ) + ) + ) + ) + ;; This should NOT be dropped because the exception might not be caught by + ;; the inner catches, and the local.set above us may not have run, and + ;; other possible code paths do not even set the local. + (local.set $x (i32.const 1)) + ) + + ;; CHECK: (func $nested-catch2 + ;; CHECK-NEXT: (local $x i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (try $try1 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $nested-catch2 + (local $x i32) + (try + (do + (throw $e (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + (local.set $x (i32.const 1)) + ) + (catch_all + (try + (do + (throw $e (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + (local.set $x (i32.const 1)) + ) + (catch_all + (local.set $x (i32.const 1)) + ) + ) + ) + ) + ;; This should be dropped because the exception is guaranteed to be caught + ;; by one of the catches and it will set the local to 1. + (local.set $x (i32.const 1)) + ) +) diff --git a/test/lit/passes/simplify-locals-eh.wast b/test/lit/passes/simplify-locals-eh.wast new file mode 100644 index 000000000..fb5f671f3 --- /dev/null +++ b/test/lit/passes/simplify-locals-eh.wast @@ -0,0 +1,153 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --simplify-locals -all -S -o - | filecheck %s + +(module + (event $e-i32 (attr 0) (param i32)) + ;; CHECK: (func $foo (param $0 i32) (param $1 i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $foo (param i32 i32)) + ;; CHECK: (func $pop-cannot-be-sinked + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e-i32 + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $pop-cannot-be-sinked (local $0 i32) + (try + (do) + (catch $e-i32 + ;; This (local.set $0) of (pop i32) cannot be sunk to (local.get $0) + ;; below, because the pop should follow right after 'catch'. + (local.set $0 (pop i32)) + (call $foo + (i32.const 3) + (local.get $0) + ) + ) + ) + ) + + ;; CHECK: (func $pop-within-catch-can-be-sinked + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (call $foo + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: (try $try0 (result i32) + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e-i32 + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $pop-within-catch-can-be-sinked (local $0 i32) + (try + (do) + (catch_all + ;; This whole 'try' body can be sinked to eliminate local.set / + ;; local.get. Even though it contains a pop, it is enclosed within + ;; try-catch, so it is OK. + (local.set $0 + (try (result i32) + (do (i32.const 0)) + (catch $e-i32 (pop i32)) + ) + ) + (call $foo + (i32.const 3) + (local.get $0) + ) + ) + ) + ) + + ;; CHECK: (func $bar (result i32) + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + (func $bar (result i32) (i32.const 3)) + ;; CHECK: (func $call-cannot-be-sinked-into-try + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (call $bar) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e-i32 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $call-cannot-be-sinked-into-try (local $0 i32) + (drop + ;; This local.tee should NOT be sinked into 'try' below, because it may + ;; throw + (local.tee $0 (call $bar)) + ) + (try + (do + (drop (local.get $0)) + ) + (catch $e-i32 + (drop (pop i32)) + ) + ) + ) + + ;; CHECK: (func $non-call-can-be-sinked-into-try + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e-i32 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $non-call-can-be-sinked-into-try (local $0 i32) + (drop + ;; This local.tee can be sinked into 'try' below, because it cannot throw + (local.tee $0 (i32.const 3)) + ) + (try + (do + (drop (local.get $0)) + ) + (catch $e-i32 + (drop (pop i32)) + ) + ) + ) +) diff --git a/test/lit/passes/stack-ir-eh.wast b/test/lit/passes/stack-ir-eh.wast new file mode 100644 index 000000000..a398be325 --- /dev/null +++ b/test/lit/passes/stack-ir-eh.wast @@ -0,0 +1,60 @@ +;; RUN: wasm-opt %s --generate-stack-ir --optimize-stack-ir --print-stack-ir \ +;; RUN: -all -S -o - | filecheck %s + +(module + (event $e0 (attr 0) (param i32)) + + ;; CHECK: (func $eh + ;; CHECK-NEXT: try $l0 + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: throw $e0 + ;; CHECK-NEXT: catch $e0 + ;; CHECK-NEXT: + ;; CHECK-NEXT: drop + ;; CHECK-NEXT: catch_all + ;; CHECK-NEXT: rethrow $l0 + ;; CHECK-NEXT: end + ;; CHECK-NEXT: try $l00 + ;; CHECK-NEXT: try $try + ;; CHECK-NEXT: i32.const 0 + ;; CHECK-NEXT: throw $e0 + ;; CHECK-NEXT: delegate $l00 + ;; CHECK-NEXT: unreachable + ;; CHECK-NEXT: catch_all + ;; CHECK-NEXT: nop + ;; CHECK-NEXT: end + ;; CHECK-NEXT: try $l01 + ;; CHECK-NEXT: nop + ;; CHECK-NEXT: delegate 0 + ;; CHECK-NEXT: ) + (func $eh + (try $l0 + (do + (throw $e0 (i32.const 0)) + ) + (catch $e0 + (drop (pop i32)) + ) + (catch_all + (rethrow $l0) + ) + ) + + (try $l0 + (do + (try + (do + (throw $e0 (i32.const 0)) + ) + (delegate $l0) + ) + ) + (catch_all) + ) + + (try $l0 + (do) + (delegate 0) ;; delegate to caller + ) + ) +) diff --git a/test/lit/passes/stack-ir-roundtrip-eh.wast b/test/lit/passes/stack-ir-roundtrip-eh.wast new file mode 100644 index 000000000..b9bb22d3e --- /dev/null +++ b/test/lit/passes/stack-ir-roundtrip-eh.wast @@ -0,0 +1,61 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --generate-stack-ir --roundtrip -all -S -o - | filecheck %s + +(module + (event $event (attr 0) (param i32)) + ;; CHECK: (func $delegate-child + ;; CHECK-NEXT: (try $label$9 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try $label$7 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $event$0 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (try $label$6 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (delegate 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $event$0 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $delegate-child + (try + (do + (try + (do) + (catch $event + (drop + (pop i32) + ) + (try + (do) + ;; the binary writer must properly handle this delegate which is + ;; the child of other try's, and not get confused by their + ;; information on the stack (this is a regression test for us + ;; properly ending the scope with a delegate and popping the + ;; relevant stack). + (delegate 2) + ) + ) + ) + ) + (catch $event + (drop + (pop i32) + ) + ) + ) + ) +) diff --git a/test/lit/passes/vacuum-eh.wast b/test/lit/passes/vacuum-eh.wast new file mode 100644 index 000000000..d69278319 --- /dev/null +++ b/test/lit/passes/vacuum-eh.wast @@ -0,0 +1,126 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. +;; RUN: wasm-opt %s --vacuum -all -S -o - | filecheck %s + +(module + (event $e (attr 0) (param i32)) + (event $e2 (attr 0) (param i32)) + + ;; CHECK: (func $try-test + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $try-test + ;; When try body does not throw, try-body can be replaced with the try body + (try + (do + (drop (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + ) + ) + ) + + ;; CHECK: (func $inner-try-catch_all-test + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (try $try0 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch_all + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $inner-try-catch_all-test (local $0 i32) + ;; The exception thrown in the inner try is caught by the inner catch_all, + ;; so the outer try body does not throw and the outer try-catch can be + ;; removed + (try + (do + (try + (do + (throw $e (i32.const 0)) + ) + (catch_all + (local.set $0 (i32.const 1)) + ) + ) + ) + (catch $e + (drop (pop i32)) + ) + ) + ) + + ;; CHECK: (func $inner-try-catch-test + ;; CHECK-NEXT: (local $0 i32) + ;; CHECK-NEXT: (try $try + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (try $try1 + ;; CHECK-NEXT: (do + ;; CHECK-NEXT: (throw $e2 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $0 + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (catch $e + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (pop i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $inner-try-catch-test (local $0 i32) + ;; The exception thrown in the inner try will not be caught by the inner + ;; catch, so the outer try-catch cannot be removed + (try + (do + (try + (do + (throw $e2 (i32.const 0)) + ) + (catch $e + (drop (pop i32)) + (local.set $0 (i32.const 1)) + ) + ) + ) + (catch $e + (drop (pop i32)) + ) + ) + ) + + ;; CHECK: (func $br-in-catch + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $br-in-catch + ;; When catch body is removed, the removal of 'br' inside the catch body + ;; should be propagated up to the outer block, so that its type will be + ;; correctly updated to unreachable. + (block $label$1 + (try + (do + (unreachable) + ) + (catch $e + (drop (pop i32)) + (br $label$1) + ) + ) + ) + ) +) diff --git a/test/passes/coalesce-locals_all-features.txt b/test/passes/coalesce-locals_all-features.txt deleted file mode 100644 index f532f5d0e..000000000 --- a/test/passes/coalesce-locals_all-features.txt +++ /dev/null @@ -1,21 +0,0 @@ -(module - (type $none_=>_i32 (func (result i32))) - (type $i32_=>_i32 (func (param i32) (result i32))) - (export "foo" (func $1)) - (func $bar (result i32) - (i32.const 1984) - ) - (func $1 (param $0 i32) (result i32) - (try $try - (do - (local.set $0 - (call $bar) - ) - ) - (catch_all - (unreachable) - ) - ) - (local.get $0) - ) -) diff --git a/test/passes/coalesce-locals_all-features.wast b/test/passes/coalesce-locals_all-features.wast deleted file mode 100644 index ff7f04f0c..000000000 --- a/test/passes/coalesce-locals_all-features.wast +++ /dev/null @@ -1,19 +0,0 @@ -(module - (func $bar (result i32) - (i32.const 1984) - ) - (func "foo" (param $0 i32) (result i32) - (local $1 i32) - (try - (do - (local.set $1 - (call $bar) ;; the call may or may not throw, so we may reach the get of $1 - ) - ) - (catch_all - (unreachable) - ) - ) - (local.get $1) - ) -) diff --git a/test/passes/code-pushing_all-features.txt b/test/passes/code-pushing_all-features.txt deleted file mode 100644 index 4bcdf5bc3..000000000 --- a/test/passes/code-pushing_all-features.txt +++ /dev/null @@ -1,127 +0,0 @@ -(module - (type $none_=>_none (func)) - (type $i32_=>_none (func (param i32))) - (event $e (attr 0) (param i32)) - (func $cant-push-past-call - (local $x i32) - (block $out - (local.set $x - (i32.const 1) - ) - (call $cant-push-past-call) - (drop - (i32.const 1) - ) - (br_if $out - (i32.const 2) - ) - (drop - (local.get $x) - ) - ) - ) - (func $cant-push-past-throw - (local $x i32) - (block $out - (local.set $x - (i32.const 1) - ) - (throw $e - (i32.const 0) - ) - (drop - (i32.const 1) - ) - (br_if $out - (i32.const 2) - ) - (drop - (local.get $x) - ) - ) - ) - (func $can-push-past-try - (local $x i32) - (block $out - (try $try - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (nop) - ) - ) - (drop - (i32.const 1) - ) - (br_if $out - (i32.const 2) - ) - (local.set $x - (i32.const 1) - ) - (drop - (local.get $x) - ) - ) - ) - (func $foo - (nop) - ) - (func $cant-push-past-try - (local $x i32) - (block $out - (local.set $x - (i32.const 1) - ) - (try $try - (do - (call $foo) - ) - (catch $e - (drop - (pop i32) - ) - ) - ) - (drop - (i32.const 1) - ) - (br_if $out - (i32.const 2) - ) - (drop - (local.get $x) - ) - ) - ) - (func $cant-push-past-rethrow-within-catch - (local $x i32) - (block $out - (local.set $x - (i32.const 1) - ) - (try $l0 - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (rethrow $l0) - ) - ) - (drop - (i32.const 1) - ) - (br_if $out - (i32.const 2) - ) - (drop - (local.get $x) - ) - ) - ) -) diff --git a/test/passes/code-pushing_all-features.wast b/test/passes/code-pushing_all-features.wast deleted file mode 100644 index d9c7cecd4..000000000 --- a/test/passes/code-pushing_all-features.wast +++ /dev/null @@ -1,86 +0,0 @@ -(module - (event $e (attr 0) (param i32)) - - (func $cant-push-past-call - (local $x i32) - (block $out - ;; This local.set cannot be pushed down, because the call below can throw - (local.set $x (i32.const 1)) - (call $cant-push-past-call) - (drop (i32.const 1)) - (br_if $out (i32.const 2)) - (drop (local.get $x)) - ) - ) - - (func $cant-push-past-throw - (local $x i32) - (block $out - ;; This local.set cannot be pushed down, because there is 'throw' below - (local.set $x (i32.const 1)) - (throw $e (i32.const 0)) - (drop (i32.const 1)) - (br_if $out (i32.const 2)) - (drop (local.get $x)) - ) - ) - - (func $can-push-past-try - (local $x i32) - (block $out - ;; This local.set can be pushed down, because the 'throw' below is going - ;; to be caught by the inner catch_all - (local.set $x (i32.const 1)) - (try - (do - (throw $e (i32.const 0)) - ) - (catch_all) - ) - (drop (i32.const 1)) - (br_if $out (i32.const 2)) - (drop (local.get $x)) - ) - ) - - (func $foo) - (func $cant-push-past-try - (local $x i32) - (block $out - ;; This local.set cannot be pushed down, because the exception thrown by - ;; 'call $foo' below may not be caught by 'catch $e' - (local.set $x (i32.const 1)) - (try - (do - (call $foo) - ) - (catch $e - (drop (pop i32)) - ) - ) - (drop (i32.const 1)) - (br_if $out (i32.const 2)) - (drop (local.get $x)) - ) - ) - - (func $cant-push-past-rethrow-within-catch - (local $x i32) - (block $out - ;; This local.set cannot be pushed down, because there is 'rethrow' within - ;; the inner catch_all - (local.set $x (i32.const 1)) - (try $l0 - (do - (throw $e (i32.const 0)) - ) - (catch_all - (rethrow $l0) - ) - ) - (drop (i32.const 1)) - (br_if $out (i32.const 2)) - (drop (local.get $x)) - ) - ) -) diff --git a/test/passes/dce_all-features.txt b/test/passes/dce_all-features.txt index 790e32595..bc1e24951 100644 --- a/test/passes/dce_all-features.txt +++ b/test/passes/dce_all-features.txt @@ -540,64 +540,8 @@ ) ) (module - (type $none_=>_none (func)) (type $none_=>_i32 (func (result i32))) - (event $e (attr 0) (param)) - (func $foo - (nop) - ) - (func $try_unreachable - (try $try - (do - (unreachable) - ) - (catch_all - (nop) - ) - ) - (call $foo) - ) - (func $catch_unreachable - (try $try - (do - (nop) - ) - (catch_all - (unreachable) - ) - ) - (call $foo) - ) - (func $both_unreachable - (try $try - (do - (unreachable) - ) - (catch_all - (unreachable) - ) - ) - ) - (func $throw - (block $label$0 - (block $label$1 - (throw $e) - ) - ) - ) - (func $rethrow - (try $l0 - (do - (nop) - ) - (catch $e - (drop - (i32.const 0) - ) - (rethrow $l0) - ) - ) - ) + (type $none_=>_none (func)) (func $unnecessary-concrete-block (result i32) (block $foo (nop) diff --git a/test/passes/dce_all-features.wast b/test/passes/dce_all-features.wast index 104093d08..0f0416f66 100644 --- a/test/passes/dce_all-features.wast +++ b/test/passes/dce_all-features.wast @@ -734,77 +734,7 @@ ) ) -;; Exception handling instruction support -;; If either try body or catch body is reachable, the whole try construct is -;; reachable (module - (func $foo) - (event $e (attr 0)) - - (func $try_unreachable - (try - (do - (unreachable) - ) - (catch_all) - ) - (call $foo) ;; shouldn't be dce'd - ) - - (func $catch_unreachable - (try - (do) - (catch_all - (unreachable) - ) - ) - (call $foo) ;; shouldn't be dce'd - ) - - (func $both_unreachable - (try - (do - (unreachable) - ) - (catch_all - (unreachable) - ) - ) - (call $foo) ;; should be dce'd - ) - - (func $throw - ;; All these wrapping expressions before 'throw' will be dce'd - (drop - (block $label$0 (result externref) - (if - (i32.clz - (block $label$1 (result i32) - (throw $e) - ) - ) - (nop) - ) - (ref.null extern) - ) - ) - ) - - (func $rethrow - (try $l0 - (do) - (catch $e - (drop - ;; This i32.add will be dce'd - (i32.add - (i32.const 0) - (rethrow $l0) - ) - ) - ) - ) - ) - (func $unnecessary-concrete-block (result i32) (block $foo (result i32) ;; unnecessary type (nop) diff --git a/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt b/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt deleted file mode 100644 index 8c86126d5..000000000 --- a/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.txt +++ /dev/null @@ -1,71 +0,0 @@ -(module - (type $i32_=>_none (func (param i32))) - (type $none_=>_none (func)) - (event $e0 (attr 0) (param i32)) - (func $eh - try $l0 - i32.const 0 - throw $e0 - catch $e0 - - drop - catch_all - rethrow $l0 - end - try $l00 - try $try - i32.const 0 - throw $e0 - delegate $l00 - unreachable - catch_all - nop - end - try $l01 - nop - delegate 0 - ) -) -(module - (type $i32_=>_none (func (param i32))) - (type $none_=>_none (func)) - (event $e0 (attr 0) (param i32)) - (func $eh (; has Stack IR ;) - (try $l0 - (do - (throw $e0 - (i32.const 0) - ) - ) - (catch $e0 - (drop - (pop i32) - ) - ) - (catch_all - (rethrow $l0) - ) - ) - (try $l00 - (do - (try $try - (do - (throw $e0 - (i32.const 0) - ) - ) - (delegate $l00) - ) - ) - (catch_all - (nop) - ) - ) - (try $l01 - (do - (nop) - ) - (delegate 0) - ) - ) -) diff --git a/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast b/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast deleted file mode 100644 index 298cb3a3c..000000000 --- a/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_all-features.wast +++ /dev/null @@ -1,34 +0,0 @@ -(module - (event $e0 (attr 0) (param i32)) - - (func $eh - (try $l0 - (do - (throw $e0 (i32.const 0)) - ) - (catch $e0 - (drop (pop i32)) - ) - (catch_all - (rethrow $l0) - ) - ) - - (try $l0 - (do - (try - (do - (throw $e0 (i32.const 0)) - ) - (delegate $l0) - ) - ) - (catch_all) - ) - - (try $l0 - (do) - (delegate 0) ;; delegate to caller - ) - ) -) diff --git a/test/passes/generate-stack-ir_roundtrip_all-features.txt b/test/passes/generate-stack-ir_roundtrip_all-features.txt deleted file mode 100644 index 8d6b95b64..000000000 --- a/test/passes/generate-stack-ir_roundtrip_all-features.txt +++ /dev/null @@ -1,32 +0,0 @@ -(module - (type $i32_=>_none (func (param i32))) - (type $none_=>_none (func)) - (event $event$0 (attr 0) (param i32)) - (func $delegate-child - (try $label$9 - (do - (try $label$7 - (do - (nop) - ) - (catch $event$0 - (drop - (pop i32) - ) - (try $label$6 - (do - (nop) - ) - (delegate 2) - ) - ) - ) - ) - (catch $event$0 - (drop - (pop i32) - ) - ) - ) - ) -) diff --git a/test/passes/generate-stack-ir_roundtrip_all-features.wast b/test/passes/generate-stack-ir_roundtrip_all-features.wast deleted file mode 100644 index dc6c68d67..000000000 --- a/test/passes/generate-stack-ir_roundtrip_all-features.wast +++ /dev/null @@ -1,31 +0,0 @@ -(module - (event $event (attr 0) (param i32)) - (func $delegate-child - (try - (do - (try - (do) - (catch $event - (drop - (pop i32) - ) - (try - (do) - ;; the binary writer must properly handle this delegate which is the - ;; child of other try's, and not get confused by their information on the - ;; stack (this is a regression test for us properly ending the scope with - ;; a delegate and popping the relevant stack). - (delegate 2) - ) - ) - ) - ) - (catch $event - (drop - (pop i32) - ) - ) - ) - ) -) - diff --git a/test/passes/inlining_all-features.txt b/test/passes/inlining_all-features.txt index 03af9517d..ac9b00559 100644 --- a/test/passes/inlining_all-features.txt +++ b/test/passes/inlining_all-features.txt @@ -55,62 +55,6 @@ ) ) (module - (type $i32_=>_none (func (param i32))) - (type $none_=>_i32 (func (result i32))) - (import "a" "b" (func $foo (result i32))) - (event $event$0 (attr 0) (param i32)) - (export "exported" (func $1)) - (func $1 (param $x i32) - (loop $label - (block - (block $__inlined_func$0 - (try $label0 - (do - (nop) - ) - (catch $event$0 - (nop) - ) - ) - ) - ) - (br_if $label - (call $foo) - ) - ) - ) -) -(module - (type $none_=>_none (func)) - (func $0 - (try $label$3 - (do - (nop) - ) - (delegate 0) - ) - ) - (func $1 - (call $0) - ) -) -(module - (type $none_=>_i32 (func (result i32))) - (func $1 (result i32) - (try $label$3 - (do - (nop) - ) - (delegate 0) - ) - (block (result i32) - (block $__inlined_func$0 (result i32) - (i32.const 42) - ) - ) - ) -) -(module (type $none_=>_ref|func| (func (result (ref func)))) (elem declare func $1) (func $1 (result (ref func)) diff --git a/test/passes/inlining_all-features.wast b/test/passes/inlining_all-features.wast index 0aa324e1a..99fab7d26 100644 --- a/test/passes/inlining_all-features.wast +++ b/test/passes/inlining_all-features.wast @@ -43,52 +43,6 @@ (call $0) ) ) -;; properly ensure unique try labels after an inlining -(module - (import "a" "b" (func $foo (result i32))) - (event $event$0 (attr 0) (param i32)) - (func $0 - (try $label - (do) - (catch $event$0 - (nop) - ) - ) - ) - (func "exported" (param $x i32) - (loop $label ;; the same label as the try that will be inlined into here - (call $0) - (br_if $label - (call $foo) - ) - ) - ) -) -;; for now, do not inline a try-delegate -(module - (func $0 - (try $label$3 - (do) - (delegate 0) - ) - ) - (func $1 - (call $0) - ) -) -;; properly support inlining into a function with a try-delegate -(module - (func $0 (result i32) - (i32.const 42) - ) - (func $1 (result i32) - (try $label$3 - (do) - (delegate 0) - ) - (call $0) - ) -) ;; handle non-nullable parameter types (which turn into local types after ;; inlining) (module diff --git a/test/passes/instrument-locals_all-features_disable-typed-function-references.txt b/test/passes/instrument-locals_all-features_disable-typed-function-references.txt index 0b00ee493..e80161497 100644 --- a/test/passes/instrument-locals_all-features_disable-typed-function-references.txt +++ b/test/passes/instrument-locals_all-features_disable-typed-function-references.txt @@ -10,7 +10,6 @@ (type $i32_i32_i31ref_=>_i31ref (func (param i32 i32 i31ref) (result i31ref))) (type $i32_i32_dataref_=>_dataref (func (param i32 i32 dataref) (result dataref))) (type $i32_i32_v128_=>_v128 (func (param i32 i32 v128) (result v128))) - (type $i32_=>_none (func (param i32))) (type $none_=>_none (func)) (import "env" "get_i32" (func $get_i32 (param i32 i32 i32) (result i32))) (import "env" "get_i64" (func $get_i64 (param i32 i32 i64) (result i64))) @@ -35,7 +34,6 @@ (import "env" "get_v128" (func $get_v128 (param i32 i32 v128) (result v128))) (import "env" "set_v128" (func $set_v128 (param i32 i32 v128) (result v128))) (elem declare func $test) - (event $e (attr 0) (param i32)) (func $test (local $x i32) (local $y i64) @@ -204,16 +202,6 @@ ) ) ) - (try $try - (do - (nop) - ) - (catch $e - (local.set $x - (pop i32) - ) - ) - ) (drop (call $get_v128 (i32.const 22) diff --git a/test/passes/instrument-locals_all-features_disable-typed-function-references.wast b/test/passes/instrument-locals_all-features_disable-typed-function-references.wast index 29de7964e..45785c5f1 100644 --- a/test/passes/instrument-locals_all-features_disable-typed-function-references.wast +++ b/test/passes/instrument-locals_all-features_disable-typed-function-references.wast @@ -1,6 +1,4 @@ (module - (event $e (attr 0) (param i32)) - (func $test (local $x i32) (local $y i64) @@ -38,14 +36,6 @@ (local.set $F (local.get $F)) (local.set $X (local.get $X)) - ;; Pop instructions should not be instrumented - (try - (do) - (catch $e - (local.set $x (pop i32)) - ) - ) - ;; Add new instructions here so expected output doesn't change too much, it ;; depends on order of instructions in this file. (drop (local.get $S)) diff --git a/test/passes/remove-unused-module-elements_all-features.txt b/test/passes/remove-unused-module-elements_all-features.txt index 9cfd05ab2..864624c7e 100644 --- a/test/passes/remove-unused-module-elements_all-features.txt +++ b/test/passes/remove-unused-module-elements_all-features.txt @@ -296,30 +296,6 @@ ) ) (module - (type $0 (func (param i32))) - (type $i64_=>_none (func (param i64))) - (type $none_=>_none (func)) - (event $e-export (attr 0) (param i64)) - (event $e-throw (attr 0) (param i32)) - (event $e-catch (attr 0) (param i32)) - (export "e-export" (event $e-export)) - (start $start) - (func $start - (try $try - (do - (throw $e-throw - (i32.const 0) - ) - ) - (catch $e-catch - (drop - (pop i32) - ) - ) - ) - ) -) -(module (type $none_=>_none (func)) (elem declare func $foo) (export "test" (func $test)) diff --git a/test/passes/remove-unused-module-elements_all-features.wast b/test/passes/remove-unused-module-elements_all-features.wast index 3b2b031ad..09f3ab0e3 100644 --- a/test/passes/remove-unused-module-elements_all-features.wast +++ b/test/passes/remove-unused-module-elements_all-features.wast @@ -286,26 +286,6 @@ ) ) ) -(module ;; non-exported and unused events can be removed - (type $0 (func (param i32))) - (event $e-remove (attr 0) (type $0)) ;; can be removed - (event $e-export (attr 0) (param i64)) ;; cannot be removed (exported) - (event $e-throw (attr 0) (type $0)) ;; cannot be removed (used in throw) - (event $e-catch (attr 0) (type $0)) ;; cannot be removed (used in catch) - (export "e-export" (event $e-export)) - (import "env" "e" (event $e-import (attr 0) (param i32))) - (start $start) - (func $start - (try - (do - (throw $e-throw (i32.const 0)) - ) - (catch $e-catch - (drop (pop i32)) - ) - ) - ) -) (module ;; functions referenced by ref.func cannot be removed (export "test" $test) (func $foo) diff --git a/test/passes/remove-unused-names_all-features.txt b/test/passes/remove-unused-names_all-features.txt deleted file mode 100644 index d3a9146c8..000000000 --- a/test/passes/remove-unused-names_all-features.txt +++ /dev/null @@ -1,37 +0,0 @@ -(module - (type $none_=>_none (func)) - (type $i32_=>_none (func (param i32))) - (event $event$0 (attr 0) (param i32)) - (func $0 - (try $label$9 - (do - (nop) - ) - (catch $event$0 - (try $label$8 - (do - (try - (do - (rethrow $label$9) - ) - (delegate $label$8) - ) - ) - (catch $event$0 - (drop - (pop i32) - ) - ) - ) - ) - ) - ) - (func $1 - (try - (do - (nop) - ) - (delegate 0) - ) - ) -) diff --git a/test/passes/remove-unused-names_all-features.wast b/test/passes/remove-unused-names_all-features.wast deleted file mode 100644 index c55268a7a..000000000 --- a/test/passes/remove-unused-names_all-features.wast +++ /dev/null @@ -1,34 +0,0 @@ -(module - (event $event$0 (attr 0) (param i32)) - (func $0 - (try $label$9 ;; needed due to a rethrow - (do - ) - (catch $event$0 - (try $label$8 ;; needed due to a delegate - (do - (try $label$6 ;; this one is not needed - (do - (rethrow $label$9) - ) - (delegate $label$8) - ) - ) - (catch $event$0 - (drop - (pop i32) - ) - ) - ) - ) - ) - ) - (func $1 - (try $label$3 - (do - (nop) - ) - (delegate 0) ;; delegates to the caller - ) - ) -) diff --git a/test/passes/remove-unused-names_code-folding_all-features.txt b/test/passes/remove-unused-names_code-folding.txt index 5437e22db..3f21ae0b3 100644 --- a/test/passes/remove-unused-names_code-folding_all-features.txt +++ b/test/passes/remove-unused-names_code-folding.txt @@ -1,10 +1,8 @@ (module (type $none_=>_none (func)) (type $none_=>_i32 (func (result i32))) - (type $i32_=>_none (func (param i32))) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $i32_=>_i32 (func (param i32) (result i32))) - (event $e-i32 (attr 0) (param i32)) (func $ifs (if (i32.const 0) @@ -1710,85 +1708,4 @@ (i32.const 2) ) ) - (func $pop-test - (block $folding-inner0 - (try - (do - (try - (do - (nop) - ) - (catch $e-i32 - (drop - (pop i32) - ) - (br $folding-inner0) - ) - ) - ) - (catch $e-i32 - (drop - (pop i32) - ) - (br $folding-inner0) - ) - ) - (return) - ) - (drop - (i32.const 111) - ) - (drop - (i32.const 222) - ) - (drop - (i32.const 333) - ) - (unreachable) - ) - (func $foo - (nop) - ) - (func $try-call-optimize-terminating-tails (result i32) - (try - (do - (call $foo) - (call $foo) - (call $foo) - (call $foo) - (return - (i32.const 0) - ) - ) - (catch_all - (call $foo) - (call $foo) - (call $foo) - (call $foo) - (return - (i32.const 0) - ) - ) - ) - (i32.const 0) - ) - (func $try-call-optimize-expression-tails - (block $x - (try - (do - (call $foo) - (call $foo) - (call $foo) - (br $x) - ) - (catch_all - (call $foo) - (call $foo) - (call $foo) - (br $x) - ) - ) - (unreachable) - ) - ) ) diff --git a/test/passes/remove-unused-names_code-folding_all-features.wast b/test/passes/remove-unused-names_code-folding.wast index 320e820d8..9979a0a3c 100644 --- a/test/passes/remove-unused-names_code-folding_all-features.wast +++ b/test/passes/remove-unused-names_code-folding.wast @@ -1191,73 +1191,4 @@ ) ) ) - - (event $e-i32 (attr 0) (param i32)) - (func $pop-test - (try - (do - (try - (do) - (catch $e-i32 - ;; Expressions containing a pop should NOT be taken out and folded. - (drop (pop i32)) - (drop (i32.const 111)) - (drop (i32.const 222)) - (drop (i32.const 333)) - (unreachable) - ) - ) - ) - (catch $e-i32 - (drop (pop i32)) - (drop (i32.const 111)) - (drop (i32.const 222)) - (drop (i32.const 333)) - (unreachable) - ) - ) - ) - - (func $foo) - (func $try-call-optimize-terminating-tails (result i32) - (try - (do - ;; Expressions that can throw should NOT be taken out of 'try' scope. - (call $foo) - (call $foo) - (call $foo) - (call $foo) - (return (i32.const 0)) - ) - (catch_all - (call $foo) - (call $foo) - (call $foo) - (call $foo) - (return (i32.const 0)) - ) - ) - (i32.const 0) - ) - - (func $try-call-optimize-expression-tails - (block $x - (try - (do - ;; Expressions that can throw should NOT be taken out of 'try' scope. - (call $foo) - (call $foo) - (call $foo) - (br $x) - ) - (catch_all - (call $foo) - (call $foo) - (call $foo) - (br $x) - ) - ) - (unreachable) - ) - ) ) diff --git a/test/passes/remove-unused-names_optimize-instructions_all-features.txt b/test/passes/remove-unused-names_optimize-instructions_all-features.txt deleted file mode 100644 index cf1e44132..000000000 --- a/test/passes/remove-unused-names_optimize-instructions_all-features.txt +++ /dev/null @@ -1,125 +0,0 @@ -(module - (type $none_=>_none (func)) - (type $i32_=>_none (func (param i32))) - (event $e (attr 0) (param i32)) - (func $dummy - (nop) - ) - (func $getFallthrough - (local $x0 i32) - (local $x1 i32) - (local $x2 i32) - (local $x3 i32) - (local $x4 i32) - (local.set $x0 - (try (result i32) - (do - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop - (local.get $x0) - ) - (local.set $x1 - (try (result i32) - (do - (call $dummy) - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop - (i32.and - (local.get $x1) - (i32.const 7) - ) - ) - (local.set $x2 - (try (result i32) - (do - (try - (do - (throw $e - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - ) - ) - (i32.const 1) - ) - (catch $e - (drop - (pop i32) - ) - (i32.const 3) - ) - ) - ) - (drop - (i32.and - (local.get $x2) - (i32.const 7) - ) - ) - (local.set $x3 - (try (result i32) - (do - (try - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (nop) - ) - ) - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop - (local.get $x3) - ) - (local.set $x4 - (try (result i32) - (do - (try - (do - (nop) - ) - (catch_all - (throw $e - (i32.const 0) - ) - ) - ) - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop - (i32.and - (local.get $x4) - (i32.const 7) - ) - ) - ) -) diff --git a/test/passes/remove-unused-names_optimize-instructions_all-features.wast b/test/passes/remove-unused-names_optimize-instructions_all-features.wast deleted file mode 100644 index e08c42169..000000000 --- a/test/passes/remove-unused-names_optimize-instructions_all-features.wast +++ /dev/null @@ -1,101 +0,0 @@ -(module - (func $dummy) - (event $e (attr 0) (param i32)) - - (func $getFallthrough ;; unit tests for Properties::getFallthrough - (local $x0 i32) - (local $x1 i32) - (local $x2 i32) - (local $x3 i32) - (local $x4 i32) - - ;; try - try body does not throw, can - (local.set $x0 - (try (result i32) - (do - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop (i32.and (local.get $x0) (i32.const 7))) - - ;; try - try body may throw, can't - (local.set $x1 - (try (result i32) - (do - (call $dummy) - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop (i32.and (local.get $x1) (i32.const 7))) - - ;; nested try - inner try may throw and may not be caught by inner catch, - ;; can't - (local.set $x2 - (try (result i32) - (do - (try - (do - (throw $e (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - ) - ) - (i32.const 1) - ) - (catch $e - (drop (pop i32)) - (i32.const 3) - ) - ) - ) - (drop (i32.and (local.get $x2) (i32.const 7))) - - ;; nested try - inner try may throw but will be caught by inner catch_all, - ;; can - (local.set $x3 - (try (result i32) - (do - (try - (do - (throw $e (i32.const 0)) - ) - (catch_all) - ) - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop (i32.and (local.get $x3) (i32.const 7))) - - ;; nested try - inner catch_all may throw, can't - (local.set $x4 - (try (result i32) - (do - (try - (do) - (catch_all - (throw $e (i32.const 0)) - ) - ) - (i32.const 1) - ) - (catch_all - (i32.const 3) - ) - ) - ) - (drop (i32.and (local.get $x4) (i32.const 7))) - ) -) diff --git a/test/passes/rse_all-features.txt b/test/passes/rse_all-features.txt index 1594425cf..8ad883d9f 100644 --- a/test/passes/rse_all-features.txt +++ b/test/passes/rse_all-features.txt @@ -3,8 +3,6 @@ (type $i32_=>_none (func (param i32))) (type $i32_i32_=>_none (func (param i32 i32))) (type $i32_f64_=>_none (func (param i32 f64))) - (event $e (attr 0) (param i32)) - (event $e2 (attr 0) (param)) (func $basic (param $x i32) (param $y f64) (local $a f32) (local $b i64) @@ -476,254 +474,4 @@ ) ) ) - (func $try1 - (local $x i32) - (try $try - (do - (nop) - ) - (catch_all - (local.set $x - (i32.const 1) - ) - ) - ) - (local.set $x - (i32.const 1) - ) - ) - (func $try2 - (local $x i32) - (try $try - (do - (throw $e - (i32.const 0) - ) - (local.set $x - (i32.const 1) - ) - ) - (catch_all - (nop) - ) - ) - (local.set $x - (i32.const 1) - ) - ) - (func $try3 - (local $x i32) - (try $try - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (local.set $x - (i32.const 1) - ) - ) - ) - (drop - (i32.const 1) - ) - ) - (func $foo - (nop) - ) - (func $try4 - (local $x i32) - (try $try - (do - (call $foo) - (local.set $x - (i32.const 1) - ) - ) - (catch_all - (nop) - ) - ) - (local.set $x - (i32.const 1) - ) - ) - (func $try5 - (local $x i32) - (try $try - (do - (local.set $x - (i32.const 1) - ) - (call $foo) - ) - (catch_all - (nop) - ) - ) - (drop - (i32.const 1) - ) - ) - (func $nested-try1 - (local $x i32) - (try $try - (do - (try $l0 - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (rethrow $l0) - ) - ) - ) - (catch_all - (local.set $x - (i32.const 1) - ) - ) - ) - (drop - (i32.const 1) - ) - ) - (func $nested-try2 - (local $x i32) - (try $try - (do - (try $l0 - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (local.set $x - (i32.const 1) - ) - (rethrow $l0) - ) - ) - ) - (catch_all - (nop) - ) - ) - (drop - (i32.const 1) - ) - ) - (func $nested-try3 - (local $x i32) - (try $try - (do - (try $l0 - (do - (throw $e - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - (local.set $x - (i32.const 1) - ) - (rethrow $l0) - ) - ) - ) - (catch_all - (nop) - ) - ) - (local.set $x - (i32.const 1) - ) - ) - (func $nested-catch1 - (local $x i32) - (try $try - (do - (throw $e - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - ) - (catch $e2 - (try $try6 - (do - (throw $e - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - ) - (catch $e2 - (local.set $x - (i32.const 1) - ) - ) - ) - ) - ) - (local.set $x - (i32.const 1) - ) - ) - (func $nested-catch2 - (local $x i32) - (try $try - (do - (throw $e - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - (local.set $x - (i32.const 1) - ) - ) - (catch_all - (try $try7 - (do - (throw $e - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - (local.set $x - (i32.const 1) - ) - ) - (catch_all - (local.set $x - (i32.const 1) - ) - ) - ) - ) - ) - (drop - (i32.const 1) - ) - ) ) diff --git a/test/passes/rse_all-features.wast b/test/passes/rse_all-features.wast index 8192ecea1..8700c232c 100644 --- a/test/passes/rse_all-features.wast +++ b/test/passes/rse_all-features.wast @@ -286,192 +286,4 @@ ) ) ) - - (event $e (attr 0) (param i32)) - (event $e2 (attr 0)) - (func $try1 - (local $x i32) - (try - (do) - (catch_all - (local.set $x (i32.const 1)) - ) - ) - ;; try will not throw. So this should NOT be dropped - (local.set $x (i32.const 1)) - ) - (func $try2 - (local $x i32) - (try - (do - (throw $e (i32.const 0)) - (local.set $x (i32.const 1)) - ) - (catch_all) - ) - ;; local.set is after 'throw' so it will not run. This should NOT be - ;; dropped. - (local.set $x (i32.const 1)) - ) - (func $try3 - (local $x i32) - (try - (do - (throw $e (i32.const 0)) - ) - (catch_all - (local.set $x (i32.const 1)) - ) - ) - ;; try body will throw and catch_all contains the same local.set. This - ;; should be dropped. - (local.set $x (i32.const 1)) - ) - (func $foo) - (func $try4 - (local $x i32) - (try - (do - (call $foo) - (local.set $x (i32.const 1)) - ) - (catch_all) - ) - ;; (call $foo) may throw and the local.set may not run, so this should NOT - ;; be dropped - (local.set $x (i32.const 1)) - ) - (func $try5 - (local $x i32) - (try - (do - (local.set $x (i32.const 1)) - (call $foo) - ) - (catch_all) - ) - ;; Even if (call $foo) throws, local.set runs before it, so this should be - ;; dropped - (local.set $x (i32.const 1)) - ) - (func $nested-try1 - (local $x i32) - (try - (do - (try $l0 - (do - (throw $e (i32.const 0)) - ) - (catch_all - (rethrow $l0) - ) - ) - ) - (catch_all - (local.set $x (i32.const 1)) - ) - ) - ;; The exception is caught by the inner catch_all and rethrown and again - ;; caught by the outer catch_all, which runs the local.set. So this should - ;; be dropped. - (local.set $x (i32.const 1)) - ) - (func $nested-try2 - (local $x i32) - (try - (do - (try $l0 - (do - (throw $e (i32.const 0)) - ) - (catch_all - (local.set $x (i32.const 1)) - (rethrow $l0) - ) - ) - ) - (catch_all) - ) - ;; The exception is caught by the inner catch_all, which runs the local.set, - ;; so this should be dropped - (local.set $x (i32.const 1)) - ) - (func $nested-try3 - (local $x i32) - (try - (do - (try $l0 - (do - (throw $e (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - (local.set $x (i32.const 1)) - (rethrow $l0) - ) - ) - ) - (catch_all) - ) - ;; Unlike nested-try2, the exception may not be caught by the inner catch, - ;; so the local.set may not run. So this should NOT be dropped. - (local.set $x (i32.const 1)) - ) - (func $nested-catch1 - (local $x i32) - (try - (do - (throw $e (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - ) - (catch $e2 - (try - (do - (throw $e (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - ) - (catch $e2 - (local.set $x (i32.const 1)) - ) - ) - ) - ) - ;; This should NOT be dropped because the exception might not be caught by - ;; the inner catches, and the local.set above us may not have run, and - ;; other possible code paths do not even set the local. - (local.set $x (i32.const 1)) - ) - (func $nested-catch2 - (local $x i32) - (try - (do - (throw $e (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - (local.set $x (i32.const 1)) - ) - (catch_all - (try - (do - (throw $e (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - (local.set $x (i32.const 1)) - ) - (catch_all - (local.set $x (i32.const 1)) - ) - ) - ) - ) - ;; This should be dropped because the exception is guaranteed to be caught - ;; by one of the catches and it will set the local to 1. - (local.set $x (i32.const 1)) - ) ) diff --git a/test/passes/simplify-locals_all-features.txt b/test/passes/simplify-locals_all-features.txt index 0cf412863..de387c27b 100644 --- a/test/passes/simplify-locals_all-features.txt +++ b/test/passes/simplify-locals_all-features.txt @@ -1895,92 +1895,6 @@ ) ) (module - (type $none_=>_none (func)) - (type $i32_=>_none (func (param i32))) - (type $i32_i32_=>_none (func (param i32 i32))) - (type $none_=>_i32 (func (result i32))) - (event $e-i32 (attr 0) (param i32)) - (func $foo (param $0 i32) (param $1 i32) - (nop) - ) - (func $pop-cannot-be-sinked - (local $0 i32) - (try $try - (do - (nop) - ) - (catch $e-i32 - (local.set $0 - (pop i32) - ) - (call $foo - (i32.const 3) - (local.get $0) - ) - ) - ) - ) - (func $pop-within-catch-can-be-sinked - (local $0 i32) - (try $try - (do - (nop) - ) - (catch_all - (nop) - (call $foo - (i32.const 3) - (try $try0 (result i32) - (do - (i32.const 0) - ) - (catch $e-i32 - (pop i32) - ) - ) - ) - ) - ) - ) - (func $bar (result i32) - (i32.const 3) - ) - (func $call-cannot-be-sinked-into-try - (local $0 i32) - (local.set $0 - (call $bar) - ) - (try $try - (do - (drop - (local.get $0) - ) - ) - (catch $e-i32 - (drop - (pop i32) - ) - ) - ) - ) - (func $non-call-can-be-sinked-into-try - (local $0 i32) - (nop) - (try $try - (do - (drop - (i32.const 3) - ) - ) - (catch $e-i32 - (drop - (pop i32) - ) - ) - ) - ) -) -(module (type $none_=>_i32 (func (result i32))) (memory $0 (shared 1 1)) (data "data") diff --git a/test/passes/simplify-locals_all-features.wast b/test/passes/simplify-locals_all-features.wast index d37af9b6d..7d153efd9 100644 --- a/test/passes/simplify-locals_all-features.wast +++ b/test/passes/simplify-locals_all-features.wast @@ -1671,77 +1671,6 @@ (local.get $1) ) ) -(module - (event $e-i32 (attr 0) (param i32)) - (func $foo (param i32 i32)) - (func $pop-cannot-be-sinked (local $0 i32) - (try - (do) - (catch $e-i32 - ;; This (local.set $0) of (pop i32) cannot be sunk to (local.get $0) - ;; below, because the pop should follow right after 'catch'. - (local.set $0 (pop i32)) - (call $foo - (i32.const 3) - (local.get $0) - ) - ) - ) - ) - - (func $pop-within-catch-can-be-sinked (local $0 i32) - (try - (do) - (catch_all - ;; This whole 'try' body can be sinked to eliminate local.set / - ;; local.get. Even though it contains a pop, it is enclosed within - ;; try-catch, so it is OK. - (local.set $0 - (try (result i32) - (do (i32.const 0)) - (catch $e-i32 (pop i32)) - ) - ) - (call $foo - (i32.const 3) - (local.get $0) - ) - ) - ) - ) - - (func $bar (result i32) (i32.const 3)) - (func $call-cannot-be-sinked-into-try (local $0 i32) - (drop - ;; This local.tee should NOT be sinked into 'try' below, because it may - ;; throw - (local.tee $0 (call $bar)) - ) - (try - (do - (drop (local.get $0)) - ) - (catch $e-i32 - (drop (pop i32)) - ) - ) - ) - - (func $non-call-can-be-sinked-into-try (local $0 i32) - (drop - ;; This local.tee can be sinked into 'try' below, because it cannot throw - (local.tee $0 (i32.const 3)) - ) - (try - (do - (drop (local.get $0)) - ) - (catch $e-i32 - (drop (pop i32)) - ) - ) - ) -) ;; data.drop has global side effects (module (memory $0 (shared 1 1)) diff --git a/test/passes/vacuum_all-features.txt b/test/passes/vacuum_all-features.txt index 3dd051992..b95959552 100644 --- a/test/passes/vacuum_all-features.txt +++ b/test/passes/vacuum_all-features.txt @@ -436,60 +436,6 @@ ) (module (type $none_=>_none (func)) - (type $i32_=>_none (func (param i32))) - (event $e (attr 0) (param i32)) - (event $e2 (attr 0) (param i32)) - (func $try-test - (nop) - ) - (func $inner-try-catch_all-test - (local $0 i32) - (try $try0 - (do - (throw $e - (i32.const 0) - ) - ) - (catch_all - (local.set $0 - (i32.const 1) - ) - ) - ) - ) - (func $inner-try-catch-test - (local $0 i32) - (try $try - (do - (try $try1 - (do - (throw $e2 - (i32.const 0) - ) - ) - (catch $e - (drop - (pop i32) - ) - (local.set $0 - (i32.const 1) - ) - ) - ) - ) - (catch $e - (drop - (pop i32) - ) - ) - ) - ) - (func $br-in-catch - (unreachable) - ) -) -(module - (type $none_=>_none (func)) (func $foo (nop) ) diff --git a/test/passes/vacuum_all-features.wast b/test/passes/vacuum_all-features.wast index c074fe234..8a6d52022 100644 --- a/test/passes/vacuum_all-features.wast +++ b/test/passes/vacuum_all-features.wast @@ -797,79 +797,6 @@ ) (module - (event $e (attr 0) (param i32)) - (event $e2 (attr 0) (param i32)) - ;; When try body does not throw, try-body can be replaced with the try body - (func $try-test - (try - (do - (drop (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - ) - ) - ) - - ;; The exception thrown in the inner try is caught by the inner catch_all, so - ;; the outer try body does not throw and the outer try-catch can be removed - (func $inner-try-catch_all-test (local $0 i32) - (try - (do - (try - (do - (throw $e (i32.const 0)) - ) - (catch_all - (local.set $0 (i32.const 1)) - ) - ) - ) - (catch $e - (drop (pop i32)) - ) - ) - ) - - ;; The exception thrown in the inner try will not be caught by the inner - ;; catch, so the outer try-catch cannot be removed - (func $inner-try-catch-test (local $0 i32) - (try - (do - (try - (do - (throw $e2 (i32.const 0)) - ) - (catch $e - (drop (pop i32)) - (local.set $0 (i32.const 1)) - ) - ) - ) - (catch $e - (drop (pop i32)) - ) - ) - ) - - ;; When catch body is removed, the removal of 'br' inside the catch body - ;; should be propagated up to the outer block, so that its type will be - ;; correctly updated to unreachable. - (func $br-in-catch - (block $label$1 - (try - (do - (unreachable) - ) - (catch $e - (drop (pop i32)) - (br $label$1) - ) - ) - ) - ) -) -(module (type $A (struct (field (mut i32)))) (func $foo (drop |