summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-09-30 14:51:08 -0700
committerGitHub <noreply@github.com>2021-09-30 14:51:08 -0700
commit58879a6c6f623156d53f72a4ca935df81143f49e (patch)
tree4c1abca54213c69b78806ced568a0146c4a0c157 /test
parent71ae6342c418c34d8409c49fd0710ec6fd767ac8 (diff)
downloadbinaryen-58879a6c6f623156d53f72a4ca935df81143f49e.tar.gz
binaryen-58879a6c6f623156d53f72a4ca935df81143f49e.tar.bz2
binaryen-58879a6c6f623156d53f72a4ca935df81143f49e.zip
[Wasm GC] Optimize static (rtt-free) operations (#4186)
Now that they are all implemented, we can optimize them. This removes the big if that ignored static operations, and implements things for them. In general this matches the existing rtt-using case, but there are a few things we can do better, which this does: * A cast of a subtype to a type always succeeds. * A test of a subtype to a type is always 1 (if non-nullable). * Repeated static casts can leave just the most demanding of them.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast665
-rw-r--r--test/passes/Oz_fuzz-exec_all-features.txt15
2 files changed, 665 insertions, 15 deletions
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index 993eb222c..37db14f9e 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -14,6 +14,10 @@
(field $i64 (mut i64))
))
+ ;; CHECK: (type $A (struct (field i32)))
+ ;; NOMNL: (type $A (struct (field i32)))
+ (type $A (struct (field i32)))
+
;; CHECK: (type $array (array (mut i8)))
;; NOMNL: (type $array (array (mut i8)))
(type $array (array (mut i8)))
@@ -22,9 +26,9 @@
;; NOMNL: (type $B (struct (field i32) (field i32) (field f32)) (extends $A))
(type $B (struct (field i32) (field i32) (field f32)) (extends $A))
- ;; CHECK: (type $A (struct (field i32)))
- ;; NOMNL: (type $A (struct (field i32)))
- (type $A (struct (field i32)))
+ ;; CHECK: (type $B-child (struct (field i32) (field i32) (field f32) (field i64)))
+ ;; NOMNL: (type $B-child (struct (field i32) (field i32) (field f32) (field i64)) (extends $B))
+ (type $B-child (struct (field i32) (field i32) (field f32) (field i64)) (extends $B))
;; CHECK: (type $empty (struct ))
;; NOMNL: (type $empty (struct ))
@@ -1954,4 +1958,659 @@
)
)
)
+
+ ;; CHECK: (func $ref-cast-static-null
+ ;; CHECK-NEXT: (local $a (ref null $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $B))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref null $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $a
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-cast-static-null
+ ;; NOMNL-NEXT: (local $a (ref null $A))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref null $A))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.null $A)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.null $A)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref null $A))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.null $B)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.null $A)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref null $B))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.null $A)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.null $B)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref null $A))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.tee $a
+ ;; NOMNL-NEXT: (ref.null $A)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.null $A)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-cast-static-null
+ (local $a (ref null $A))
+ ;; Casting nulls results in a null.
+ (drop
+ (ref.cast_static $A
+ (ref.null $A)
+ )
+ )
+ (drop
+ (ref.cast_static $A
+ (ref.null $B)
+ )
+ )
+ (drop
+ (ref.cast_static $B
+ (ref.null $A)
+ )
+ )
+ ;; A fallthrough works too.
+ (drop
+ (ref.cast_static $A
+ (local.tee $a
+ (ref.null $A)
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-static-impossible (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 (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_static $struct
+ (local.get $func)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-static-general (param $a (ref null $A)) (param $b (ref null $B))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $a)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $b)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B
+ ;; CHECK-NEXT: (local.get $a)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $a
+ ;; CHECK-NEXT: (local.get $a)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-cast-static-general (param $a (ref null $A)) (param $b (ref null $B))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $a)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $b)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B
+ ;; NOMNL-NEXT: (local.get $a)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.tee $a
+ ;; NOMNL-NEXT: (local.get $a)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-cast-static-general (param $a (ref null $A)) (param $b (ref null $B))
+ ;; In the general case, a static cast of something simply succeeds if the
+ ;; type is a subtype.
+ (drop
+ (ref.cast_static $A
+ (local.get $a)
+ )
+ )
+ (drop
+ (ref.cast_static $A
+ (local.get $b)
+ )
+ )
+ ;; This is the only one that we cannot know for sure will succeed.
+ (drop
+ (ref.cast_static $B
+ (local.get $a)
+ )
+ )
+ ;; A fallthrough works too.
+ (drop
+ (ref.cast_static $A
+ (local.tee $a
+ (local.get $a)
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-static-squared (param $x eqref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $A
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-cast-static-squared (param $x eqref)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $A
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-cast-static-squared (param $x eqref)
+ ;; Identical ref.casts can be folded together.
+ (drop
+ (ref.cast_static $A
+ (ref.cast_static $A
+ (local.get $x)
+ )
+ )
+ )
+ ;; When subtypes exist, we only need the stricter one.
+ (drop
+ (ref.cast_static $A
+ (ref.cast_static $B
+ (local.get $x)
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $B
+ (ref.cast_static $A
+ (local.get $x)
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-static-many (param $x eqref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-cast-static-many (param $x eqref)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-cast-static-many (param $x eqref)
+ ;; We should optimize a long sequence of static casts when we can. All six
+ ;; orderings of these casts should collapse into the strictest one.
+ (drop
+ (ref.cast_static $A
+ (ref.cast_static $B
+ (ref.cast_static $B-child
+ (local.get $x)
+ )
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $A
+ (ref.cast_static $B-child
+ (ref.cast_static $B
+ (local.get $x)
+ )
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $B
+ (ref.cast_static $A
+ (ref.cast_static $B-child
+ (local.get $x)
+ )
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $B
+ (ref.cast_static $B-child
+ (ref.cast_static $A
+ (local.get $x)
+ )
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $B-child
+ (ref.cast_static $A
+ (ref.cast_static $B
+ (local.get $x)
+ )
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $B-child
+ (ref.cast_static $B
+ (ref.cast_static $A
+ (local.get $x)
+ )
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-static-very-many (param $x eqref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $B-child
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-cast-static-very-many (param $x eqref)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $B-child
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-cast-static-very-many (param $x eqref)
+ ;; We should optimize an arbitrarily-long long sequence of static casts.
+ (drop
+ (ref.cast_static $A
+ (ref.cast_static $B
+ (ref.cast_static $B-child
+ (ref.cast_static $A
+ (ref.cast_static $A
+ (ref.cast_static $B-child
+ (ref.cast_static $B-child
+ (ref.cast_static $B
+ (ref.cast_static $B
+ (ref.cast_static $B
+ (ref.cast_static $B-child
+ (ref.cast_static $A
+ (local.get $x)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-static-squared-impossible (param $x eqref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast_static $struct
+ ;; CHECK-NEXT: (ref.cast_static $array
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-cast-static-squared-impossible (param $x eqref)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast_static $struct
+ ;; NOMNL-NEXT: (ref.cast_static $array
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref $struct))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-cast-static-squared-impossible (param $x eqref)
+ ;; Impossible casts will trap unless the input is null.
+ (drop
+ (ref.cast_static $struct
+ (ref.cast_static $array
+ (local.get $x)
+ )
+ )
+ )
+ (drop
+ (ref.cast_static $struct
+ (ref.cast_static $array
+ (ref.as_non_null (local.get $x))
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-test-static-same-type (param $nullable (ref null $A)) (param $non-nullable (ref $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.test_static $A
+ ;; CHECK-NEXT: (local.get $nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $non-nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-test-static-same-type (param $nullable (ref null $A)) (param $non-nullable (ref $A))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.test_static $A
+ ;; NOMNL-NEXT: (local.get $nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $non-nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 1)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-test-static-same-type (param $nullable (ref null $A)) (param $non-nullable (ref $A))
+ ;; A nullable value cannot be optimized here even though it is the same
+ ;; type.
+ (drop
+ (ref.test_static $A
+ (local.get $nullable)
+ )
+ )
+ ;; But if it is non-nullable, it must succeed.
+ (drop
+ (ref.test_static $A
+ (local.get $non-nullable)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-test-static-subtype (param $nullable (ref null $B)) (param $non-nullable (ref $B))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.test_static $A
+ ;; CHECK-NEXT: (local.get $nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $non-nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-test-static-subtype (param $nullable (ref null $B)) (param $non-nullable (ref $B))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.test_static $A
+ ;; NOMNL-NEXT: (local.get $nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $non-nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 1)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-test-static-subtype (param $nullable (ref null $B)) (param $non-nullable (ref $B))
+ ;; As above, but the input is a subtype, so the same things happen.
+ (drop
+ (ref.test_static $A
+ (local.get $nullable)
+ )
+ )
+ (drop
+ (ref.test_static $A
+ (local.get $non-nullable)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-test-static-supertype (param $nullable (ref null $A)) (param $non-nullable (ref $A))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.test_static $B
+ ;; CHECK-NEXT: (local.get $nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.test_static $B
+ ;; CHECK-NEXT: (local.get $non-nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-test-static-supertype (param $nullable (ref null $A)) (param $non-nullable (ref $A))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.test_static $B
+ ;; NOMNL-NEXT: (local.get $nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.test_static $B
+ ;; NOMNL-NEXT: (local.get $non-nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-test-static-supertype (param $nullable (ref null $A)) (param $non-nullable (ref $A))
+ ;; As above, but the input is a supertype. We can't know at compile time
+ ;; what to do here.
+ (drop
+ (ref.test_static $B
+ (local.get $nullable)
+ )
+ )
+ (drop
+ (ref.test_static $B
+ (local.get $non-nullable)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-test-static-impossible (param $nullable (ref null $array)) (param $non-nullable (ref $array))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $non-nullable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; NOMNL: (func $ref-test-static-impossible (param $nullable (ref null $array)) (param $non-nullable (ref $array))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 0)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result i32)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.get $non-nullable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (i32.const 0)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ (func $ref-test-static-impossible (param $nullable (ref null $array)) (param $non-nullable (ref $array))
+ ;; Testing an impossible cast will definitely fail.
+ (drop
+ (ref.test_static $struct
+ (local.get $nullable)
+ )
+ )
+ (drop
+ (ref.test_static $struct
+ (local.get $non-nullable)
+ )
+ )
+ )
)
diff --git a/test/passes/Oz_fuzz-exec_all-features.txt b/test/passes/Oz_fuzz-exec_all-features.txt
index 179a75082..5730b7ad8 100644
--- a/test/passes/Oz_fuzz-exec_all-features.txt
+++ b/test/passes/Oz_fuzz-exec_all-features.txt
@@ -533,17 +533,10 @@
(i32.const 0)
)
(call $log
- (ref.test_static $struct
- (array.new $bytes
- (i32.const 20)
- (i32.const 10)
- )
- )
+ (i32.const 0)
)
(call $log
- (ref.test_static $struct
- (struct.new_default $struct)
- )
+ (i32.const 1)
)
(call $log
(ref.test_static $extendedstruct
@@ -551,9 +544,7 @@
)
)
(call $log
- (ref.test_static $struct
- (struct.new_default $extendedstruct)
- )
+ (i32.const 1)
)
)
(func $29 (; has Stack IR ;)