summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2022-12-08 11:50:45 -0600
committerGitHub <noreply@github.com>2022-12-08 09:50:45 -0800
commit48959ab5a74d849e9782f54b3535c6fca69d51d7 (patch)
treeb6da926b399636eb2cfc34ce6adbdc24b8488bcc /test
parent2cb5cefb6392619d908ce2ab683815d7e22ac9a5 (diff)
downloadbinaryen-48959ab5a74d849e9782f54b3535c6fca69d51d7.tar.gz
binaryen-48959ab5a74d849e9782f54b3535c6fca69d51d7.tar.bz2
binaryen-48959ab5a74d849e9782f54b3535c6fca69d51d7.zip
Allow casting to basic heap types (#5332)
The standard casting instructions now allow casting to basic heap types, not just user-defined types, but they also require that the intended type and argument type have a common supertype. Update the validator to use the standard rules, update the binary parser and printer to allow basic types, and update the tests to remove or modify newly invalid test cases.
Diffstat (limited to 'test')
-rw-r--r--test/lit/binary/legacy-static-casts.test1
-rw-r--r--test/lit/cast-to-basic.wast83
-rw-r--r--test/lit/passes/gufa-refs.wast24
-rw-r--r--test/lit/passes/optimize-instructions-gc-tnh.wast29
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast50
-rw-r--r--test/passes/Oz_fuzz-exec_all-features.txt25
-rw-r--r--test/passes/Oz_fuzz-exec_all-features.wast8
-rw-r--r--test/spec/ref_cast.wast59
8 files changed, 173 insertions, 106 deletions
diff --git a/test/lit/binary/legacy-static-casts.test b/test/lit/binary/legacy-static-casts.test
index 53218ba65..ad2209594 100644
--- a/test/lit/binary/legacy-static-casts.test
+++ b/test/lit/binary/legacy-static-casts.test
@@ -3,6 +3,7 @@
;; Test that the opcodes for the deprecated *_static cast instructions still parse.
;; RUN: wasm-opt %s.wasm -all -S -o - | filecheck %s
+
;; CHECK: (type ${} (struct ))
;; CHECK: (type $none_=>_none (func))
diff --git a/test/lit/cast-to-basic.wast b/test/lit/cast-to-basic.wast
new file mode 100644
index 000000000..c6b8ea9e7
--- /dev/null
+++ b/test/lit/cast-to-basic.wast
@@ -0,0 +1,83 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+
+;; Test that casts to basic types round trip properly.
+
+;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s
+
+(module
+ ;; CHECK: (func $test (type $none_=>_i32) (result i32)
+ ;; CHECK-NEXT: (ref.test data
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test (result i32)
+ (ref.test struct
+ (ref.null none)
+ )
+ )
+
+ ;; CHECK: (func $cast (type $none_=>_none)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast null data
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $cast
+ (drop
+ (ref.cast null struct
+ (ref.null none)
+ )
+ )
+ )
+
+ ;; CHECK: (func $br (type $none_=>_none)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block $label$1 (result dataref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_on_cast $label$1 data
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br
+ (drop
+ (block $l (result structref)
+ (drop
+ (br_on_cast $l struct
+ (ref.null none)
+ )
+ )
+ (ref.null none)
+ )
+ )
+ )
+
+ ;; CHECK: (func $br-fail (type $none_=>_none)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block $label$1 (result dataref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_on_cast_fail $label$1 data
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br-fail
+ (drop
+ (block $l (result structref)
+ (drop
+ (br_on_cast_fail $l struct
+ (ref.null none)
+ )
+ )
+ (ref.null none)
+ )
+ )
+ )
+)
diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast
index f209cef88..2b221dfd8 100644
--- a/test/lit/passes/gufa-refs.wast
+++ b/test/lit/passes/gufa-refs.wast
@@ -981,7 +981,8 @@
;; CHECK: (type $none_=>_none (func))
- ;; CHECK: (elem declare func $func)
+ ;; CHECK: (type $unrelated (struct ))
+ (type $unrelated (struct))
;; CHECK: (func $func (type $none_=>_none)
;; CHECK-NEXT: (local $child (ref null $child))
@@ -1034,13 +1035,8 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $parent (result (ref $parent))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block (result (ref $none_=>_none))
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (br_on_cast $parent $parent
- ;; CHECK-NEXT: (ref.func $func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.func $func)
+ ;; CHECK-NEXT: (br_on_cast $parent $parent
+ ;; CHECK-NEXT: (struct.new_default $unrelated)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
@@ -1087,14 +1083,14 @@
(local.get $parent)
)
)
- ;; A ref.func is cast to a struct type, and then we read from that. The cast
- ;; will trap at runtime, of course; for here, we should not error and also
- ;; we can optimize these to unreachables. atm we filter out trapping
- ;; contents in ref.cast, but not br_on_cast, so test both.
+ ;; An unrelated type is cast to a struct type, and then we read from that.
+ ;; The cast will trap at runtime, of course; for here, we should not error
+ ;; and also we can optimize these to unreachables. atm we filter out
+ ;; trapping contents in ref.cast, but not br_on_cast, so test both.
(drop
(struct.get $parent 0
(ref.cast null $parent
- (ref.func $func)
+ (struct.new $unrelated)
)
)
)
@@ -1103,7 +1099,7 @@
(block $parent (result (ref $parent))
(drop
(br_on_cast $parent $parent
- (ref.func $func)
+ (struct.new $unrelated)
)
)
(unreachable)
diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast
index 2d3e25b9b..741cd3921 100644
--- a/test/lit/passes/optimize-instructions-gc-tnh.wast
+++ b/test/lit/passes/optimize-instructions-gc-tnh.wast
@@ -48,43 +48,34 @@
)
)
- ;; TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref)
+ ;; TNH: (func $ref.eq-no (type $eqref_eqref_anyref_=>_none) (param $a eqref) (param $b eqref) (param $any anyref)
;; TNH-NEXT: (drop
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; NO_TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref)
+ ;; NO_TNH: (func $ref.eq-no (type $eqref_eqref_anyref_=>_none) (param $a eqref) (param $b eqref) (param $any anyref)
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.eq
- ;; NO_TNH-NEXT: (block (result (ref $struct))
- ;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.func $ref.eq-no)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (unreachable)
+ ;; NO_TNH-NEXT: (ref.cast null $struct
+ ;; NO_TNH-NEXT: (local.get $any)
;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (block (result (ref data))
- ;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.func $ref.eq-no)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (unreachable)
+ ;; NO_TNH-NEXT: (ref.as_data
+ ;; NO_TNH-NEXT: (local.get $any)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
- (func $ref.eq-no (param $a (ref null eq)) (param $b (ref null eq))
- ;; We must leave the inputs to ref.eq of type eqref or a subtype. Note that
- ;; these casts will trap, so other opts might get in the way before we can
- ;; do anything. The crucial thing we test here is that we do not emit
- ;; something that does not validate (as ref.eq inputs must be eqrefs).
+ (func $ref.eq-no (param $a (ref null eq)) (param $b (ref null eq)) (param $any anyref)
+ ;; We must leave the inputs to ref.eq of type eqref or a subtype.
(drop
(ref.eq
(ref.cast null $struct
- (ref.func $ref.eq-no) ;; *Not* an eqref!
+ (local.get $any) ;; *Not* an eqref!
)
(ref.as_non_null
(ref.as_data
(ref.as_non_null
- (ref.func $ref.eq-no) ;; *Not* an eqref!
+ (local.get $any) ;; *Not* an eqref!
)
)
)
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index 61b558868..d0ab6f859 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -1000,13 +1000,6 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast null $struct
- ;; CHECK-NEXT: (ref.as_func
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null $struct
;; CHECK-NEXT: (ref.as_i31
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
@@ -1030,13 +1023,6 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (ref.cast null $struct
- ;; NOMNL-NEXT: (ref.as_func
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.cast null $struct
;; NOMNL-NEXT: (ref.as_i31
;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
@@ -1066,13 +1052,6 @@
;; other ref.as* operations are ignored for now
(drop
(ref.cast null $struct
- (ref.as_func
- (local.get $x)
- )
- )
- )
- (drop
- (ref.cast null $struct
(ref.as_i31
(local.get $x)
)
@@ -2130,35 +2109,6 @@
)
)
- ;; CHECK: (func $ref-cast-static-impossible (type $ref|func|_=>_none) (param $func (ref func))
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block (result (ref $struct))
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (unreachable)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; NOMNL: (func $ref-cast-static-impossible (type $ref|func|_=>_none) (param $func (ref func))
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block (result (ref $struct))
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (local.get $func)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (unreachable)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- (func $ref-cast-static-impossible (param $func (ref func))
- ;; A func cannot be cast to a struct, so this will trap.
- (drop
- (ref.cast null $struct
- (local.get $func)
- )
- )
- )
-
;; CHECK: (func $ref-cast-static-general (type $ref?|$A|_ref?|$B|_=>_none) (param $a (ref null $A)) (param $b (ref null $B))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $a)
diff --git a/test/passes/Oz_fuzz-exec_all-features.txt b/test/passes/Oz_fuzz-exec_all-features.txt
index afeae72f0..af706cc23 100644
--- a/test/passes/Oz_fuzz-exec_all-features.txt
+++ b/test/passes/Oz_fuzz-exec_all-features.txt
@@ -34,8 +34,6 @@
[host limit allocation failure]
[fuzz-exec] calling init-array-packed
[fuzz-exec] note result: init-array-packed => 213
-[fuzz-exec] calling cast-func-to-struct
-[trap cast error]
[fuzz-exec] calling array-copy
[LoggingExternalInterface logging 10]
[LoggingExternalInterface logging 10]
@@ -80,13 +78,12 @@
(export "cast-on-func" (func $12))
(export "array-alloc-failure" (func $7))
(export "init-array-packed" (func $14))
- (export "cast-func-to-struct" (func $9))
- (export "array-copy" (func $17))
- (export "array.init_static" (func $18))
- (export "array.init_static-packed" (func $19))
- (export "static-casts" (func $20))
+ (export "array-copy" (func $16))
+ (export "array.init_static" (func $17))
+ (export "array.init_static-packed" (func $18))
+ (export "static-casts" (func $19))
(export "static-br_on_cast" (func $2))
- (export "static-br_on_cast_fail" (func $22))
+ (export "static-br_on_cast_fail" (func $21))
(func $0 (type $void_func) (; has Stack IR ;)
(local $0 i32)
(call $log
@@ -225,7 +222,7 @@
(i32.const 10)
)
)
- (func $17 (type $void_func) (; has Stack IR ;)
+ (func $16 (type $void_func) (; has Stack IR ;)
(local $0 (ref $bytes))
(local $1 (ref $bytes))
(array.set $bytes
@@ -280,7 +277,7 @@
)
)
)
- (func $18 (type $void_func) (; has Stack IR ;)
+ (func $17 (type $void_func) (; has Stack IR ;)
(local $0 (ref $bytes))
(call $log
(array.len
@@ -305,7 +302,7 @@
)
)
)
- (func $19 (type $void_func) (; has Stack IR ;)
+ (func $18 (type $void_func) (; has Stack IR ;)
(call $log
(array.get_u $bytes
(array.init_static $bytes
@@ -315,7 +312,7 @@
)
)
)
- (func $20 (type $void_func) (; has Stack IR ;)
+ (func $19 (type $void_func) (; has Stack IR ;)
(call $log
(i32.const 1)
)
@@ -335,7 +332,7 @@
(i32.const 0)
)
)
- (func $22 (type $void_func) (; has Stack IR ;)
+ (func $21 (type $void_func) (; has Stack IR ;)
(call $log
(i32.const -2)
)
@@ -376,8 +373,6 @@
[fuzz-exec] calling array-alloc-failure
[fuzz-exec] calling init-array-packed
[fuzz-exec] note result: init-array-packed => 213
-[fuzz-exec] calling cast-func-to-struct
-[trap unreachable]
[fuzz-exec] calling array-copy
[LoggingExternalInterface logging 10]
[LoggingExternalInterface logging 10]
diff --git a/test/passes/Oz_fuzz-exec_all-features.wast b/test/passes/Oz_fuzz-exec_all-features.wast
index 203fc60fe..4c6af8a93 100644
--- a/test/passes/Oz_fuzz-exec_all-features.wast
+++ b/test/passes/Oz_fuzz-exec_all-features.wast
@@ -233,14 +233,6 @@
(func $call-target (param $0 eqref)
(nop)
)
- (func "cast-func-to-struct"
- (drop
- ;; An impossible cast of a function to a struct, which should fail.
- (ref.cast null $struct
- (ref.func $call-target)
- )
- )
- )
(func "array-copy"
(local $x (ref null $bytes))
(local $y (ref null $bytes))
diff --git a/test/spec/ref_cast.wast b/test/spec/ref_cast.wast
index 53ca9227c..22859d167 100644
--- a/test/spec/ref_cast.wast
+++ b/test/spec/ref_cast.wast
@@ -61,7 +61,66 @@
(drop (ref.cast null $t2 (global.get $tab.12)))
)
+
+ (func (export "test-ref-test-t0") (result i32)
+ (ref.test $t0 (struct.new $t0))
+ )
+
+ (func (export "test-ref-test-struct") (result i32)
+ (ref.test struct (struct.new $t0))
+ )
+
+ (func (export "test-ref-test-any") (result i32)
+ (ref.test any (struct.new $t0))
+ )
+
+ (func (export "test-ref-cast-struct")
+ (drop
+ (ref.cast null struct (struct.new $t0))
+ )
+ )
+
+ (func (export "test-br-on-cast-struct") (result i32)
+ (drop
+ (block $l (result (ref struct))
+ (drop
+ (br_on_cast $l struct (struct.new $t0))
+ )
+ (return (i32.const 0))
+ )
+ )
+ (i32.const 1)
+ )
+
+ (func (export "test-br-on-cast-fail-struct") (result i32)
+ (drop
+ (block $l (result (ref struct))
+ (drop
+ (br_on_cast_fail $l struct (struct.new $t0))
+ )
+ (return (i32.const 0))
+ )
+ )
+ (i32.const 1)
+ )
)
+
(invoke "test-sub")
(invoke "test-canon")
+(assert_return (invoke "test-ref-test-t0") (i32.const 1))
+(assert_return (invoke "test-ref-test-struct") (i32.const 1))
+(assert_return (invoke "test-ref-test-any") (i32.const 1))
+(assert_return (invoke "test-ref-cast-struct"))
+(assert_return (invoke "test-br-on-cast-struct") (i32.const 1))
+(assert_return (invoke "test-br-on-cast-fail-struct") (i32.const 0))
+
+(assert_invalid
+ (module
+ (type $t0 (struct))
+ (func (export "test-ref-test-extern") (result i32)
+ (ref.test extern (struct.new $t0))
+ )
+ )
+ "common supertype"
+)