;; 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 (type $0) ;; 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 (type $2) (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 (type $0) ;; 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 (type $0) ;; 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 (type $0) ;; 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 (type $0) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (try $try3 ;; CHECK-NEXT: (do ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (throw $e ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; 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) (then (throw $e (i32.const 0)) ) (else (unreachable) ) ) ) (catch_all) ) ) )