blob: 10de158d4b620fc75ab846124e637cf38ce4a2b1 [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: wasm-opt %s -all --translate-to-new-eh -S -o - | filecheck %s
;; RUN: wasm-opt %s -all --translate-to-new-eh -S -o %t
;; RUN: wasm-opt %t -all --optimize-level=3 --generate-stack-ir --optimize-stack-ir --print-stack-ir | filecheck %s --check-prefix STACKIR-OPT
(module
;; CHECK: (type $0 (func (result i32 i64)))
;; CHECK: (type $1 (func))
;; CHECK: (type $2 (func (result i32)))
;; CHECK: (type $3 (func (result i32 exnref)))
;; CHECK: (type $4 (func (result i32 i64 exnref)))
;; CHECK: (type $5 (func (param i32)))
;; CHECK: (type $6 (func (param i32 i64)))
;; CHECK: (tag $e-empty)
;; STACKIR-OPT: (type $0 (func (result i32 i64)))
;; STACKIR-OPT: (type $1 (func))
;; STACKIR-OPT: (type $2 (func (result i32)))
;; STACKIR-OPT: (type $3 (func (result i32 exnref)))
;; STACKIR-OPT: (type $4 (func (result i32 i64 exnref)))
;; STACKIR-OPT: (type $5 (func (param i32)))
;; STACKIR-OPT: (type $6 (func (param i32 i64)))
;; STACKIR-OPT: (tag $e-empty)
(tag $e-empty)
;; CHECK: (tag $e-i32 (param i32))
;; STACKIR-OPT: (tag $e-i32 (param i32))
(tag $e-i32 (param i32))
;; CHECK: (tag $e-i32-i64 (param i32 i64))
;; STACKIR-OPT: (tag $e-i32-i64 (param i32 i64))
(tag $e-i32-i64 (param i32 i64))
;; CHECK: (func $foo (type $1)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $foo (type $1)
;; STACKIR-OPT-NEXT: )
(func $foo)
;; CHECK: (func $bar (type $1)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $bar (type $1)
;; STACKIR-OPT-NEXT: )
(func $bar)
;; CHECK: (func $baz (type $1)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $baz (type $1)
;; STACKIR-OPT-NEXT: )
(func $baz)
;; ---------------------------------------------------------------------------
;; Basic tests for all combinations of try body's type (none, single, and
;; tuple) and the catch's tag type (none, single, and tuple) and with /
;; without rethrows
;; CHECK: (func $try-none-tag-none (type $1)
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (block $catch1
;; CHECK-NEXT: (try_table (catch $e-empty $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-none-tag-none (type $1)
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1
;; STACKIR-OPT-NEXT: try_table (catch $e-empty $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-none-tag-none
;; try's type is none and catch's tag type is none
(try $l0
(do
(call $foo)
)
(catch $e-empty ;; converted to catch
(call $foo)
)
(catch_all ;; converted to catch_all
(call $bar)
)
)
)
;; CHECK: (func $try-none-tag-none-with-rethrow (type $1)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result exnref)
;; CHECK-NEXT: (try_table (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-none-tag-none-with-rethrow (type $1)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-none-tag-none-with-rethrow
;; try's type is none and catch's tag type is none, and there are rethrows
(try $l0
(do
(call $foo)
)
(catch $e-empty ;; converted to catch_ref, because of rethrow
(rethrow $l0)
)
(catch_all ;; converted to catch_all_ref, because of rethrow
(rethrow $l0)
)
)
)
;; CHECK: (func $try-none-tag-single (type $1)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result i32)
;; CHECK-NEXT: (try_table (catch $e-i32 $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-none-tag-single (type $1)
;; STACKIR-OPT-NEXT: (local $0 i32)
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1 (result i32)
;; STACKIR-OPT-NEXT: try_table (catch $e-i32 $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: drop
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-none-tag-single
;; try's type is none and catch's tag type is single
(try $l0
(do
(call $foo)
)
(catch $e-i32
(drop
(pop i32)
)
)
(catch_all
(call $bar)
)
)
)
;; CHECK: (func $try-none-tag-single-with-rethrow (type $1)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 (tuple i32 exnref))
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block $catch1 (type $3) (result i32 exnref)
;; CHECK-NEXT: (try_table (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-none-tag-single-with-rethrow (type $1)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 i32)
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 exnref))
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (type $3) (result i32 exnref)
;; STACKIR-OPT-NEXT: try_table (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 2 0
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 2 1
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: drop
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-none-tag-single-with-rethrow
;; try's type is none and catch's tag type is single, and there are rethrows
(try $l0
(do
(call $foo)
)
(catch $e-i32
(drop
(pop i32)
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-none-tag-tuple (type $1)
;; CHECK-NEXT: (local $0 (tuple i32 i64))
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (type $0) (result i32 i64)
;; CHECK-NEXT: (try_table (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-none-tag-tuple (type $1)
;; STACKIR-OPT-NEXT: (local $0 (tuple i32 i64))
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: try_table (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: tuple.drop 2
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-none-tag-tuple
;; try's type is none and catch's tag type is tuple
(try $l0
(do
(call $foo)
)
(catch $e-i32-i64
(tuple.drop 2
(pop (tuple i32 i64))
)
)
(catch_all
(call $bar)
)
)
)
;; CHECK: (func $try-none-tag-tuple-with-rethrow (type $1)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 (tuple i32 i64))
;; CHECK-NEXT: (local $2 (tuple i32 i64 exnref))
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block $catch1 (type $4) (result i32 i64 exnref)
;; CHECK-NEXT: (try_table (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-none-tag-tuple-with-rethrow (type $1)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 (tuple i32 i64))
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 i64 exnref))
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (type $4) (result i32 i64 exnref)
;; STACKIR-OPT-NEXT: try_table (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 0
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 1
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: local.set $1
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 2
;; STACKIR-OPT-NEXT: local.get $1
;; STACKIR-OPT-NEXT: tuple.drop 2
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-none-tag-tuple-with-rethrow
;; try's type is none and catch's tag type is tuple, and there are rethrows
(try $l0
(do
(call $foo)
)
(catch $e-i32-i64
(tuple.drop 2
(pop (tuple i32 i64))
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-single-tag-none (type $2) (result i32)
;; CHECK-NEXT: (block $outer0 (result i32)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (block $catch1
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (result i32) (catch $e-empty $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-single-tag-none (type $2) (result i32)
;; STACKIR-OPT-NEXT: block $outer0 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1
;; STACKIR-OPT-NEXT: try_table (result i32) (catch $e-empty $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 1
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-single-tag-none (result i32)
;; try's type is single and catch's tag type is none
(try $l0 (result i32)
(do
(call $foo)
(i32.const 0)
)
(catch $e-empty
(i32.const 1)
)
(catch_all
(i32.const 2)
)
)
)
;; CHECK: (func $try-single-tag-none-with-rethrow (type $2) (result i32)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (block $outer0 (result i32)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result exnref)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (result i32) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-single-tag-none-with-rethrow (type $2) (result i32)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: block $outer0 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (result exnref)
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-single-tag-none-with-rethrow (result i32)
;; try's type is single and catch's tag type is none, and there are rethrows
(try $l0 (result i32)
(do
(call $foo)
(i32.const 0)
)
(catch $e-empty
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-single-tag-single (type $2) (result i32)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (block $outer0 (result i32)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result i32)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (result i32) (catch $e-i32 $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-single-tag-single (type $2) (result i32)
;; STACKIR-OPT-NEXT: (local $0 i32)
;; STACKIR-OPT-NEXT: block $outer0 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1 (result i32)
;; STACKIR-OPT-NEXT: try_table (result i32) (catch $e-i32 $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-single-tag-single (result i32)
;; try's type is single and catch's tag type is single
(try $l0 (result i32)
(do
(call $foo)
(i32.const 0)
)
(catch $e-i32
(pop i32)
)
(catch_all
(i32.const 2)
)
)
)
;; CHECK: (func $try-single-tag-single-with-rethrow (type $2) (result i32)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 (tuple i32 exnref))
;; CHECK-NEXT: (block $outer0 (result i32)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block $catch1 (type $3) (result i32 exnref)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (result i32) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-single-tag-single-with-rethrow (type $2) (result i32)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 i32)
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 exnref))
;; STACKIR-OPT-NEXT: block $outer0 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (type $3) (result i32 exnref)
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 2 0
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 2 1
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: drop
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-single-tag-single-with-rethrow (result i32)
;; try's type is single and catch's tag type is single, and there are
;; rethrows
(try $l0 (result i32)
(do
(call $foo)
(i32.const 0)
)
(catch $e-i32
(drop
(pop i32)
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-single-tag-tuple (type $2) (result i32)
;; CHECK-NEXT: (local $0 (tuple i32 i64))
;; CHECK-NEXT: (block $outer0 (result i32)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (type $0) (result i32 i64)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (result i32) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-single-tag-tuple (type $2) (result i32)
;; STACKIR-OPT-NEXT: (local $0 (tuple i32 i64))
;; STACKIR-OPT-NEXT: block $outer0 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: try_table (result i32) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: tuple.drop 2
;; STACKIR-OPT-NEXT: i32.const 1
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-single-tag-tuple (result i32)
;; try's type is single and catch's tag type is tuple
(try $l0 (result i32)
(do
(call $foo)
(i32.const 0)
)
(catch $e-i32-i64
(tuple.drop 2
(pop (tuple i32 i64))
)
(i32.const 1)
)
(catch_all
(i32.const 2)
)
)
)
;; CHECK: (func $try-single-tag-tuple-with-rethrow (type $2) (result i32)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 (tuple i32 i64))
;; CHECK-NEXT: (local $2 (tuple i32 i64 exnref))
;; CHECK-NEXT: (block $outer0 (result i32)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block $catch1 (type $4) (result i32 i64 exnref)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (result i32) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-single-tag-tuple-with-rethrow (type $2) (result i32)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 (tuple i32 i64))
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 i64 exnref))
;; STACKIR-OPT-NEXT: block $outer0 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (type $4) (result i32 i64 exnref)
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 0
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 1
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: local.set $1
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 2
;; STACKIR-OPT-NEXT: local.get $1
;; STACKIR-OPT-NEXT: tuple.drop 2
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-single-tag-tuple-with-rethrow (result i32)
;; try's type is single and catch's tag type is tuple, and there are
;; rethrows
(try $l0 (result i32)
(do
(call $foo)
(i32.const 0)
)
(catch $e-i32-i64
(tuple.drop 2
(pop (tuple i32 i64))
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-tuple-tag-none (type $0) (result i32 i64)
;; CHECK-NEXT: (block $outer0 (type $0) (result i32 i64)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (block $catch1
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (type $0) (result i32 i64) (catch $e-empty $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (i64.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-tuple-tag-none (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $outer0 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1
;; STACKIR-OPT-NEXT: try_table (type $0) (result i32 i64) (catch $e-empty $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 1
;; STACKIR-OPT-NEXT: i64.const 1
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 2
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-tuple-tag-none (result i32 i64)
;; try's type is tuple and catch's tag type is none
(try $l0 (result i32 i64)
(do
(call $foo)
(tuple.make 2
(i32.const 0)
(i64.const 0)
)
)
(catch $e-empty
(tuple.make 2
(i32.const 1)
(i64.const 1)
)
)
(catch_all
(tuple.make 2
(i32.const 2)
(i64.const 0)
)
)
)
)
;; CHECK: (func $try-tuple-tag-none-with-rethrow (type $0) (result i32 i64)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (block $outer0 (type $0) (result i32 i64)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result exnref)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (type $0) (result i32 i64) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-tuple-tag-none-with-rethrow (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: block $outer0 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (result exnref)
;; STACKIR-OPT-NEXT: try_table (type $0) (result i32 i64) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-tuple-tag-none-with-rethrow (result i32 i64)
;; try's type is tuple and catch's tag type is none, and there are rethrows
(try $l0 (result i32 i64)
(do
(call $foo)
(tuple.make 2
(i32.const 0)
(i64.const 0)
)
)
(catch $e-empty
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-tuple-tag-single (type $0) (result i32 i64)
;; CHECK-NEXT: (local $0 i32)
;; CHECK-NEXT: (block $outer0 (type $0) (result i32 i64)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result i32)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (type $0) (result i32 i64) (catch $e-i32 $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: (i64.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-tuple-tag-single (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: (local $0 i32)
;; STACKIR-OPT-NEXT: block $outer0 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1 (result i32)
;; STACKIR-OPT-NEXT: try_table (type $0) (result i32 i64) (catch $e-i32 $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 2
;; STACKIR-OPT-NEXT: i64.const 2
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-tuple-tag-single (result i32 i64)
;; try's type is tuple and catch's tag type is single
(try $l0 (result i32 i64)
(do
(call $foo)
(tuple.make 2
(i32.const 0)
(i64.const 0)
)
)
(catch $e-i32
(tuple.make 2
(pop i32)
(i64.const 0)
)
)
(catch_all
(tuple.make 2
(i32.const 2)
(i64.const 2)
)
)
)
)
;; CHECK: (func $try-tuple-tag-single-with-rethrow (type $0) (result i32 i64)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 (tuple i32 exnref))
;; CHECK-NEXT: (block $outer0 (type $0) (result i32 i64)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block $catch1 (type $3) (result i32 exnref)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (type $0) (result i32 i64) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (block (type $0) (result i32 i64)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-tuple-tag-single-with-rethrow (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 i32)
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 exnref))
;; STACKIR-OPT-NEXT: block $outer0 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (type $3) (result i32 exnref)
;; STACKIR-OPT-NEXT: try_table (type $0) (result i32 i64) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 2 0
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 2 1
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: drop
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-tuple-tag-single-with-rethrow (result i32 i64)
;; try's type is tuple and catch's tag type is single, and there are
;; rethrows
(try $l0 (result i32 i64)
(do
(call $foo)
(tuple.make 2
(i32.const 0)
(i64.const 0)
)
)
(catch $e-i32
(drop
(pop i32)
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $try-tuple-tag-tuple (type $0) (result i32 i64)
;; CHECK-NEXT: (local $0 (tuple i32 i64))
;; CHECK-NEXT: (block $outer0 (type $0) (result i32 i64)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (type $0) (result i32 i64)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (type $0) (result i32 i64) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: (i64.const 2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-tuple-tag-tuple (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: (local $0 (tuple i32 i64))
;; STACKIR-OPT-NEXT: block $outer0 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: block $catch1 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: try_table (type $0) (result i32 i64) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 2
;; STACKIR-OPT-NEXT: i64.const 2
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-tuple-tag-tuple (result i32 i64)
;; try's type is tuple and catch's tag type is tuple
(try $l0 (result i32 i64)
(do
(call $foo)
(tuple.make 2
(i32.const 0)
(i64.const 0)
)
)
(catch $e-i32-i64
(pop (tuple i32 i64))
)
(catch_all
(tuple.make 2
(i32.const 2)
(i64.const 2)
)
)
)
)
;; CHECK: (func $try-tuple-tag-tuple-with-rethrow (type $0) (result i32 i64)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 (tuple i32 i64))
;; CHECK-NEXT: (local $2 (tuple i32 i64 exnref))
;; CHECK-NEXT: (block $outer0 (type $0) (result i32 i64)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all2 (result exnref)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block $catch1 (type $4) (result i32 i64 exnref)
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (try_table (type $0) (result i32 i64) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i64.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0
;; CHECK-NEXT: (block (type $0) (result i32 i64)
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-tuple-tag-tuple-with-rethrow (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 (tuple i32 i64))
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 i64 exnref))
;; STACKIR-OPT-NEXT: block $outer0 (type $0) (result i32 i64)
;; STACKIR-OPT-NEXT: block $catch_all2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1 (type $4) (result i32 i64 exnref)
;; STACKIR-OPT-NEXT: try_table (type $0) (result i32 i64) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: i64.const 0
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 0
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 1
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: local.set $1
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.extract 3 2
;; STACKIR-OPT-NEXT: local.get $1
;; STACKIR-OPT-NEXT: tuple.drop 2
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-tuple-tag-tuple-with-rethrow (result i32 i64)
;; try's type is tuple and catch's tag type is tuple, and there are
;; rethrows
(try $l0 (result i32 i64)
(do
(call $foo)
(tuple.make 2
(i32.const 0)
(i64.const 0)
)
)
(catch $e-i32-i64
(tuple.drop 2
(pop (tuple i32 i64))
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; ---------------------------------------------------------------------------
;; More try-catch tests
;; CHECK: (func $catchless-delegateless-try (type $1)
;; CHECK-NEXT: (try_table
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $catchless-delegateless-try (type $1)
;; STACKIR-OPT-NEXT: try_table
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $catchless-delegateless-try
(try
(do
(call $foo)
)
)
)
;; CHECK: (func $multiple-catches-and-catch_all (type $1)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (local $2 (tuple i32 i64))
;; CHECK-NEXT: (local $3 (tuple i32 exnref))
;; CHECK-NEXT: (local $4 (tuple i32 i64 exnref))
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all4 (result exnref)
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (block $catch3 (type $4) (result i32 i64 exnref)
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (block $catch2 (type $3) (result i32 exnref)
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch1 (result exnref)
;; CHECK-NEXT: (try_table (catch_ref $e-empty $catch1) (catch_ref $e-i32 $catch2) (catch_ref $e-i32-i64 $catch3) (catch_all_ref $catch_all4)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (tuple.drop 2
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $multiple-catches-and-catch_all (type $1)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 i32)
;; STACKIR-OPT-NEXT: (local $2 (tuple i32 i64))
;; STACKIR-OPT-NEXT: (local $3 (tuple i32 exnref))
;; STACKIR-OPT-NEXT: (local $4 (tuple i32 i64 exnref))
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch_all4 (result exnref)
;; STACKIR-OPT-NEXT: block $catch3 (type $4) (result i32 i64 exnref)
;; STACKIR-OPT-NEXT: block $catch2 (type $3) (result i32 exnref)
;; STACKIR-OPT-NEXT: block $catch1 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_ref $e-empty $catch1) (catch_ref $e-i32 $catch2) (catch_ref $e-i32-i64 $catch3) (catch_all_ref $catch_all4)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $3
;; STACKIR-OPT-NEXT: local.get $3
;; STACKIR-OPT-NEXT: tuple.extract 2 0
;; STACKIR-OPT-NEXT: local.get $3
;; STACKIR-OPT-NEXT: tuple.extract 2 1
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: drop
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $4
;; STACKIR-OPT-NEXT: local.get $4
;; STACKIR-OPT-NEXT: tuple.extract 3 0
;; STACKIR-OPT-NEXT: local.get $4
;; STACKIR-OPT-NEXT: tuple.extract 3 1
;; STACKIR-OPT-NEXT: tuple.make 2
;; STACKIR-OPT-NEXT: local.set $2
;; STACKIR-OPT-NEXT: local.get $4
;; STACKIR-OPT-NEXT: tuple.extract 3 2
;; STACKIR-OPT-NEXT: local.get $2
;; STACKIR-OPT-NEXT: tuple.drop 2
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $multiple-catches-and-catch_all
(try $l0
(do
(call $foo)
)
(catch $e-empty
(rethrow $l0)
)
(catch $e-i32
(drop
(pop i32)
)
(rethrow $l0)
)
(catch $e-i32-i64
(tuple.drop 2
(pop (tuple i32 i64))
)
(rethrow $l0)
)
(catch_all
(rethrow $l0)
)
)
)
;; CHECK: (func $nested-catch-rethrows (type $1)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (local $1 exnref)
;; CHECK-NEXT: (block $outer3
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch_all4 (result exnref)
;; CHECK-NEXT: (try_table (catch_all_ref $catch_all4)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $outer0
;; CHECK-NEXT: (local.set $1
;; CHECK-NEXT: (block $catch2 (result exnref)
;; CHECK-NEXT: (block $catch1
;; CHECK-NEXT: (try_table (catch $e-empty $catch1) (catch_ref $e-empty $catch2)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $nested-catch-rethrows (type $1)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: (local $1 exnref)
;; STACKIR-OPT-NEXT: block $outer3
;; STACKIR-OPT-NEXT: block $catch_all4 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $catch_all4)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer3
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.set $0
;; STACKIR-OPT-NEXT: block $outer0
;; STACKIR-OPT-NEXT: block $catch2 (result exnref)
;; STACKIR-OPT-NEXT: block $catch1
;; STACKIR-OPT-NEXT: try_table (catch $e-empty $catch1) (catch_ref $e-empty $catch2)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: local.get $0
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $nested-catch-rethrows
(try $l0
(do
(call $foo)
)
(catch_all
(try $l1
(do
(call $foo)
)
;; This catch will be converted to a 'catch' clause in a try_table,
;; because the rethrow in this catch body does not refer to the
;; current try
(catch $e-empty
(rethrow $l0)
)
;; This catch will be converted to a 'catch_ref' clause in a
;; try_table, because the rethrow in this catch body refers to the
;; current try
(catch $e-empty
(rethrow $l1)
)
)
)
)
)
;; ---------------------------------------------------------------------------
;; try-delegate tests
;; CHECK: (func $delegate-target-outer-try-none (type $1)
;; CHECK-NEXT: (block $outer1
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (try_table (catch_all $catch_all2)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l00 (result exnref)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (try_table (catch_all_ref $l00)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $baz)
;; CHECK-NEXT: (br $outer1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-target-outer-try-none (type $1)
;; STACKIR-OPT-NEXT: block $outer1
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: try_table (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: block $l00 (result exnref)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $baz
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $delegate-target-outer-try-none
;; An inner try-delegate targets an outer try whose type is none
(try $l0
(do
(call $foo)
(try
(do
(call $bar)
)
(delegate $l0)
)
(call $baz)
)
(catch_all)
)
)
;; CHECK: (func $multiple-delegates-target-outer-try-none (type $1)
;; CHECK-NEXT: (block $outer1
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (try_table (catch_all $catch_all2)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l00 (result exnref)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (try_table (catch_all_ref $l00)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: (try_table (catch_all_ref $l00)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $baz)
;; CHECK-NEXT: (br $outer1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $multiple-delegates-target-outer-try-none (type $1)
;; STACKIR-OPT-NEXT: block $outer1
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: try_table (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: block $l00 (result exnref)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $baz
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $multiple-delegates-target-outer-try-none
;; Multiple inner try-delegates target an outer try whose type is none
(try $l0
(do
(call $foo)
(try
(do
(call $bar)
)
(delegate $l0)
)
(try
(do
(call $bar)
)
(delegate $l0)
)
(call $baz)
)
(catch_all)
)
)
;; CHECK: (func $delegate-target-outer-try-concrete (type $2) (result i32)
;; CHECK-NEXT: (block $outer1 (result i32)
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (br $outer1
;; CHECK-NEXT: (try_table (result i32) (catch_all $catch_all2)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l00 (result exnref)
;; CHECK-NEXT: (br $outer1
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (try_table (result i32) (catch_all_ref $l00)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-target-outer-try-concrete (type $2) (result i32)
;; STACKIR-OPT-NEXT: block $outer1 (result i32)
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: block $l00 (result exnref)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: i32.const 1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $delegate-target-outer-try-concrete (result i32)
;; An inner try-delegate targets an outer try whose type is concrete
(try $l0 (result i32)
(do
(call $foo)
(try (result i32)
(do
(call $bar)
(i32.const 0)
)
(delegate $l0)
)
)
(catch_all
(i32.const 1)
)
)
)
;; CHECK: (func $deletate-target-outer-try-unreachable (type $1)
;; CHECK-NEXT: (try_table
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l00 (result exnref)
;; CHECK-NEXT: (try_table (catch_all_ref $l00)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $deletate-target-outer-try-unreachable (type $1)
;; STACKIR-OPT-NEXT: try_table
;; STACKIR-OPT-NEXT: block $l00 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: return
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: )
(func $deletate-target-outer-try-unreachable
;; An inner try-delegate targets an outer try whose body type is unreachable
;; (due to a return). In this case we don't need an additional 'br' to an
;; outer block.
(try $l0
(do
(try
(do
(call $foo)
)
(delegate $l0)
)
(return)
)
)
)
;; CHECK: (func $delegate-target-caller-none (type $1)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $__binaryen_delegate_caller_target0 (result exnref)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $baz)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-target-caller-none (type $1)
;; STACKIR-OPT-NEXT: block $__binaryen_delegate_caller_target0 (result exnref)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $baz
;; STACKIR-OPT-NEXT: return
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: )
(func $delegate-target-caller-none
;; A try-delegate targets the caller whose type is none
(call $foo)
(try
(do
(call $bar)
)
(delegate 0)
)
(call $baz)
)
;; CHECK: (func $multiple-delegates-target-caller-none (type $1)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $__binaryen_delegate_caller_target0 (result exnref)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $baz)
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $multiple-delegates-target-caller-none (type $1)
;; STACKIR-OPT-NEXT: block $__binaryen_delegate_caller_target0 (result exnref)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: call $baz
;; STACKIR-OPT-NEXT: return
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: )
(func $multiple-delegates-target-caller-none
;; Multiple try-delegates target the caller whose type is none
(call $foo)
(try
(do
(call $bar)
)
(delegate 0)
)
(try
(do
(call $bar)
)
(delegate 0)
)
(call $baz)
)
;; CHECK: (func $delegate-target-caller-concrete (type $2) (result i32)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $__binaryen_delegate_caller_target0 (result exnref)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (try_table (result i32) (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (call $bar)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-target-caller-concrete (type $2) (result i32)
;; STACKIR-OPT-NEXT: block $__binaryen_delegate_caller_target0 (result exnref)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: call $bar
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: return
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: )
(func $delegate-target-caller-concrete (result i32)
;; A try-delegate targets the caller whose type is concrete
(call $foo)
(try (result i32)
(do
(call $bar)
(i32.const 0)
)
(delegate 0)
)
)
;; CHECK: (func $delegate-nested-more (type $1)
;; CHECK-NEXT: (block $outer3
;; CHECK-NEXT: (block $catch_all4
;; CHECK-NEXT: (try_table (catch_all $catch_all4)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l00 (result exnref)
;; CHECK-NEXT: (block $outer1
;; CHECK-NEXT: (block $catch_all2
;; CHECK-NEXT: (try_table (catch_all $catch_all2)
;; CHECK-NEXT: (try_table (catch_all_ref $l00)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-nested-more (type $1)
;; STACKIR-OPT-NEXT: block $outer3
;; STACKIR-OPT-NEXT: block $catch_all4
;; STACKIR-OPT-NEXT: try_table (catch_all $catch_all4)
;; STACKIR-OPT-NEXT: block $l00 (result exnref)
;; STACKIR-OPT-NEXT: block $outer1
;; STACKIR-OPT-NEXT: block $catch_all2
;; STACKIR-OPT-NEXT: try_table (catch_all $catch_all2)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer3
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $delegate-nested-more
(try $l0
(do
(try
(do
(try
(do
(call $foo)
)
(delegate $l0)
)
)
(catch_all)
)
)
(catch_all)
)
)
;; CHECK: (func $delegate-target-outer-try-delegate (type $1)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $__binaryen_delegate_caller_target0 (result exnref)
;; CHECK-NEXT: (block $outer2
;; CHECK-NEXT: (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l01 (result exnref)
;; CHECK-NEXT: (try_table (catch_all_ref $l01)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-target-outer-try-delegate (type $1)
;; STACKIR-OPT-NEXT: block $__binaryen_delegate_caller_target0 (result exnref)
;; STACKIR-OPT-NEXT: block $outer2
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: block $l01 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l01)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: return
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: )
(func $delegate-target-outer-try-delegate
;; An inner try-delegate targets an outer try-delegate that targets the
;; caller
(try $l0
(do
(try
(do
(call $foo)
)
(delegate $l0)
)
)
(delegate 0)
)
)
;; CHECK: (func $delegate-target-outer-try-delegate-concrete (type $2) (result i32)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $__binaryen_delegate_caller_target0 (result exnref)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (block $outer2 (result i32)
;; CHECK-NEXT: (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l01 (result exnref)
;; CHECK-NEXT: (br $outer2
;; CHECK-NEXT: (try_table (result i32) (catch_all_ref $l01)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $delegate-target-outer-try-delegate-concrete (type $2) (result i32)
;; STACKIR-OPT-NEXT: block $__binaryen_delegate_caller_target0 (result exnref)
;; STACKIR-OPT-NEXT: block $outer2 (result i32)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: block $l01 (result exnref)
;; STACKIR-OPT-NEXT: try_table (result i32) (catch_all_ref $l01)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: i32.const 0
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: return
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: )
(func $delegate-target-outer-try-delegate-concrete (result i32)
;; An inner try-delegate targets an outer try-delegate that targets the
;; caller, where the type of the try-delegates and the caller is concrete
(try $l0 (result i32)
(do
(try (result i32)
(do
(call $foo)
(i32.const 0)
)
(delegate $l0)
)
)
(delegate 0)
)
)
;; CHECK: (func $throw_ref-in-resultless-block (type $2) (result i32)
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $__binaryen_delegate_caller_target0 (result exnref)
;; CHECK-NEXT: (return
;; CHECK-NEXT: (block
;; CHECK-NEXT: (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $throw_ref-in-resultless-block (type $2) (result i32)
;; STACKIR-OPT-NEXT: block $__binaryen_delegate_caller_target0 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $__binaryen_delegate_caller_target0)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: )
(func $throw_ref-in-resultless-block (result i32)
;; When the function return type is concrete, try-delegate that targets the
;; caller is translated to
;; (throw_ref
;; (block $__binaryen_delegate_caller_target (result exnref)
;; (return
;; function body
;; )
;; )
;; )
;; We should do that even if the function body's type is not concrete.
(block ;; This block doesn't have concrete result type
(try
(do
(call $foo)
)
(delegate 1)
)
(unreachable)
)
)
;; CHECK: (func $try-delegate-within-catchless-try (type $1)
;; CHECK-NEXT: (block $outer1
;; CHECK-NEXT: (try_table
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l00 (result exnref)
;; CHECK-NEXT: (try_table (catch_all_ref $l00)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-delegate-within-catchless-try (type $1)
;; STACKIR-OPT-NEXT: block $outer1
;; STACKIR-OPT-NEXT: try_table
;; STACKIR-OPT-NEXT: block $l00 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l00)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-delegate-within-catchless-try
(try $l0
(do
(try
(do
(call $foo)
)
(delegate $l0)
)
)
)
)
;; CHECK: (func $try-catch-rethrow-with-inner-delegate (type $1)
;; CHECK-NEXT: (local $0 exnref)
;; CHECK-NEXT: (block $outer2
;; CHECK-NEXT: (local.set $0
;; CHECK-NEXT: (block $catch3 (result exnref)
;; CHECK-NEXT: (try_table (catch_ref $e-empty $catch3)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $outer1
;; CHECK-NEXT: (try_table
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (block $l10 (result exnref)
;; CHECK-NEXT: (try_table (catch_all_ref $l10)
;; CHECK-NEXT: (call $foo)
;; CHECK-NEXT: )
;; CHECK-NEXT: (br $outer1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (throw_ref
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; STACKIR-OPT: (func $try-catch-rethrow-with-inner-delegate (type $1)
;; STACKIR-OPT-NEXT: (local $0 exnref)
;; STACKIR-OPT-NEXT: block $outer2
;; STACKIR-OPT-NEXT: block $catch3 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_ref $e-empty $catch3)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer2
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: block $outer1
;; STACKIR-OPT-NEXT: try_table
;; STACKIR-OPT-NEXT: block $l10 (result exnref)
;; STACKIR-OPT-NEXT: try_table (catch_all_ref $l10)
;; STACKIR-OPT-NEXT: call $foo
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: br $outer1
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: unreachable
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: throw_ref
;; STACKIR-OPT-NEXT: end
;; STACKIR-OPT-NEXT: )
(func $try-catch-rethrow-with-inner-delegate
(try $l0
(do
(call $foo)
)
(catch $e-empty
(try $l1
(do
(try
(do
(call $foo)
)
(delegate $l1)
)
)
)
(rethrow $l0)
)
)
)
)