diff options
author | Alon Zakai <azakai@google.com> | 2021-09-30 14:51:08 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-30 14:51:08 -0700 |
commit | 58879a6c6f623156d53f72a4ca935df81143f49e (patch) | |
tree | 4c1abca54213c69b78806ced568a0146c4a0c157 /test | |
parent | 71ae6342c418c34d8409c49fd0710ec6fd767ac8 (diff) | |
download | binaryen-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.wast | 665 | ||||
-rw-r--r-- | test/passes/Oz_fuzz-exec_all-features.txt | 15 |
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 ;) |