| ;; 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 |
| ;; CHECK: (tag $e (param i32)) |
| (tag $e (param i32)) |
| ;; CHECK: (tag $e2 (param i32)) |
| (tag $e2 (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 (result i32) |
| ;; 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: (return |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $inner-try-catch_all-test (result i32) |
| (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 |
| (return (i32.const 1)) |
| ) |
| ) |
| ) |
| (catch $e |
| (drop (pop i32)) |
| ) |
| ) |
| (i32.const 2) |
| ) |
| |
| ;; 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) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $try-delegate-outer-target |
| ;; CHECK-NEXT: (local $0 i32) |
| ;; CHECK-NEXT: (try $label$0 |
| ;; CHECK-NEXT: (do |
| ;; CHECK-NEXT: (try $try |
| ;; CHECK-NEXT: (do |
| ;; CHECK-NEXT: (try $try2 |
| ;; CHECK-NEXT: (do |
| ;; CHECK-NEXT: (throw $e |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (delegate $label$0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (catch_all |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $try-delegate-outer-target |
| (local $0 i32) |
| (try $label$0 ;; outer try |
| (do |
| ;; If it were not for the inner (delegate $label0), this middle try |
| ;; cannot throw even if there is a throw in the inner try, because this |
| ;; try has a catch_all. And Vacuum can replace the outer try-catch with |
| ;; the try's body if the body doesn't throw. |
| ;; |
| ;; But because the inner try has a delegate that targets the outer try, |
| ;; this middle try can throw, and we can't do the optimization for |
| ;; the outer try. |
| (try ;; middle try |
| (do |
| (try ;; inner try |
| (do |
| (throw $e |
| (i32.const 0) |
| ) |
| ) |
| (delegate $label$0) |
| ) |
| ) |
| (catch_all) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $trivial-catch-all-of-throw |
| ;; CHECK-NEXT: (local $0 i32) |
| ;; CHECK-NEXT: (try $try3 |
| ;; CHECK-NEXT: (do |
| ;; CHECK-NEXT: (if |
| ;; CHECK-NEXT: (local.get $0) |
| ;; CHECK-NEXT: (throw $e |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (catch_all |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $trivial-catch-all-of-throw (local $0 i32) |
| ;; This try-catch's body throws, but the catch-all catches it, so the entire |
| ;; try can be optimized out. |
| (try |
| (do |
| (throw $e (i32.const 0)) |
| ) |
| (catch_all) |
| ) |
| ;; Here we also have a possible trap, so we can't do it. |
| (try |
| (do |
| (if |
| (local.get $0) |
| (throw $e (i32.const 0)) |
| (unreachable) |
| ) |
| ) |
| (catch_all) |
| ) |
| ) |
| ) |