summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-01-09 15:15:43 -0800
committerGitHub <noreply@github.com>2023-01-09 15:15:43 -0800
commita803a0830586aaa3e9c989403881298b430f312c (patch)
treeb2208d66d1abc2e875b990f4a1816a69ba7cc3a0 /test
parent67abc2a1b9adcdf080387a29e0c92b6f5a31057a (diff)
downloadbinaryen-a803a0830586aaa3e9c989403881298b430f312c.tar.gz
binaryen-a803a0830586aaa3e9c989403881298b430f312c.tar.bz2
binaryen-a803a0830586aaa3e9c989403881298b430f312c.zip
[Wasm GC] More minor cast optimizations (#5402)
Look for definitely-failing casts along all the fallthrough values. Specifically, if any cast in the middle proves the final cast will fail, then we know we will trap. Fully optimize redundant casts, considering both the type and the heap type. Combine a cast with a ref.as_non_null.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast258
1 files changed, 130 insertions, 128 deletions
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index 42b915c38..e6ee4784a 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -32,18 +32,14 @@
;; NOMNL: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
(type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
+ (type $empty (struct))
+
;; CHECK: (type $void (func))
;; CHECK: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
-
- ;; CHECK: (type $empty (struct ))
;; NOMNL: (type $void (func))
;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
-
- ;; NOMNL: (type $empty (struct ))
- (type $empty (struct))
-
(type $C (struct_subtype (field i32) (field i32) (field f64) $A))
(type $void (func))
@@ -880,10 +876,8 @@
;; CHECK: (func $flip-cast-of-as-non-null (type $anyref_=>_none) (param $x anyref)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $struct
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $struct
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
@@ -894,19 +888,20 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast $struct
- ;; CHECK-NEXT: (ref.as_i31
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (block (result (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.as_i31
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (func $flip-cast-of-as-non-null (type $anyref_=>_none) (param $x anyref)
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $struct
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $struct
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
@@ -917,17 +912,20 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.cast $struct
- ;; NOMNL-NEXT: (ref.as_i31
- ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: (block (result (ref $struct))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.as_i31
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
(func $flip-cast-of-as-non-null (param $x anyref)
(drop
(ref.cast $struct
- ;; this can be moved through the ref.cast null outward.
+ ;; this can be folded into the outer cast, which checks for null too
(ref.as_non_null
(local.get $x)
)
@@ -944,7 +942,7 @@
)
)
)
- ;; other ref.as* operations are ignored for now
+ ;; This will trap, so we can emit an unreachable.
(drop
(ref.cast $struct
(ref.as_i31
@@ -1243,24 +1241,21 @@
)
;; CHECK: (func $ref-cast-squared-different (type $eqref_=>_none) (param $x eqref)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null $struct
- ;; CHECK-NEXT: (ref.cast null $empty
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast null none
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (func $ref-cast-squared-different (type $eqref_=>_none) (param $x eqref)
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.cast null $struct
- ;; NOMNL-NEXT: (ref.cast null $empty
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast null none
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
(func $ref-cast-squared-different (param $x eqref)
- ;; Different casts cannot be folded.
+ ;; Different casts cannot be folded. We can emit a cast to null here, which
+ ;; is the only possible thing that can pass through.
(drop
(ref.cast null $struct
(ref.cast null $empty
@@ -1369,10 +1364,8 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $struct
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $struct
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
@@ -1391,10 +1384,8 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $array
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $array
+ ;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
@@ -1403,17 +1394,13 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $struct
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $struct
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $array
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $array
+ ;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
@@ -1424,10 +1411,8 @@
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (block (result i32)
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $struct
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $struct
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
@@ -1446,10 +1431,8 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $array
- ;; NOMNL-NEXT: (local.get $y)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $array
+ ;; NOMNL-NEXT: (local.get $y)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (i32.const 0)
@@ -1458,17 +1441,13 @@
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (block (result i32)
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $struct
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $struct
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $array
- ;; NOMNL-NEXT: (local.get $y)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $array
+ ;; NOMNL-NEXT: (local.get $y)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (i32.const 0)
@@ -1523,29 +1502,21 @@
;; CHECK: (func $ref-eq-possible-b (type $eqref_eqref_=>_none) (param $x eqref) (param $y eqref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.eq
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $A
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $B
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $B
+ ;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.eq
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $B
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $B
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $A
- ;; CHECK-NEXT: (local.get $y)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $A
+ ;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -1553,29 +1524,21 @@
;; NOMNL: (func $ref-eq-possible-b (type $eqref_eqref_=>_none) (param $x eqref) (param $y eqref)
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (ref.eq
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $A
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $A
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $B
- ;; NOMNL-NEXT: (local.get $y)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $B
+ ;; NOMNL-NEXT: (local.get $y)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (ref.eq
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $B
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $B
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $A
- ;; NOMNL-NEXT: (local.get $y)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $A
+ ;; NOMNL-NEXT: (local.get $y)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
@@ -1586,14 +1549,10 @@
(drop
(ref.eq
(ref.cast $A
- (ref.as_non_null
- (local.get $x)
- )
+ (local.get $x)
)
(ref.cast $B
- (ref.as_non_null
- (local.get $y)
- )
+ (local.get $y)
)
)
)
@@ -1601,14 +1560,10 @@
(drop
(ref.eq
(ref.cast $B
- (ref.as_non_null
- (local.get $x)
- )
+ (local.get $x)
)
(ref.cast $A
- (ref.as_non_null
- (local.get $y)
- )
+ (local.get $y)
)
)
)
@@ -1736,14 +1691,14 @@
;; CHECK: (func $incompatible-cast-of-unknown (type $ref?|$struct|_=>_none) (param $struct (ref null $struct))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null $array
+ ;; CHECK-NEXT: (ref.cast null none
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; NOMNL: (func $incompatible-cast-of-unknown (type $ref?|$struct|_=>_none) (param $struct (ref null $struct))
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.cast null $array
+ ;; NOMNL-NEXT: (ref.cast null none
;; NOMNL-NEXT: (local.get $struct)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
@@ -2602,19 +2557,35 @@
;; CHECK: (func $ref-cast-static-squared-impossible (type $eqref_=>_none) (param $x eqref)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null $struct
- ;; CHECK-NEXT: (ref.cast null $array
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (ref.cast null none
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast $array
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $struct))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.cast null $array
- ;; CHECK-NEXT: (local.get $x)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $array
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast $array
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
@@ -2623,19 +2594,35 @@
;; CHECK-NEXT: )
;; NOMNL: (func $ref-cast-static-squared-impossible (type $eqref_=>_none) (param $x eqref)
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.cast null $struct
- ;; NOMNL-NEXT: (ref.cast null $array
- ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: (ref.cast null none
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref $struct))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast $array
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (block (result (ref $struct))
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.cast null $array
- ;; NOMNL-NEXT: (local.get $x)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.cast $array
+ ;; NOMNL-NEXT: (local.get $x)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (block (result (ref $struct))
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (ref.cast $array
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (unreachable)
@@ -2643,7 +2630,8 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
(func $ref-cast-static-squared-impossible (param $x eqref)
- ;; Impossible casts will trap unless the input is null.
+ ;; Impossible casts will trap unless the input is null. Only the first one
+ ;; here, which lets a null get through, will not trap.
(drop
(ref.cast null $struct
(ref.cast null $array
@@ -2653,6 +2641,20 @@
)
(drop
(ref.cast $struct
+ (ref.cast null $array
+ (local.get $x)
+ )
+ )
+ )
+ (drop
+ (ref.cast null $struct
+ (ref.cast $array
+ (local.get $x)
+ )
+ )
+ )
+ (drop
+ (ref.cast $struct
(ref.cast $array
(ref.as_non_null (local.get $x))
)
@@ -3062,7 +3064,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null $struct
+ ;; CHECK-NEXT: (ref.cast null none
;; CHECK-NEXT: (local.get $null-b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -3093,7 +3095,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.cast null $struct
+ ;; NOMNL-NEXT: (ref.cast null none
;; NOMNL-NEXT: (local.get $null-b)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
@@ -3117,8 +3119,8 @@
(local.get $b)
)
)
- ;; This last case is the only one that can succeed. We leave it alone, but
- ;; in theory we could optimize it to { ref == null ? null : trap }.
+ ;; This last case is the only one that can succeed. We turn it into a cast
+ ;; to a null.
(drop
(ref.cast null $struct
(local.get $null-b)