diff options
Diffstat (limited to 'test/lit')
-rw-r--r-- | test/lit/binary/annotated-array-len.test | 18 | ||||
-rw-r--r-- | test/lit/binary/annotated-array-len.test.wasm | bin | 36 -> 0 bytes | |||
-rw-r--r-- | test/lit/binary/bad-ref-as.test | 5 | ||||
-rw-r--r-- | test/lit/binary/bad-ref-as.test.wasm | bin | 29 -> 0 bytes | |||
-rw-r--r-- | test/lit/legacy-static-casts.wast | 47 | ||||
-rw-r--r-- | test/lit/passes/abstract-type-refining.wast | 15 | ||||
-rw-r--r-- | test/lit/passes/code-pushing-gc.wast | 18 | ||||
-rw-r--r-- | test/lit/passes/gufa-refs.wast | 2 | ||||
-rw-r--r-- | test/lit/passes/merge-blocks.wast | 2 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc-tnh.wast | 58 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc.wast | 42 | ||||
-rw-r--r-- | test/lit/passes/remove-unused-brs-gc.wast | 101 | ||||
-rw-r--r-- | test/lit/passes/remove-unused-brs_all-features.wast | 135 | ||||
-rw-r--r-- | test/lit/passes/vacuum-gc.wast | 6 | ||||
-rw-r--r-- | test/lit/passes/vacuum-tnh.wast | 6 | ||||
-rw-r--r-- | test/lit/ref-cast-nop.wast | 29 |
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 Binary files differdeleted file mode 100644 index b199f58de..000000000 --- a/test/lit/binary/annotated-array-len.test.wasm +++ /dev/null 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 Binary files differdeleted file mode 100644 index 637537dd2..000000000 --- a/test/lit/binary/bad-ref-as.test.wasm +++ /dev/null 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) - ) - ) -) |