summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-08-17 14:47:02 -0700
committerGitHub <noreply@github.com>2023-08-17 14:47:02 -0700
commit7abe224ab5c00fa471e3f4e1ed176974b8ac4e9b (patch)
tree6dafb705a4f5ee3570c3c610a2eef777d9a7efcd
parent67dd6f7db409f9ab7171e97db9da2a4e01a5dc4b (diff)
downloadbinaryen-7abe224ab5c00fa471e3f4e1ed176974b8ac4e9b.tar.gz
binaryen-7abe224ab5c00fa471e3f4e1ed176974b8ac4e9b.tar.bz2
binaryen-7abe224ab5c00fa471e3f4e1ed176974b8ac4e9b.zip
Further improve ref.cast during finalization (#5882)
We previously improved the nullability and heap type of the ref.cast target type in RefCast::finalize() based on what we knew about its input type. Simplify the code and make this improvement more powerful by using the greatest lower bound of the original cast target and input type.
-rw-r--r--src/wasm/wasm.cpp27
-rw-r--r--test/lit/passes/optimize-casts.wast8
-rw-r--r--test/lit/passes/optimize-instructions-call_ref.wast2
-rw-r--r--test/lit/passes/optimize-instructions-gc-iit.wast4
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast16
-rw-r--r--test/lit/passes/precompute-gc.wast2
-rw-r--r--test/lit/passes/signature-refining.wast2
7 files changed, 30 insertions, 31 deletions
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 648a25d9e..74b944bb6 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -948,23 +948,18 @@ void RefCast::finalize() {
return;
}
- // Do not unnecessarily lose non-nullability info. We could leave this for
- // optimizations, but doing it here as part of finalization/refinalization
- // ensures that type information flows through in an optimal manner and can be
- // used as soon as possible.
- if (ref->type.isNonNullable() && type.isNullable()) {
- type = Type(type.getHeapType(), NonNullable);
- }
-
- // Do not unnecessarily lose heap type info, as above for nullability. Note
- // that we must check if the ref has a heap type, as we reach this before
- // validation, which will error if the ref does not in fact have a heap type.
- // (This is a downside of propagating type information here, as opposed to
- // leaving it for an optimization pass.)
- if (ref->type.isRef() &&
- HeapType::isSubType(ref->type.getHeapType(), type.getHeapType())) {
- type = Type(ref->type.getHeapType(), type.getNullability());
+ // We reach this before validation, so the input type might be totally wrong.
+ // Return early in this case to avoid doing the wrong thing below.
+ if (!ref->type.isRef()) {
+ return;
}
+
+ // Do not unnecessarily lose type information. We could leave this for
+ // optimizations (and indeed we do a more powerful version of this in
+ // OptimizeInstructions), but doing it here as part of
+ // finalization/refinalization ensures that type information flows through in
+ // an optimal manner and can be used as soon as possible.
+ type = Type::getGreatestLowerBound(type, ref->type);
}
void BrOn::finalize() {
diff --git a/test/lit/passes/optimize-casts.wast b/test/lit/passes/optimize-casts.wast
index 254daedc4..097f03c62 100644
--- a/test/lit/passes/optimize-casts.wast
+++ b/test/lit/passes/optimize-casts.wast
@@ -824,7 +824,9 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast $D
- ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (block (result anyref)
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -841,7 +843,9 @@
)
(drop
(ref.cast $D
- (local.get $x)
+ (block (result anyref)
+ (local.get $x)
+ )
)
)
)
diff --git a/test/lit/passes/optimize-instructions-call_ref.wast b/test/lit/passes/optimize-instructions-call_ref.wast
index a085e1ed4..3b2ec2b54 100644
--- a/test/lit/passes/optimize-instructions-call_ref.wast
+++ b/test/lit/passes/optimize-instructions-call_ref.wast
@@ -160,7 +160,7 @@
;; CHECK: (func $fallthrough-bad-type (type $none_=>_i32) (result i32)
;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref nofunc))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.func $return-nothing)
;; CHECK-NEXT: )
diff --git a/test/lit/passes/optimize-instructions-gc-iit.wast b/test/lit/passes/optimize-instructions-gc-iit.wast
index b3d5a2559..e4694f4c7 100644
--- a/test/lit/passes/optimize-instructions-gc-iit.wast
+++ b/test/lit/passes/optimize-instructions-gc-iit.wast
@@ -39,7 +39,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $child)
;; CHECK-NEXT: )
@@ -60,7 +60,7 @@
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (drop
- ;; TNH-NEXT: (block
+ ;; TNH-NEXT: (block (result (ref none))
;; TNH-NEXT: (drop
;; TNH-NEXT: (local.get $child)
;; TNH-NEXT: )
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index 6d9e32d3d..e7933e8a1 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -584,7 +584,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast i31
;; CHECK-NEXT: (local.get $x)
@@ -1088,7 +1088,7 @@
;; CHECK: (func $incompatible-cast-of-non-null (type $ref|$struct|_=>_none) (param $struct (ref $struct))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
@@ -1988,7 +1988,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast $array
;; CHECK-NEXT: (local.get $x)
@@ -1998,7 +1998,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast $array
;; CHECK-NEXT: (local.get $x)
@@ -2008,7 +2008,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast $array
;; CHECK-NEXT: (local.get $x)
@@ -2320,7 +2320,7 @@
;; CHECK: (func $ref-cast-heap-type-incompatible (type $ref?|$B|_ref|$B|_=>_none) (param $null-b (ref null $B)) (param $b (ref $B))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $b)
;; CHECK-NEXT: )
@@ -2328,7 +2328,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $null-b)
;; CHECK-NEXT: )
@@ -2336,7 +2336,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $b)
;; CHECK-NEXT: )
diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast
index 369bd685c..94b076687 100644
--- a/test/lit/passes/precompute-gc.wast
+++ b/test/lit/passes/precompute-gc.wast
@@ -810,7 +810,7 @@
;; CHECK: (func $odd-cast-and-get-non-null (type $ref|$func-return-i32|_=>_none) (param $temp (ref $func-return-i32))
;; CHECK-NEXT: (local.set $temp
- ;; CHECK-NEXT: (ref.cast $func-return-i32
+ ;; CHECK-NEXT: (ref.cast nofunc
;; CHECK-NEXT: (ref.func $receive-f64)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast
index 1b575174d..dc674b1b0 100644
--- a/test/lit/passes/signature-refining.wast
+++ b/test/lit/passes/signature-refining.wast
@@ -873,7 +873,7 @@
;; CHECK: (func $1 (type $ref|$[i8]|_=>_none) (param $2 (ref $[i8]))
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast struct
+ ;; CHECK-NEXT: (ref.cast none
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )