summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2022-12-21 11:47:48 -0600
committerGitHub <noreply@github.com>2022-12-21 09:47:48 -0800
commit49fb2e23bb3c932389f23fdda33a32d034ca9a0c (patch)
treefbe18fa7d4809a59a0d9577fb723bf1873d8adeb /test
parent94a45c6aba605f0f7e0a2fac227a2dd7c03a391f (diff)
downloadbinaryen-49fb2e23bb3c932389f23fdda33a32d034ca9a0c.tar.gz
binaryen-49fb2e23bb3c932389f23fdda33a32d034ca9a0c.tar.bz2
binaryen-49fb2e23bb3c932389f23fdda33a32d034ca9a0c.zip
Support `ref.test null` (#5368)
This new variant of ref.test returns 1 if the input is null.
Diffstat (limited to 'test')
-rw-r--r--test/example/c-api-kitchen-sink.c5
-rw-r--r--test/example/c-api-kitchen-sink.txt2
-rw-r--r--test/lit/binary/legacy-static-casts.test.wasmbin66 -> 66 bytes
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast149
-rw-r--r--test/spec/ref_test.wast330
5 files changed, 476 insertions, 10 deletions
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index 0dadeef1d..de105d239 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -1102,9 +1102,8 @@ void test_core() {
BinaryenI31New(module, makeInt32(module, 0)),
BinaryenI31Get(module, i31refExpr, 1),
BinaryenI31Get(module, BinaryenI31New(module, makeInt32(module, 2)), 0),
- BinaryenRefTest(module,
- BinaryenGlobalGet(module, "i8Array-global", i8Array),
- BinaryenTypeGetHeapType(i8Array)),
+ BinaryenRefTest(
+ module, BinaryenGlobalGet(module, "i8Array-global", i8Array), i8Array),
BinaryenRefCast(
module, BinaryenGlobalGet(module, "i8Array-global", i8Array), i8Array),
BinaryenStructNew(module, 0, 0, BinaryenTypeGetHeapType(i32Struct)),
diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt
index 41f96c184..1ee529eb3 100644
--- a/test/example/c-api-kitchen-sink.txt
+++ b/test/example/c-api-kitchen-sink.txt
@@ -2165,7 +2165,7 @@ BinaryenFeatureAll: 126975
)
)
(drop
- (ref.test $[mut:i8]
+ (ref.test null $[mut:i8]
(global.get $i8Array-global)
)
)
diff --git a/test/lit/binary/legacy-static-casts.test.wasm b/test/lit/binary/legacy-static-casts.test.wasm
index 2dcfc9f01..aef179b2a 100644
--- a/test/lit/binary/legacy-static-casts.test.wasm
+++ b/test/lit/binary/legacy-static-casts.test.wasm
Binary files differ
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index bd697419b..1bf72ae04 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -14,18 +14,18 @@
(field $i64 (mut i64))
))
+ ;; CHECK: (type $array (array (mut i8)))
+
;; CHECK: (type $A (struct (field i32)))
+ ;; NOMNL: (type $array (array (mut i8)))
+
;; NOMNL: (type $A (struct (field i32)))
(type $A (struct (field i32)))
- ;; CHECK: (type $B (struct_subtype (field i32) (field i32) (field f32) $A))
-
- ;; CHECK: (type $array (array (mut i8)))
- ;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A))
-
- ;; NOMNL: (type $array (array (mut i8)))
(type $array (array (mut i8)))
+ ;; CHECK: (type $B (struct_subtype (field i32) (field i32) (field f32) $A))
+ ;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A))
(type $B (struct_subtype (field i32) (field i32) (field f32) $A))
;; CHECK: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
@@ -1882,6 +1882,21 @@
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.test null $array
+ ;; CHECK-NEXT: (local.get $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.get $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (func $incompatible-test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct))
;; NOMNL-NEXT: (drop
@@ -1892,6 +1907,21 @@
;; NOMNL-NEXT: (i32.const 0)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.test null $array
+ ;; NOMNL-NEXT: (local.get $struct)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.as_non_null
+ ;; NOMNL-NEXT: (local.get $struct)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 0)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
(func $incompatible-test (param $struct (ref null $struct))
(drop
@@ -1900,6 +1930,20 @@
(local.get $struct)
)
)
+ (drop
+ ;; But this one might succeed due to a null, so don't optimize it.
+ (ref.test null $array
+ (local.get $struct)
+ )
+ )
+ (drop
+ ;; This one cannot succeed due to a null, so optimize it.
+ (ref.test null $array
+ (ref.as_non_null
+ (local.get $struct)
+ )
+ )
+ )
)
;; CHECK: (func $subtype-compatible (type $ref?|$A|_ref?|$B|_=>_none) (param $A (ref null $A)) (param $B (ref null $B))
@@ -1913,6 +1957,34 @@
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.get $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.get $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (func $subtype-compatible (type $ref?|$A|_ref?|$B|_=>_none) (param $A (ref null $A)) (param $B (ref null $B))
;; NOMNL-NEXT: (drop
@@ -1925,6 +1997,34 @@
;; NOMNL-NEXT: (local.get $B)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $B)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 1)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.as_non_null
+ ;; NOMNL-NEXT: (local.get $B)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 1)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.as_non_null
+ ;; NOMNL-NEXT: (local.get $B)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 1)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
(func $subtype-compatible (param $A (ref null $A)) (param $B (ref null $B))
(drop
@@ -1939,6 +2039,28 @@
(local.get $B)
)
)
+ (drop
+ ;; If the test is nullable, this will succeed.
+ (ref.test null $A
+ (local.get $B)
+ )
+ )
+ (drop
+ ;; We will also succeed if the input is non-nullable.
+ (ref.test $A
+ (ref.as_non_null
+ (local.get $B)
+ )
+ )
+ )
+ (drop
+ ;; Or if the test is nullable and the input is non-nullable.
+ (ref.test null $A
+ (ref.as_non_null
+ (local.get $B)
+ )
+ )
+ )
)
;; CHECK: (func $ref.test-unreachable (type $ref?|$A|_=>_none) (param $A (ref null $A))
;; CHECK-NEXT: (drop
@@ -1946,6 +2068,11 @@
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.test null $A
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (func $ref.test-unreachable (type $ref?|$A|_=>_none) (param $A (ref null $A))
;; NOMNL-NEXT: (drop
@@ -1953,6 +2080,11 @@
;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.test null $A
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
(func $ref.test-unreachable (param $A (ref null $A))
(drop
@@ -1962,6 +2094,11 @@
(unreachable)
)
)
+ (drop
+ (ref.test null $A
+ (unreachable)
+ )
+ )
)
;; CHECK: (func $consecutive-opts-with-unreachable (type $funcref_=>_none) (param $func funcref)
diff --git a/test/spec/ref_test.wast b/test/spec/ref_test.wast
new file mode 100644
index 000000000..bb6479548
--- /dev/null
+++ b/test/spec/ref_test.wast
@@ -0,0 +1,330 @@
+;; Abstract Types
+
+(module
+ (type $ft (func))
+ (type $st (struct))
+ (type $at (array i8))
+
+ (table $ta 10 anyref)
+ (table $tf 10 funcref)
+ (table $te 10 externref)
+
+ (elem declare func $f)
+ (func $f)
+
+ (func (export "init")
+ (table.set $ta (i32.const 0) (ref.null any))
+ (table.set $ta (i32.const 1) (ref.null struct))
+ (table.set $ta (i32.const 2) (ref.null none))
+ (table.set $ta (i32.const 3) (i31.new (i32.const 7)))
+ (table.set $ta (i32.const 4) (struct.new_default $st))
+ (table.set $ta (i32.const 5) (array.new_default $at (i32.const 0)))
+ ;; (table.set $ta (i32.const 6) (extern.internalize (extern.externalize (i31.new (i32.const 0)))))
+ ;; (table.set $ta (i32.const 7) (extern.internalize (ref.null extern)))
+
+ (table.set $tf (i32.const 0) (ref.null nofunc))
+ (table.set $tf (i32.const 1) (ref.null func))
+ (table.set $tf (i32.const 2) (ref.func $f))
+
+ (table.set $te (i32.const 0) (ref.null noextern))
+ (table.set $te (i32.const 1) (ref.null extern))
+ ;; (table.set $te (i32.const 2) (extern.externalize (i31.new (i32.const 0))))
+ ;; (table.set $te (i32.const 3) (extern.externalize (i31.new (i32.const 8))))
+ ;; (table.set $te (i32.const 4) (extern.externalize (struct.new_default $st)))
+ ;; (table.set $te (i32.const 5) (extern.externalize (ref.null any)))
+ )
+
+ (func (export "ref_test_null_data") (param $i i32) (result i32)
+ (i32.add
+ (ref.is_null (table.get $ta (local.get $i)))
+ (ref.test null none (table.get $ta (local.get $i)))
+ )
+ )
+ (func (export "ref_test_any") (param $i i32) (result i32)
+ (i32.add
+ (ref.test any (table.get $ta (local.get $i)))
+ (ref.test null any (table.get $ta (local.get $i)))
+ )
+ )
+ (func (export "ref_test_eq") (param $i i32) (result i32)
+ (i32.add
+ (ref.test eq (table.get $ta (local.get $i)))
+ (ref.test null eq (table.get $ta (local.get $i)))
+ )
+ )
+ (func (export "ref_test_i31") (param $i i32) (result i32)
+ (i32.add
+ (ref.test i31 (table.get $ta (local.get $i)))
+ (ref.test null i31 (table.get $ta (local.get $i)))
+ )
+ )
+ (func (export "ref_test_struct") (param $i i32) (result i32)
+ (i32.add
+ (ref.test struct (table.get $ta (local.get $i)))
+ (ref.test null struct (table.get $ta (local.get $i)))
+ )
+ )
+ (func (export "ref_test_array") (param $i i32) (result i32)
+ (i32.add
+ (ref.test array (table.get $ta (local.get $i)))
+ (ref.test null array (table.get $ta (local.get $i)))
+ )
+ )
+
+ (func (export "ref_test_null_func") (param $i i32) (result i32)
+ (i32.add
+ (ref.is_null (table.get $tf (local.get $i)))
+ (ref.test null nofunc (table.get $tf (local.get $i)))
+ )
+ )
+ (func (export "ref_test_func") (param $i i32) (result i32)
+ (i32.add
+ (ref.test func (table.get $tf (local.get $i)))
+ (ref.test null func (table.get $tf (local.get $i)))
+ )
+ )
+
+ (func (export "ref_test_null_extern") (param $i i32) (result i32)
+ (i32.add
+ (ref.is_null (table.get $te (local.get $i)))
+ (ref.test null noextern (table.get $te (local.get $i)))
+ )
+ )
+ (func (export "ref_test_extern") (param $i i32) (result i32)
+ (i32.add
+ (ref.test extern (table.get $te (local.get $i)))
+ (ref.test null extern (table.get $te (local.get $i)))
+ )
+ )
+)
+
+(invoke "init")
+
+(assert_return (invoke "ref_test_null_data" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "ref_test_null_data" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "ref_test_null_data" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "ref_test_null_data" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "ref_test_null_data" (i32.const 4)) (i32.const 0))
+(assert_return (invoke "ref_test_null_data" (i32.const 5)) (i32.const 0))
+;; (assert_return (invoke "ref_test_null_data" (i32.const 6)) (i32.const 0))
+;; (assert_return (invoke "ref_test_null_data" (i32.const 7)) (i32.const 2))
+
+(assert_return (invoke "ref_test_any" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_any" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ref_test_any" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "ref_test_any" (i32.const 3)) (i32.const 2))
+(assert_return (invoke "ref_test_any" (i32.const 4)) (i32.const 2))
+(assert_return (invoke "ref_test_any" (i32.const 5)) (i32.const 2))
+;; (assert_return (invoke "ref_test_any" (i32.const 6)) (i32.const 2))
+;; (assert_return (invoke "ref_test_any" (i32.const 7)) (i32.const 1))
+
+(assert_return (invoke "ref_test_eq" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_eq" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ref_test_eq" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "ref_test_eq" (i32.const 3)) (i32.const 2))
+(assert_return (invoke "ref_test_eq" (i32.const 4)) (i32.const 2))
+(assert_return (invoke "ref_test_eq" (i32.const 5)) (i32.const 2))
+;; (assert_return (invoke "ref_test_eq" (i32.const 6)) (i32.const 0))
+;; (assert_return (invoke "ref_test_eq" (i32.const 7)) (i32.const 1))
+
+(assert_return (invoke "ref_test_i31" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_i31" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ref_test_i31" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "ref_test_i31" (i32.const 3)) (i32.const 2))
+(assert_return (invoke "ref_test_i31" (i32.const 4)) (i32.const 0))
+(assert_return (invoke "ref_test_i31" (i32.const 5)) (i32.const 0))
+;; (assert_return (invoke "ref_test_i31" (i32.const 6)) (i32.const 0))
+;; (assert_return (invoke "ref_test_i31" (i32.const 7)) (i32.const 1))
+
+(assert_return (invoke "ref_test_struct" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_struct" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ref_test_struct" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "ref_test_struct" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "ref_test_struct" (i32.const 4)) (i32.const 2))
+(assert_return (invoke "ref_test_struct" (i32.const 5)) (i32.const 2)) ;; TOOD: expect 0 once struct is not an alias for data
+;; (assert_return (invoke "ref_test_struct" (i32.const 6)) (i32.const 0))
+;; (assert_return (invoke "ref_test_struct" (i32.const 7)) (i32.const 1))
+
+(assert_return (invoke "ref_test_array" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_array" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ref_test_array" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "ref_test_array" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "ref_test_array" (i32.const 4)) (i32.const 0))
+(assert_return (invoke "ref_test_array" (i32.const 5)) (i32.const 2))
+;; (assert_return (invoke "ref_test_array" (i32.const 6)) (i32.const 0))
+;; (assert_return (invoke "ref_test_array" (i32.const 7)) (i32.const 1))
+
+(assert_return (invoke "ref_test_null_func" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "ref_test_null_func" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "ref_test_null_func" (i32.const 2)) (i32.const 0))
+
+(assert_return (invoke "ref_test_func" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_func" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "ref_test_func" (i32.const 2)) (i32.const 2))
+
+(assert_return (invoke "ref_test_null_extern" (i32.const 0)) (i32.const 2))
+(assert_return (invoke "ref_test_null_extern" (i32.const 1)) (i32.const 2))
+;; (assert_return (invoke "ref_test_null_extern" (i32.const 2)) (i32.const 0))
+;; (assert_return (invoke "ref_test_null_extern" (i32.const 3)) (i32.const 0))
+;; (assert_return (invoke "ref_test_null_extern" (i32.const 4)) (i32.const 0))
+;; (assert_return (invoke "ref_test_null_extern" (i32.const 5)) (i32.const 2))
+
+(assert_return (invoke "ref_test_extern" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "ref_test_extern" (i32.const 1)) (i32.const 1))
+;; (assert_return (invoke "ref_test_extern" (i32.const 2)) (i32.const 2))
+;; (assert_return (invoke "ref_test_extern" (i32.const 3)) (i32.const 2))
+;; (assert_return (invoke "ref_test_extern" (i32.const 4)) (i32.const 2))
+;; (assert_return (invoke "ref_test_extern" (i32.const 5)) (i32.const 1))
+
+
+;; Concrete Types
+
+(module
+ (type $t0 (struct_subtype data))
+ (type $t1 (struct_subtype i32 $t0))
+ (type $t1' (struct_subtype i32 $t0))
+ (type $t2 (struct_subtype i32 i32 $t1))
+ (type $t2' (struct_subtype i32 i32 $t1'))
+ (type $t3 (struct_subtype i32 i32 $t0))
+ (type $t0' (struct_subtype $t0))
+ (type $t4 (struct_subtype i32 i32 $t0'))
+
+ (table $tab 20 (ref null struct))
+
+ (func $init
+ (table.set $tab (i32.const 0) (struct.new_default $t0))
+ (table.set $tab (i32.const 10) (struct.new_default $t0))
+ (table.set $tab (i32.const 1) (struct.new_default $t1))
+ (table.set $tab (i32.const 11) (struct.new_default $t1'))
+ (table.set $tab (i32.const 2) (struct.new_default $t2))
+ (table.set $tab (i32.const 12) (struct.new_default $t2'))
+ (table.set $tab (i32.const 3) (struct.new_default $t3))
+ (table.set $tab (i32.const 4) (struct.new_default $t4))
+ )
+
+ (func (export "test-sub")
+ (call $init)
+ (block $l
+ ;; must hold
+ (br_if $l (i32.eqz (ref.test null $t0 (ref.null struct))))
+ (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t0))))
+ (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t1))))
+ (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t2))))
+ (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t3))))
+ (br_if $l (i32.eqz (ref.test null $t0 (ref.null $t4))))
+ (br_if $l (i32.eqz (ref.test null $t0 (table.get $tab (i32.const 0)))))
+ (br_if $l (i32.eqz (ref.test null $t0 (table.get $tab (i32.const 1)))))
+ (br_if $l (i32.eqz (ref.test null $t0 (table.get $tab (i32.const 2)))))
+ (br_if $l (i32.eqz (ref.test null $t0 (table.get $tab (i32.const 3)))))
+ (br_if $l (i32.eqz (ref.test null $t0 (table.get $tab (i32.const 4)))))
+
+ (br_if $l (i32.eqz (ref.test null $t1 (ref.null struct))))
+ (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t0))))
+ (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t1))))
+ (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t2))))
+ (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t3))))
+ (br_if $l (i32.eqz (ref.test null $t1 (ref.null $t4))))
+ (br_if $l (i32.eqz (ref.test null $t1 (table.get $tab (i32.const 1)))))
+ (br_if $l (i32.eqz (ref.test null $t1 (table.get $tab (i32.const 2)))))
+
+ (br_if $l (i32.eqz (ref.test null $t2 (ref.null struct))))
+ (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t0))))
+ (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t1))))
+ (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t2))))
+ (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t3))))
+ (br_if $l (i32.eqz (ref.test null $t2 (ref.null $t4))))
+ (br_if $l (i32.eqz (ref.test null $t2 (table.get $tab (i32.const 2)))))
+
+ (br_if $l (i32.eqz (ref.test null $t3 (ref.null struct))))
+ (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t0))))
+ (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t1))))
+ (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t2))))
+ (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t3))))
+ (br_if $l (i32.eqz (ref.test null $t3 (ref.null $t4))))
+ (br_if $l (i32.eqz (ref.test null $t3 (table.get $tab (i32.const 3)))))
+
+ (br_if $l (i32.eqz (ref.test null $t4 (ref.null struct))))
+ (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t0))))
+ (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t1))))
+ (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t2))))
+ (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t3))))
+ (br_if $l (i32.eqz (ref.test null $t4 (ref.null $t4))))
+ (br_if $l (i32.eqz (ref.test null $t4 (table.get $tab (i32.const 4)))))
+
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 0)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 1)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 2)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 3)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 4)))))
+
+ (br_if $l (i32.eqz (ref.test $t1 (table.get $tab (i32.const 1)))))
+ (br_if $l (i32.eqz (ref.test $t1 (table.get $tab (i32.const 2)))))
+
+ (br_if $l (i32.eqz (ref.test $t2 (table.get $tab (i32.const 2)))))
+
+ (br_if $l (i32.eqz (ref.test $t3 (table.get $tab (i32.const 3)))))
+
+ (br_if $l (i32.eqz (ref.test $t4 (table.get $tab (i32.const 4)))))
+
+ ;; must not hold
+ (br_if $l (ref.test $t0 (ref.null struct)))
+ (br_if $l (ref.test $t1 (ref.null struct)))
+ (br_if $l (ref.test $t2 (ref.null struct)))
+ (br_if $l (ref.test $t3 (ref.null struct)))
+ (br_if $l (ref.test $t4 (ref.null struct)))
+
+ (br_if $l (ref.test $t1 (table.get $tab (i32.const 0))))
+ (br_if $l (ref.test $t1 (table.get $tab (i32.const 3))))
+ (br_if $l (ref.test $t1 (table.get $tab (i32.const 4))))
+
+ (br_if $l (ref.test $t2 (table.get $tab (i32.const 0))))
+ (br_if $l (ref.test $t2 (table.get $tab (i32.const 1))))
+ (br_if $l (ref.test $t2 (table.get $tab (i32.const 3))))
+ (br_if $l (ref.test $t2 (table.get $tab (i32.const 4))))
+
+ (br_if $l (ref.test $t3 (table.get $tab (i32.const 0))))
+ (br_if $l (ref.test $t3 (table.get $tab (i32.const 1))))
+ (br_if $l (ref.test $t3 (table.get $tab (i32.const 2))))
+ (br_if $l (ref.test $t3 (table.get $tab (i32.const 4))))
+
+ (br_if $l (ref.test $t4 (table.get $tab (i32.const 0))))
+ (br_if $l (ref.test $t4 (table.get $tab (i32.const 1))))
+ (br_if $l (ref.test $t4 (table.get $tab (i32.const 2))))
+ (br_if $l (ref.test $t4 (table.get $tab (i32.const 3))))
+
+ (return)
+ )
+ (unreachable)
+ )
+
+ (func (export "test-canon")
+ (call $init)
+ (block $l
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 0)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 1)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 2)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 3)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 4)))))
+
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 10)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 11)))))
+ (br_if $l (i32.eqz (ref.test $t0 (table.get $tab (i32.const 12)))))
+
+ (br_if $l (i32.eqz (ref.test $t1' (table.get $tab (i32.const 1)))))
+ (br_if $l (i32.eqz (ref.test $t1' (table.get $tab (i32.const 2)))))
+
+ (br_if $l (i32.eqz (ref.test $t1 (table.get $tab (i32.const 11)))))
+ (br_if $l (i32.eqz (ref.test $t1 (table.get $tab (i32.const 12)))))
+
+ (br_if $l (i32.eqz (ref.test $t2' (table.get $tab (i32.const 2)))))
+
+ (br_if $l (i32.eqz (ref.test $t2 (table.get $tab (i32.const 12)))))
+
+ (return)
+ )
+ (unreachable)
+ )
+)
+
+(invoke "test-sub")
+(invoke "test-canon")