summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-01-06 17:53:54 -0600
committerGitHub <noreply@github.com>2023-01-06 23:53:54 +0000
commitdea55e161497b9c7beaaa9fb3cdff003060ac391 (patch)
tree9ce352adc9201dcc2fd30b398e4fb7ba8eeb1a44 /test
parent54b1cf9025f5564c49dba730dc9fe6600aa7d532 (diff)
downloadbinaryen-dea55e161497b9c7beaaa9fb3cdff003060ac391.tar.gz
binaryen-dea55e161497b9c7beaaa9fb3cdff003060ac391.tar.bz2
binaryen-dea55e161497b9c7beaaa9fb3cdff003060ac391.zip
Fix a bug optimizing out br_on_cast (#5403)
We were considering casts between unrelated types as unconditionally failing, but in the case where the unrelated types are nullable, the cast could still succeed if the value is null. This bug was introduced in #5397.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/remove-unused-brs-gc.wast99
1 files changed, 95 insertions, 4 deletions
diff --git a/test/lit/passes/remove-unused-brs-gc.wast b/test/lit/passes/remove-unused-brs-gc.wast
index 5c45b9e7c..b4c529f74 100644
--- a/test/lit/passes/remove-unused-brs-gc.wast
+++ b/test/lit/passes/remove-unused-brs-gc.wast
@@ -144,16 +144,29 @@
)
)
- ;; CHECK: (func $br_on_cast_unrelated (type $none_=>_ref|$struct|) (result (ref $struct))
- ;; CHECK-NEXT: (block $block
+ ;; CHECK: (func $br_on_cast_unrelated (type $none_=>_ref?|$struct|) (result (ref null $struct))
+ ;; CHECK-NEXT: (local $nullable-struct2 (ref null $struct2))
+ ;; CHECK-NEXT: (block $block (result (ref null $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new_default $struct2)
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $struct2)
;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $nullable-struct2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_on_cast $block null $struct
+ ;; CHECK-NEXT: (local.get $nullable-struct2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $br_on_cast_unrelated (result (ref $struct))
- (block $block (result (ref $struct))
+ (func $br_on_cast_unrelated (result (ref null $struct))
+ (local $nullable-struct2 (ref null $struct2))
+ (block $block (result (ref null $struct))
(drop
;; This cast can be computed at compile time: it will definitely fail, so we
;; can remove it.
@@ -161,6 +174,84 @@
(struct.new $struct2)
)
)
+ (drop
+ ;; We can still remove it even if the cast allows nulls.
+ (br_on_cast $block null $struct
+ (struct.new $struct2)
+ )
+ )
+ (drop
+ ;; Or if the cast does not allow nulls and the value is nullable.
+ (br_on_cast $block $struct
+ (local.get $nullable-struct2)
+ )
+ )
+ (drop
+ ;; But if both are nullable, then we can't optimize because the cast would
+ ;; succeed if the value is a null.
+ (br_on_cast $block null $struct
+ (local.get $nullable-struct2)
+ )
+ )
+ (unreachable)
+ )
+ )
+
+ ;; CHECK: (func $br_on_cast_fail_unrelated (type $none_=>_anyref) (result anyref)
+ ;; CHECK-NEXT: (local $nullable-struct2 (ref null $struct2))
+ ;; CHECK-NEXT: (block $block (result (ref null $struct2))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br $block
+ ;; CHECK-NEXT: (struct.new_default $struct2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br $block
+ ;; CHECK-NEXT: (struct.new_default $struct2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br $block
+ ;; CHECK-NEXT: (local.get $nullable-struct2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (br_on_cast_fail $block null $struct
+ ;; CHECK-NEXT: (local.get $nullable-struct2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br_on_cast_fail_unrelated (result anyref)
+ (local $nullable-struct2 (ref null $struct2))
+ (block $block (result anyref)
+ (drop
+ ;; This cast can be computed at compile time: it will definitely fail, so we
+ ;; can replace it with an unconditional br.
+ (br_on_cast_fail $block $struct
+ (struct.new $struct2)
+ )
+ )
+ (drop
+ ;; We can still replace it even if the cast allows nulls.
+ (br_on_cast_fail $block null $struct
+ (struct.new $struct2)
+ )
+ )
+ (drop
+ ;; Or if the cast does not allow nulls and the value is nullable.
+ (br_on_cast_fail $block $struct
+ (local.get $nullable-struct2)
+ )
+ )
+ (drop
+ ;; But if both are nullable, then we can't optimize because the cast would
+ ;; succeed if the value is a null.
+ (br_on_cast_fail $block null $struct
+ (local.get $nullable-struct2)
+ )
+ )
(unreachable)
)
)