summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp3
-rw-r--r--test/lit/passes/optimize-instructions-gc-tnh.wast160
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast62
3 files changed, 113 insertions, 112 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 3a5f56be9..e71519012 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -2227,6 +2227,9 @@ struct OptimizeInstructions
}
assert(curr->op == RefAsNonNull);
+ if (trapOnNull(curr, curr->value)) {
+ return;
+ }
skipNonNullCast(curr->value, curr);
if (!curr->value->type.isNullable()) {
replaceCurrent(curr->value);
diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast
index 7902c2161..846ae4283 100644
--- a/test/lit/passes/optimize-instructions-gc-tnh.wast
+++ b/test/lit/passes/optimize-instructions-gc-tnh.wast
@@ -398,18 +398,10 @@
;; TNH: (func $null.arm.null.effects (type $void)
;; TNH-NEXT: (block ;; (replaces something unreachable we can't emit)
;; TNH-NEXT: (drop
- ;; TNH-NEXT: (block (result nullref)
- ;; TNH-NEXT: (drop
- ;; TNH-NEXT: (ref.as_non_null
- ;; TNH-NEXT: (ref.null none)
- ;; TNH-NEXT: )
- ;; TNH-NEXT: )
- ;; TNH-NEXT: (block (result nullref)
- ;; TNH-NEXT: (drop
- ;; TNH-NEXT: (call $get-i32)
- ;; TNH-NEXT: )
- ;; TNH-NEXT: (ref.null none)
- ;; TNH-NEXT: )
+ ;; TNH-NEXT: (select
+ ;; TNH-NEXT: (unreachable)
+ ;; TNH-NEXT: (ref.null none)
+ ;; TNH-NEXT: (call $get-i32)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (drop
@@ -417,17 +409,42 @@
;; TNH-NEXT: )
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
+ ;; TNH-NEXT: (block
+ ;; TNH-NEXT: (drop
+ ;; TNH-NEXT: (block (result nullref)
+ ;; TNH-NEXT: (drop
+ ;; TNH-NEXT: (call $get-i32)
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: (ref.null none)
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: )
+ ;; TNH-NEXT: (unreachable)
+ ;; TNH-NEXT: )
;; TNH-NEXT: )
;; NO_TNH: (func $null.arm.null.effects (type $void)
- ;; NO_TNH-NEXT: (struct.set $struct 0
- ;; NO_TNH-NEXT: (select (result (ref null $struct))
- ;; NO_TNH-NEXT: (ref.as_non_null
+ ;; NO_TNH-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; NO_TNH-NEXT: (drop
+ ;; NO_TNH-NEXT: (select
+ ;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: (ref.null none)
+ ;; NO_TNH-NEXT: (call $get-i32)
;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: (call $get-i32)
;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (i32.const 1)
+ ;; NO_TNH-NEXT: (drop
+ ;; NO_TNH-NEXT: (i32.const 1)
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (unreachable)
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (block
+ ;; NO_TNH-NEXT: (drop
+ ;; NO_TNH-NEXT: (block (result nullref)
+ ;; NO_TNH-NEXT: (drop
+ ;; NO_TNH-NEXT: (call $get-i32)
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (ref.null none)
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
(func $null.arm.null.effects
@@ -443,6 +460,15 @@
)
(i32.const 1)
)
+ ;; The same, but without ref.as_non_null.
+ (struct.set $struct 0
+ (select (result (ref null $struct))
+ (ref.null none)
+ (ref.null none)
+ (call $get-i32)
+ )
+ (i32.const 1)
+ )
)
;; TNH: (func $set-get-cast (type $structref_=>_none) (param $ref structref)
@@ -529,7 +555,7 @@
)
)
- ;; TNH: (func $cast-if-null (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; TNH: (func $cast-if-null (type $ref|none|_=>_ref|$struct|) (param $x (ref none)) (result (ref $struct))
;; TNH-NEXT: (block ;; (replaces something unreachable we can't emit)
;; TNH-NEXT: (drop
;; TNH-NEXT: (block
@@ -542,34 +568,30 @@
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; NO_TNH: (func $cast-if-null (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; NO_TNH: (func $cast-if-null (type $ref|none|_=>_ref|$struct|) (param $x (ref none)) (result (ref $struct))
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (if (result (ref none))
;; NO_TNH-NEXT: (i32.const 1)
;; NO_TNH-NEXT: (unreachable)
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (local.get $x)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
- (func $cast-if-null (result (ref $struct))
+ (func $cast-if-null (param $x (ref none)) (result (ref $struct))
;; We can remove the unreachable arm of the if here in TNH mode. While doing
;; so we must refinalize properly or else we'll hit an error in pass-debug
;; mode.
(ref.cast $struct
(if (result (ref none))
- (i32.const 1)
- (unreachable)
- (ref.as_non_null
- (ref.null none)
- )
+ (i32.const 1)
+ (unreachable)
+ (local.get $x)
)
)
)
- ;; TNH: (func $cast-if-null-flip (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; TNH: (func $cast-if-null-flip (type $ref|none|_=>_ref|$struct|) (param $x (ref none)) (result (ref $struct))
;; TNH-NEXT: (block ;; (replaces something unreachable we can't emit)
;; TNH-NEXT: (drop
;; TNH-NEXT: (block
@@ -582,27 +604,23 @@
;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; NO_TNH: (func $cast-if-null-flip (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; NO_TNH: (func $cast-if-null-flip (type $ref|none|_=>_ref|$struct|) (param $x (ref none)) (result (ref $struct))
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (if (result (ref none))
;; NO_TNH-NEXT: (i32.const 1)
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (local.get $x)
;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
- (func $cast-if-null-flip (result (ref $struct))
+ (func $cast-if-null-flip (param $x (ref none)) (result (ref $struct))
;; As above but with arms flipped.
(ref.cast $struct
(if (result (ref none))
- (i32.const 1)
- (ref.as_non_null
- (ref.null none)
- )
- (unreachable)
+ (i32.const 1)
+ (local.get $x)
+ (unreachable)
)
)
)
@@ -772,32 +790,23 @@
)
)
- ;; TNH: (func $select.unreachable.child (type $none_=>_ref|$struct|) (result (ref $struct))
- ;; TNH-NEXT: (select
- ;; TNH-NEXT: (ref.as_non_null
- ;; TNH-NEXT: (ref.null none)
+ ;; TNH: (func $select.unreachable.child (type $ref|$struct|_=>_ref|$struct|) (param $x (ref $struct)) (result (ref $struct))
+ ;; TNH-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; TNH-NEXT: (drop
+ ;; TNH-NEXT: (unreachable)
;; TNH-NEXT: )
;; TNH-NEXT: (unreachable)
- ;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; NO_TNH: (func $select.unreachable.child (type $none_=>_ref|$struct|) (result (ref $struct))
- ;; NO_TNH-NEXT: (select
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (block
- ;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: )
+ ;; NO_TNH: (func $select.unreachable.child (type $ref|$struct|_=>_ref|$struct|) (param $x (ref $struct)) (result (ref $struct))
+ ;; NO_TNH-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (i32.const 1)
+ ;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
- (func $select.unreachable.child (result (ref $struct))
+ (func $select.unreachable.child (param $x (ref $struct)) (result (ref $struct))
;; We will turn the false arm of the select into an unreachable first, and
;; then process the select. While doing so we must not error, as the select
;; itself will still have a reachable type (a full refinalize only
@@ -807,50 +816,31 @@
(ref.as_non_null
(ref.null none)
)
- (ref.cast $struct
- (ref.as_non_null
- (ref.null none)
- )
- )
+ (local.get $x)
(i32.const 1)
)
)
)
- ;; TNH: (func $select.unreachable.child.flip (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; TNH: (func $select.unreachable.child.flip (type $ref|$struct|_=>_ref|$struct|) (param $x (ref $struct)) (result (ref $struct))
;; TNH-NEXT: (select
+ ;; TNH-NEXT: (local.get $x)
;; TNH-NEXT: (unreachable)
- ;; TNH-NEXT: (ref.as_non_null
- ;; TNH-NEXT: (ref.null none)
- ;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; TNH-NEXT: )
- ;; NO_TNH: (func $select.unreachable.child.flip (type $none_=>_ref|$struct|) (result (ref $struct))
+ ;; NO_TNH: (func $select.unreachable.child.flip (type $ref|$struct|_=>_ref|$struct|) (param $x (ref $struct)) (result (ref $struct))
;; NO_TNH-NEXT: (select
- ;; NO_TNH-NEXT: (block
- ;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (unreachable)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (ref.as_non_null
- ;; NO_TNH-NEXT: (ref.null none)
- ;; NO_TNH-NEXT: )
+ ;; NO_TNH-NEXT: (local.get $x)
+ ;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: (i32.const 1)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
- (func $select.unreachable.child.flip (result (ref $struct))
+ (func $select.unreachable.child.flip (param $x (ref $struct)) (result (ref $struct))
;; Flip case of the above.
(ref.cast $struct
(select (result (ref $struct))
- (ref.cast $struct
- (ref.as_non_null
- (ref.null none)
- )
- )
+ (local.get $x)
(ref.as_non_null
(ref.null none)
)
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index c7238b353..adcf654d6 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -28,17 +28,17 @@
(type $B (struct_subtype (field i32) (field i32) (field f32) $A))
- ;; CHECK: (type $void (func))
-
;; CHECK: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B))
- ;; NOMNL: (type $void (func))
-
;; 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))
+ ;; NOMNL: (type $void (func))
+
;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A))
(type $C (struct_subtype (field i32) (field i32) (field f64) $A))
@@ -908,32 +908,32 @@
)
)
- ;; CHECK: (func $flip-tee-of-as-non-null-non-nullable (type $ref|any|_=>_none) (param $x (ref any))
+ ;; CHECK: (func $flip-tee-of-as-non-null-non-nullable (type $ref|any|_anyref_=>_none) (param $x (ref any)) (param $y anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; NOMNL: (func $flip-tee-of-as-non-null-non-nullable (type $ref|any|_=>_none) (param $x (ref any))
+ ;; NOMNL: (func $flip-tee-of-as-non-null-non-nullable (type $ref|any|_anyref_=>_none) (param $x (ref any)) (param $y anyref)
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (local.tee $x
;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.null none)
+ ;; NOMNL-NEXT: (local.get $y)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
- (func $flip-tee-of-as-non-null-non-nullable (param $x (ref any))
+ (func $flip-tee-of-as-non-null-non-nullable (param $x (ref any)) (param $y (ref null any))
(drop
(local.tee $x
;; this *cannnot* be moved through the tee outward, as the param is in
;; fact non-nullable, and we depend on the ref.as_non_null in order to
;; get a valid type to assign to it
(ref.as_non_null
- (ref.null any)
+ (local.get $y)
)
)
)
@@ -1579,7 +1579,7 @@
)
)
- ;; CHECK: (func $incompatible-cast-of-null (type $void)
+ ;; CHECK: (func $incompatible-cast-of-null (type $ref?|$struct|_=>_none) (param $x (ref null $struct))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
@@ -1587,14 +1587,14 @@
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; NOMNL: (func $incompatible-cast-of-null (type $void)
+ ;; NOMNL: (func $incompatible-cast-of-null (type $ref?|$struct|_=>_none) (param $x (ref null $struct))
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
@@ -1602,14 +1602,14 @@
;; NOMNL-NEXT: (block
;; NOMNL-NEXT: (drop
;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (ref.null none)
+ ;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
- (func $incompatible-cast-of-null
+ (func $incompatible-cast-of-null (param $x (ref null $struct))
(drop
(ref.cast $array
;; The child is null, so the cast will trap. Replace it with an
@@ -1623,7 +1623,7 @@
;; transformation. In practice this code will trap before getting to our
;; new unreachable.
(ref.as_non_null
- (ref.null $struct)
+ (local.get $x)
)
)
)
@@ -3160,27 +3160,35 @@
;; CHECK: (func $struct.set.null.fallthrough (type $void)
;; CHECK-NEXT: (local $temp (ref null $struct))
- ;; CHECK-NEXT: (struct.set $struct $i8
- ;; CHECK-NEXT: (local.tee $temp
- ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.tee $temp
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 100)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; NOMNL: (func $struct.set.null.fallthrough (type $void)
;; NOMNL-NEXT: (local $temp (ref null $struct))
- ;; NOMNL-NEXT: (struct.set $struct $i8
- ;; NOMNL-NEXT: (local.tee $temp
- ;; NOMNL-NEXT: (ref.null none)
+ ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (local.tee $temp
+ ;; NOMNL-NEXT: (unreachable)
+ ;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (i32.const 100)
+ ;; NOMNL-NEXT: (drop
+ ;; NOMNL-NEXT: (i32.const 100)
+ ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (unreachable)
;; NOMNL-NEXT: )
(func $struct.set.null.fallthrough
(local $temp (ref null $struct))
- ;; The value falling through the tee shows the local.set will trap. We can
+ ;; The value falling through the tee shows the struct.set will trap. We can
;; append an unreachable after it. While doing so we must not emit a drop of
;; the struct.set (which would be valid for a struct.get etc.).
(struct.set $struct 0