summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorHeejin Ahn <aheejin@gmail.com>2024-01-23 18:51:57 -0800
committerGitHub <noreply@github.com>2024-01-23 18:51:57 -0800
commit1ce851d7a2044cd1c121bec7de676a61aa147c79 (patch)
treeec1561b0955e5b54c3ef93dc69ce8f1875b94af6 /test
parent9090ce56fcc67e15005aeedc59c6bc6773220f11 (diff)
downloadbinaryen-1ce851d7a2044cd1c121bec7de676a61aa147c79.tar.gz
binaryen-1ce851d7a2044cd1c121bec7de676a61aa147c79.tar.bz2
binaryen-1ce851d7a2044cd1c121bec7de676a61aa147c79.zip
[EH] Add translator from old to new EH instructions (#6210)
This translates the old Phase 3 EH instructions, which include `try`, `catch`, `catch_all`, `delegate`, and `rethrow`, into the new EH instructions, which include `try_table` (with `catch` / `catch_ref` / `catch_all` / `catch_all_ref`) and `throw_ref`, passed at the Oct 2023 CG meeting. This translator can be used as a standalone tool by users of the previous EH toolchain to generate binaries for the new spec without recompiling, and also can be used at the end of the Binaryen pipeline to produce binaries for the new spec while the end-to-end toolchain implementation for the new spec is in progress. While the goal of this pass is not optimization, this tries to a little better than the most naive implementation, namely by omitting a few instructions where possible and trying to minimize the number of additional locals, because this can be used as a standalone translator or the last stage of the pipeline while we can't post-optimize the results because the whole pipeline (-On) is not ready for the new EH.
Diffstat (limited to 'test')
-rw-r--r--test/lit/help/wasm-opt.test3
-rw-r--r--test/lit/help/wasm2js.test3
-rw-r--r--test/lit/passes/translate-eh-old-to-new.wast1479
3 files changed, 1485 insertions, 0 deletions
diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test
index 132296d5b..07d218007 100644
--- a/test/lit/help/wasm-opt.test
+++ b/test/lit/help/wasm-opt.test
@@ -486,6 +486,9 @@
;; CHECK-NEXT:
;; CHECK-NEXT: --symbolmap (alias for print-function-map)
;; CHECK-NEXT:
+;; CHECK-NEXT: --translate-eh-old-to-new translate old EH instructions to
+;; CHECK-NEXT: new ones
+;; CHECK-NEXT:
;; CHECK-NEXT: --trap-mode-clamp replace trapping operations with
;; CHECK-NEXT: clamping semantics
;; CHECK-NEXT:
diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test
index 1d378f0ad..e81d07718 100644
--- a/test/lit/help/wasm2js.test
+++ b/test/lit/help/wasm2js.test
@@ -445,6 +445,9 @@
;; CHECK-NEXT:
;; CHECK-NEXT: --symbolmap (alias for print-function-map)
;; CHECK-NEXT:
+;; CHECK-NEXT: --translate-eh-old-to-new translate old EH instructions to
+;; CHECK-NEXT: new ones
+;; CHECK-NEXT:
;; CHECK-NEXT: --trap-mode-clamp replace trapping operations with
;; CHECK-NEXT: clamping semantics
;; CHECK-NEXT:
diff --git a/test/lit/passes/translate-eh-old-to-new.wast b/test/lit/passes/translate-eh-old-to-new.wast
new file mode 100644
index 000000000..b012a8536
--- /dev/null
+++ b/test/lit/passes/translate-eh-old-to-new.wast
@@ -0,0 +1,1479 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+;; RUN: wasm-opt %s -all --translate-eh-old-to-new -S -o - | filecheck %s
+
+(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)
+ (tag $e-empty)
+ ;; CHECK: (tag $e-i32 (param i32))
+ (tag $e-i32 (param i32))
+ ;; CHECK: (tag $e-i32-i64 (param i32 i64))
+ (tag $e-i32-i64 (param i32 i64))
+
+ ;; CHECK: (func $foo (type $1)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $foo)
+ ;; CHECK: (func $bar (type $1)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $bar)
+ ;; CHECK: (func $baz (type $1)
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-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: )
+ (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: )
+ (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: )
+ (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 (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: )
+ (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 (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: )
+ (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 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 (i32 i64))
+ ;; CHECK-NEXT: (local $2 (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: )
+ (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 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: )
+ (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: )
+ (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: )
+ (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 (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: )
+ (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 (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: )
+ (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 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 (i32 i64))
+ ;; CHECK-NEXT: (local $2 (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: )
+ (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 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: )
+ (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: )
+ (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: )
+ (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 (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: )
+ (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 (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: )
+ (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 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 (i32 i64))
+ ;; CHECK-NEXT: (local $2 (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: )
+ (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 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: )
+ (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 (i32 i64))
+ ;; CHECK-NEXT: (local $3 (i32 exnref))
+ ;; CHECK-NEXT: (local $4 (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: )
+ (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 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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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: )
+ (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)
+ )
+ )
+)