summaryrefslogtreecommitdiff
path: root/test/lit
diff options
context:
space:
mode:
Diffstat (limited to 'test/lit')
-rw-r--r--test/lit/binary/annotated-array-len.test18
-rw-r--r--test/lit/binary/annotated-array-len.test.wasmbin36 -> 0 bytes
-rw-r--r--test/lit/binary/bad-ref-as.test5
-rw-r--r--test/lit/binary/bad-ref-as.test.wasmbin29 -> 0 bytes
-rw-r--r--test/lit/legacy-static-casts.wast47
-rw-r--r--test/lit/passes/abstract-type-refining.wast15
-rw-r--r--test/lit/passes/code-pushing-gc.wast18
-rw-r--r--test/lit/passes/gufa-refs.wast2
-rw-r--r--test/lit/passes/merge-blocks.wast2
-rw-r--r--test/lit/passes/optimize-instructions-gc-tnh.wast58
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast42
-rw-r--r--test/lit/passes/remove-unused-brs-gc.wast101
-rw-r--r--test/lit/passes/remove-unused-brs_all-features.wast135
-rw-r--r--test/lit/passes/vacuum-gc.wast6
-rw-r--r--test/lit/passes/vacuum-tnh.wast6
-rw-r--r--test/lit/ref-cast-nop.wast29
16 files changed, 148 insertions, 336 deletions
diff --git a/test/lit/binary/annotated-array-len.test b/test/lit/binary/annotated-array-len.test
deleted file mode 100644
index 9cf6eecbe..000000000
--- a/test/lit/binary/annotated-array-len.test
+++ /dev/null
@@ -1,18 +0,0 @@
-;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-
-;; Test the we can properly parse the annotated array.len format that we no
-;; longer emit.
-
-;; RUN: wasm-dis %s.wasm -all | filecheck %s
-
-;; CHECK: (type $none_=>_i32 (func (result i32)))
-
-;; CHECK: (type $[mut:i8] (array (mut i8)))
-
-;; CHECK: (func $0 (type $none_=>_i32) (result i32)
-;; CHECK-NEXT: (array.len
-;; CHECK-NEXT: (array.new_default $[mut:i8]
-;; CHECK-NEXT: (i32.const 0)
-;; CHECK-NEXT: )
-;; CHECK-NEXT: )
-;; CHECK-NEXT: )
diff --git a/test/lit/binary/annotated-array-len.test.wasm b/test/lit/binary/annotated-array-len.test.wasm
deleted file mode 100644
index b199f58de..000000000
--- a/test/lit/binary/annotated-array-len.test.wasm
+++ /dev/null
Binary files differ
diff --git a/test/lit/binary/bad-ref-as.test b/test/lit/binary/bad-ref-as.test
deleted file mode 100644
index 3accdd553..000000000
--- a/test/lit/binary/bad-ref-as.test
+++ /dev/null
@@ -1,5 +0,0 @@
-;; Test that we error properly on a file with a ref.as of a non-ref type.
-
-;; RUN: not wasm-opt -all %s.wasm 2>&1 | filecheck %s
-
-;; CHECK: ref.cast ref must have ref type
diff --git a/test/lit/binary/bad-ref-as.test.wasm b/test/lit/binary/bad-ref-as.test.wasm
deleted file mode 100644
index 637537dd2..000000000
--- a/test/lit/binary/bad-ref-as.test.wasm
+++ /dev/null
Binary files differ
diff --git a/test/lit/legacy-static-casts.wast b/test/lit/legacy-static-casts.wast
deleted file mode 100644
index 893fb0a33..000000000
--- a/test/lit/legacy-static-casts.wast
+++ /dev/null
@@ -1,47 +0,0 @@
-;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-
-;; Check that the deprecated *_static instruction names are still parsed correctly.
-
-;; RUN: wasm-opt %s -all -S -o - | filecheck %s
-
-(module
- ;; CHECK: (type $none_=>_none (func))
-
- ;; CHECK: (type $struct (struct ))
- (type $struct (struct))
-
- ;; CHECK: (func $test (type $none_=>_none)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.test $struct
- ;; CHECK-NEXT: (ref.null none)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null none
- ;; CHECK-NEXT: (ref.null none)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast_nop none
- ;; CHECK-NEXT: (ref.null none)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $test
- (drop
- (ref.test_static $struct
- (ref.null none)
- )
- )
- (drop
- (ref.cast_static $struct
- (ref.null none)
- )
- )
- (drop
- (ref.cast_nop_static $struct
- (ref.null none)
- )
- )
- )
-)
diff --git a/test/lit/passes/abstract-type-refining.wast b/test/lit/passes/abstract-type-refining.wast
index 220de9656..af2b210fd 100644
--- a/test/lit/passes/abstract-type-refining.wast
+++ b/test/lit/passes/abstract-type-refining.wast
@@ -217,11 +217,6 @@
;; YESTNH-NEXT: (local.get $x)
;; YESTNH-NEXT: )
;; YESTNH-NEXT: )
- ;; YESTNH-NEXT: (drop
- ;; YESTNH-NEXT: (ref.cast i31
- ;; YESTNH-NEXT: (local.get $x)
- ;; YESTNH-NEXT: )
- ;; YESTNH-NEXT: )
;; YESTNH-NEXT: )
;; NO_TNH: (func $basic (type $anyref_=>_none) (param $x anyref)
;; NO_TNH-NEXT: (drop
@@ -229,11 +224,6 @@
;; NO_TNH-NEXT: (local.get $x)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.cast i31
- ;; NO_TNH-NEXT: (local.get $x)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
(func $basic (param $x anyref)
;; Casts to basic types should not be modified.
@@ -242,11 +232,6 @@
(local.get $x)
)
)
- (drop
- (ref.as_i31
- (local.get $x)
- )
- )
)
;; YESTNH: (func $locals (type $none_=>_none)
diff --git a/test/lit/passes/code-pushing-gc.wast b/test/lit/passes/code-pushing-gc.wast
index 56cfc8777..9587d5ab7 100644
--- a/test/lit/passes/code-pushing-gc.wast
+++ b/test/lit/passes/code-pushing-gc.wast
@@ -7,8 +7,8 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $out (result (ref func))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_on_cast $out (ref $none_=>_none) (ref func)
- ;; CHECK-NEXT: (ref.func $br_on)
+ ;; CHECK-NEXT: (br_on_cast $out nullfuncref (ref func)
+ ;; CHECK-NEXT: (ref.null nofunc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $x
@@ -28,8 +28,8 @@
;; We can push the local.set past the br_on.
(local.set $x (ref.func $br_on))
(drop
- (br_on_func $out
- (ref.func $br_on)
+ (br_on_cast $out funcref (ref func)
+ (ref.null nofunc)
)
)
(drop
@@ -48,8 +48,8 @@
;; CHECK-NEXT: (ref.func $br_on_no)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_on_cast $out (ref $none_=>_none) (ref func)
- ;; CHECK-NEXT: (ref.func $br_on_no)
+ ;; CHECK-NEXT: (br_on_cast $out nullfuncref (ref func)
+ ;; CHECK-NEXT: (ref.null nofunc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.func $br_on_no)
@@ -61,13 +61,13 @@
;; CHECK-NEXT: )
(func $br_on_no
(local $x (ref null func))
- ;; We can't push here since the local.get is outside of the loop.
+ ;; We can't push here since the local.get is outside of the block.
(drop
(block $out (result (ref func))
(local.set $x (ref.func $br_on_no))
(drop
- (br_on_func $out
- (ref.func $br_on_no)
+ (br_on_cast $out funcref (ref func)
+ (ref.null nofunc)
)
)
(ref.func $br_on_no)
diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast
index 7c7aa8c40..b82fbf148 100644
--- a/test/lit/passes/gufa-refs.wast
+++ b/test/lit/passes/gufa-refs.wast
@@ -54,7 +54,7 @@
(ref.is_null
(loop $loop (result (ref func))
(nop)
- (ref.as_func
+ (ref.cast func
(ref.as_non_null
(ref.null func)
)
diff --git a/test/lit/passes/merge-blocks.wast b/test/lit/passes/merge-blocks.wast
index 2b3afa771..02772c9b6 100644
--- a/test/lit/passes/merge-blocks.wast
+++ b/test/lit/passes/merge-blocks.wast
@@ -34,7 +34,7 @@
(block $label$1 (result (ref null i31)) ;; this block type must stay, we
;; cannot remove it due to the br_on
(drop
- (br_on_i31 $label$1
+ (br_on_cast $label$1 anyref (ref i31)
(ref.null any)
)
)
diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast
index 831d229a2..155ac82cf 100644
--- a/test/lit/passes/optimize-instructions-gc-tnh.wast
+++ b/test/lit/passes/optimize-instructions-gc-tnh.wast
@@ -146,7 +146,7 @@
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
(func $ref.is_b (param $a eqref) (param $f funcref) (result i32)
- ;; Here we only have a cast, and no ref.as operations that force the value
+ ;; Here we only have a cast, and no cast operations that force the value
;; to be non-nullable. That means we cannot remove the ref.is, but we can
;; remove the cast in TNH.
(drop
@@ -164,28 +164,56 @@
)
)
- ;; TNH: (func $ref.is_func (type $funcref_=>_i32) (param $a funcref) (result i32)
+ ;; TNH: (func $ref.test (type $eqref_=>_i32) (param $a eqref) (result i32)
;; TNH-NEXT: (drop
- ;; TNH-NEXT: (ref.as_non_null
- ;; TNH-NEXT: (local.get $a)
+ ;; TNH-NEXT: (block (result i32)
+ ;; TNH-NEXT: (drop
+ ;; TNH-NEXT: (ref.cast null i31
+ ;; TNH-NEXT: (local.get $a)
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; TNH-NEXT: (i32.const 1)
+ ;; TNH-NEXT: (block (result i32)
+ ;; TNH-NEXT: (drop
+ ;; TNH-NEXT: (ref.as_non_null
+ ;; TNH-NEXT: (local.get $a)
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: (i32.const 1)
+ ;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; NO_TNH: (func $ref.is_func (type $funcref_=>_i32) (param $a funcref) (result i32)
+ ;; NO_TNH: (func $ref.test (type $eqref_=>_i32) (param $a eqref) (result i32)
;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (local.get $a)
+ ;; NO_TNH-NEXT: (block (result i32)
+ ;; NO_TNH-NEXT: (drop
+ ;; NO_TNH-NEXT: (ref.cast null i31
+ ;; NO_TNH-NEXT: (local.get $a)
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (i32.const 1)
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (block (result i32)
+ ;; NO_TNH-NEXT: (drop
+ ;; NO_TNH-NEXT: (ref.as_non_null
+ ;; NO_TNH-NEXT: (local.get $a)
+ ;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (i32.const 1)
;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (i32.const 1)
;; NO_TNH-NEXT: )
- (func $ref.is_func (param $a funcref) (result i32)
- ;; The check must succeed. We can return 1 here, and drop the rest, with or
- ;; without TNH (in particular, TNH should not just remove the cast but not
- ;; return a 1).
- (ref.is_func
- (ref.as_func
+ (func $ref.test (param $a eqref) (result i32)
+ (drop
+ (ref.test null i31
+ (ref.cast null i31
+ (local.get $a)
+ )
+ )
+ )
+ (ref.test eq
+ (ref.cast eq
(local.get $a)
)
)
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index 34070487b..9f33c55a3 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -122,8 +122,8 @@
)
;; ref.is_null is not needed on a non-nullable value, and if something is
- ;; a func we don't need that either etc. if we know the result
- ;; CHECK: (func $unneeded_is (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31))
+ ;; cast to its own type, we don't need that either, etc.
+ ;; CHECK: (func $unneeded_test (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
@@ -149,7 +149,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $unneeded_is
+ (func $unneeded_test
(param $struct (ref $struct))
(param $func (ref func))
(param $i31 (ref i31))
@@ -157,16 +157,16 @@
(ref.is_null (local.get $struct))
)
(drop
- (ref.is_func (local.get $func))
+ (ref.test func (local.get $func))
)
(drop
- (ref.is_i31 (local.get $i31))
+ (ref.test i31 (local.get $i31))
)
)
;; similar to $unneeded_is, but the values are nullable. we can at least
;; leave just the null check.
- ;; CHECK: (func $unneeded_is_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref)
+ ;; CHECK: (func $unneeded_test_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $struct)
@@ -187,7 +187,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $unneeded_is_null
+ (func $unneeded_test_null
(param $struct (ref null $struct))
(param $func (ref null func))
(param $i31 (ref null i31))
@@ -197,17 +197,17 @@
;; This can be optimized to !is_null rather than ref.test func, since we
;; know the heap type is what we want, so the only possible issue is a null.
(drop
- (ref.is_func (local.get $func))
+ (ref.test func (local.get $func))
)
;; This can be optimized similarly.
(drop
- (ref.is_i31 (local.get $i31))
+ (ref.test i31 (local.get $i31))
)
)
;; ref.as_non_null is not needed on a non-nullable value, and if something is
;; a func we don't need that either etc., and can just return the value.
- ;; CHECK: (func $unneeded_as (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31))
+ ;; CHECK: (func $unneeded_cast (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
@@ -218,7 +218,7 @@
;; CHECK-NEXT: (local.get $i31)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $unneeded_as
+ (func $unneeded_cast
(param $struct (ref $struct))
(param $func (ref func))
(param $i31 (ref i31))
@@ -226,16 +226,16 @@
(ref.as_non_null (local.get $struct))
)
(drop
- (ref.as_func (local.get $func))
+ (ref.cast func (local.get $func))
)
(drop
- (ref.as_i31 (local.get $i31))
+ (ref.cast i31 (local.get $i31))
)
)
- ;; similar to $unneeded_as, but the values are nullable. we can turn the
+ ;; similar to $unneeded_cast, but the values are nullable. we can turn the
;; more specific things into ref.as_non_null.
- ;; CHECK: (func $unneeded_as_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref)
+ ;; CHECK: (func $unneeded_cast_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
@@ -252,7 +252,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $unneeded_as_null
+ (func $unneeded_cast_null
(param $struct (ref null $struct))
(param $func (ref null func))
(param $i31 (ref null i31))
@@ -260,10 +260,10 @@
(ref.as_non_null (local.get $struct))
)
(drop
- (ref.as_func (local.get $func))
+ (ref.cast func (local.get $func))
)
(drop
- (ref.as_i31 (local.get $i31))
+ (ref.cast i31 (local.get $i31))
)
)
@@ -285,10 +285,10 @@
(func $unneeded_unreachability
;; unreachable instructions can simply be ignored
(drop
- (ref.is_func (unreachable))
+ (ref.test func (unreachable))
)
(drop
- (ref.as_func (unreachable))
+ (ref.cast func (unreachable))
)
)
@@ -617,7 +617,7 @@
;; This will trap, so we can emit an unreachable.
(drop
(ref.cast $struct
- (ref.as_i31
+ (ref.cast i31
(local.get $x)
)
)
diff --git a/test/lit/passes/remove-unused-brs-gc.wast b/test/lit/passes/remove-unused-brs-gc.wast
index e063fa482..50ffd9583 100644
--- a/test/lit/passes/remove-unused-brs-gc.wast
+++ b/test/lit/passes/remove-unused-brs-gc.wast
@@ -11,57 +11,6 @@
(type $struct2 (struct))
)
- ;; CHECK: (func $br_on_non_i31-1 (type $none_=>_none)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block $any (result (ref null $struct))
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br $any
- ;; CHECK-NEXT: (struct.new_default $struct)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.null none)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $br_on_non_i31-1
- (drop
- (block $any (result anyref)
- (drop
- ;; An struct is not an i31, and so we should branch.
- (br_on_non_i31 $any
- (struct.new $struct)
- )
- )
- (ref.null any)
- )
- )
- )
- ;; CHECK: (func $br_on_non_i31-2 (type $none_=>_none)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block $any (result nullref)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (i31.new
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.null none)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $br_on_non_i31-2
- (drop
- (block $any (result anyref)
- (drop
- ;; An i31 is provided here, and so we will not branch.
- (br_on_non_i31 $any
- (i31.new (i32.const 0))
- )
- )
- (ref.null any)
- )
- )
- )
-
;; CHECK: (func $br_on-if (type $ref|struct|_=>_none) (param $0 (ref struct))
;; CHECK-NEXT: (block $label
;; CHECK-NEXT: (drop
@@ -93,51 +42,51 @@
)
)
- ;; CHECK: (func $nested_br_on (type $none_=>_i31ref) (result i31ref)
- ;; CHECK-NEXT: (block $label$1 (result (ref i31))
+ ;; CHECK: (func $br_on_cast (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; CHECK-NEXT: (block $block (result (ref $struct))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br $label$1
- ;; CHECK-NEXT: (i31.new
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (br $block
+ ;; CHECK-NEXT: (struct.new_default $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $nested_br_on (result i31ref)
- (block $label$1 (result i31ref)
+ (func $br_on_cast (result (ref $struct))
+ (block $block (result (ref $struct))
(drop
- ;; The inner br_on_i31 will become a direct br since the type proves it
- ;; is in fact data. That then becomes unreachable, and the parent must
- ;; handle that properly (do nothing without hitting an assertion).
- (br_on_i31 $label$1
- (br_on_i31 $label$1
- (i31.new (i32.const 0))
- )
+ ;; This static cast can be computed at compile time: it will definitely be
+ ;; taken, so we can turn it into a normal br.
+ (br_on_cast $block anyref (ref $struct)
+ (struct.new $struct)
)
)
(unreachable)
)
)
- ;; CHECK: (func $br_on_cast (type $none_=>_ref|$struct|) (result (ref $struct))
- ;; CHECK-NEXT: (block $block (result (ref $struct))
+ ;; CHECK: (func $nested_br_on_cast (type $none_=>_i31ref) (result i31ref)
+ ;; CHECK-NEXT: (block $label$1 (result (ref i31))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br $block
- ;; CHECK-NEXT: (struct.new_default $struct)
+ ;; CHECK-NEXT: (br $label$1
+ ;; CHECK-NEXT: (i31.new
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $br_on_cast (result (ref $struct))
- (block $block (result (ref $struct))
+ (func $nested_br_on_cast (result i31ref)
+ (block $label$1 (result i31ref)
(drop
- ;; This static cast can be computed at compile time: it will definitely be
- ;; taken, so we can turn it into a normal br.
- (br_on_cast $block anyref (ref $struct)
- (struct.new $struct)
+ ;; The inner br_on_cast will become a direct br since the type proves it
+ ;; is in fact i31. That then becomes unreachable, and the parent must
+ ;; handle that properly (do nothing without hitting an assertion).
+ (br_on_cast $label$1 (ref any) (ref i31)
+ (br_on_cast $label$1 (ref any) (ref i31)
+ (i31.new (i32.const 0))
+ )
)
)
(unreachable)
diff --git a/test/lit/passes/remove-unused-brs_all-features.wast b/test/lit/passes/remove-unused-brs_all-features.wast
index 8ca632040..c93f25df2 100644
--- a/test/lit/passes/remove-unused-brs_all-features.wast
+++ b/test/lit/passes/remove-unused-brs_all-features.wast
@@ -8,10 +8,10 @@
(type $vector (array (mut i32)))
;; CHECK: (type $struct (struct (field (ref null $vector))))
(type $struct (struct (field (ref null $vector))))
- ;; CHECK: (type $ref|func|_=>_none (func (param (ref func))))
-
;; CHECK: (type $i32_=>_none (func (param i32)))
+ ;; CHECK: (type $none_=>_funcref (func (result funcref)))
+
;; CHECK: (type $none_=>_ref?|$struct| (func (result (ref null $struct))))
;; CHECK: (type $none_=>_f64 (func (result f64)))
@@ -20,9 +20,11 @@
;; CHECK: (type $i32_=>_funcref (func (param i32) (result funcref)))
+ ;; CHECK: (type $none_=>_none (func))
+
;; CHECK: (import "out" "log" (func $log (type $i32_=>_none) (param i32)))
(import "out" "log" (func $log (param i32)))
- ;; CHECK: (elem declare func $br_on-to-br $i32_=>_none $none_=>_i32)
+ ;; CHECK: (elem declare func $br_on_non_null $br_on_null $i32_=>_none $none_=>_i32)
;; CHECK: (func $foo (type $none_=>_ref?|$struct|) (result (ref null $struct))
;; CHECK-NEXT: (if (result (ref null $struct))
@@ -116,110 +118,57 @@
)
)
- ;; CHECK: (func $br_on-to-br (type $ref|func|_=>_none) (param $func (ref func))
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
+ ;; CHECK: (func $br_on_null (type $none_=>_none)
;; CHECK-NEXT: (block $null
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.func $br_on-to-br)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 2)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block $func (result (ref $ref|func|_=>_none))
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br $func
- ;; CHECK-NEXT: (ref.func $br_on-to-br)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 3)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.func $br_on-to-br)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 4)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block $i31 (result (ref i31))
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br $i31
- ;; CHECK-NEXT: (i31.new
- ;; CHECK-NEXT: (i32.const 42)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 5)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i31.new
- ;; CHECK-NEXT: (i32.const 1337)
+ ;; CHECK-NEXT: (br_on_null $null
+ ;; CHECK-NEXT: (ref.null nofunc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 6)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block $non-null (result (ref $ref|func|_=>_none))
- ;; CHECK-NEXT: (br $non-null
- ;; CHECK-NEXT: (ref.func $br_on-to-br)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $log
- ;; CHECK-NEXT: (i32.const 7)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.func $br_on-to-br)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.func $br_on_null)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $br_on-to-br (param $func (ref func))
- (call $log (i32.const 0))
+ (func $br_on_null
(block $null
- ;; a non-null reference is not null, and the br is never taken
+ ;; A null reference to bottom is definitely null, and the br is always taken.
+ ;; TODO: Optimize this.
(drop
- (br_on_null $null (ref.func $br_on-to-br))
+ (br_on_null $null (ref.null nofunc))
)
- (call $log (i32.const 1))
- )
- (call $log (i32.const 2))
- (drop
- (block $func (result funcref)
- ;; a non-null function reference means we always take the br
- (drop
- (br_on_func $func (ref.func $br_on-to-br))
- )
- (call $log (i32.const 3))
- (ref.func $br_on-to-br)
+ ;; On the other hand, if we know the input is not null, the branch will never
+ ;; be taken.
+ (drop
+ (br_on_null $null (ref.func $br_on_null))
)
)
- (call $log (i32.const 4))
- (drop
- (block $i31 (result i31ref)
- ;; a non-null i31 reference means we always take the br
- (drop
- (br_on_i31 $i31
- (i31.new (i32.const 42))
- )
- )
- (call $log (i32.const 5))
- (i31.new (i32.const 1337))
+ )
+
+ ;; CHECK: (func $br_on_non_null (type $none_=>_funcref) (result funcref)
+ ;; CHECK-NEXT: (block $non-null (result (ref $none_=>_funcref))
+ ;; CHECK-NEXT: (br $non-null
+ ;; CHECK-NEXT: (ref.func $br_on_non_null)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (br_on_non_null $non-null
+ ;; CHECK-NEXT: (ref.null nofunc)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.func $br_on_non_null)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br_on_non_null (result funcref)
+ (block $non-null (result (ref func))
+ ;; A non-null reference is not null, and the br is always taken.
+ (br_on_non_null $non-null
+ (ref.func $br_on_non_null)
)
- )
- (call $log (i32.const 6))
- (drop
- (block $non-null (result (ref func))
- ;; a non-null reference is not null, and the br is always taken
- (br_on_non_null $non-null (ref.func $br_on-to-br))
- (call $log (i32.const 7))
- (ref.func $br_on-to-br)
+ ;; On the other hand, if we know the input is null, the branch will never be
+ ;; taken.
+ ;; TODO: Optimize this.
+ (br_on_non_null $non-null
+ (ref.null nofunc)
)
+ (ref.func $br_on_non_null)
)
)
)
diff --git a/test/lit/passes/vacuum-gc.wast b/test/lit/passes/vacuum-gc.wast
index 69dbe0b89..fcdeb8cd2 100644
--- a/test/lit/passes/vacuum-gc.wast
+++ b/test/lit/passes/vacuum-gc.wast
@@ -18,13 +18,13 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast i31
+ ;; CHECK-NEXT: (ref.cast null i31
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $drop-ref-as (param $x anyref)
- ;; Without -tnh, we must assume all ref_as* can have a trap effect, and so
+ ;; Without -tnh, we must assume all casts can have a trap effect, and so
;; we cannot remove anything here.
(drop
(ref.as_non_null
@@ -32,7 +32,7 @@
)
)
(drop
- (ref.as_i31
+ (ref.cast null i31
(local.get $x)
)
)
diff --git a/test/lit/passes/vacuum-tnh.wast b/test/lit/passes/vacuum-tnh.wast
index f60c4c5cb..c3de8c21c 100644
--- a/test/lit/passes/vacuum-tnh.wast
+++ b/test/lit/passes/vacuum-tnh.wast
@@ -33,7 +33,7 @@
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.cast i31
+ ;; NO_TNH-NEXT: (ref.cast null i31
;; NO_TNH-NEXT: (local.get $y)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
@@ -55,9 +55,9 @@
)
)
- ;; Other ref.as* as well.
+ ;; Other casts as well.
(drop
- (ref.as_i31
+ (ref.cast null i31
(local.get $y)
)
)
diff --git a/test/lit/ref-cast-nop.wast b/test/lit/ref-cast-nop.wast
deleted file mode 100644
index 3b284db04..000000000
--- a/test/lit/ref-cast-nop.wast
+++ /dev/null
@@ -1,29 +0,0 @@
-;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
-
-;; RUN: wasm-opt -all %s -S --roundtrip -o - | filecheck %s
-
-(module
- ;; CHECK: (type $struct (struct (field i32)))
- (type $struct (struct i32))
- ;; CHECK: (func $ref.cast_nop (type $ref|any|_=>_ref|$struct|) (param $x (ref any)) (result (ref $struct))
- ;; CHECK-NEXT: (ref.cast_nop $struct
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $ref.cast_nop (param $x (ref any)) (result (ref $struct))
- (ref.cast_nop $struct
- (local.get $x)
- )
- )
-
- ;; CHECK: (func $ref.cast_nop.null (type $ref|any|_=>_ref|none|) (param $x (ref any)) (result (ref none))
- ;; CHECK-NEXT: (ref.cast_nop none
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- (func $ref.cast_nop.null (param $x (ref any)) (result (ref none))
- (ref.cast_nop none
- (local.get $x)
- )
- )
-)