summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-07-07 12:25:42 -0700
committerGitHub <noreply@github.com>2023-07-07 12:25:42 -0700
commit0d3bb31a37e151a7d4dcf32575f5789f0a3818ce (patch)
tree9f2bb746054460d4fe7efd8a28087edb5e094e5d /test
parentcdb7aeab40b4c522de20b242019f7e88641445d5 (diff)
downloadbinaryen-0d3bb31a37e151a7d4dcf32575f5789f0a3818ce.tar.gz
binaryen-0d3bb31a37e151a7d4dcf32575f5789f0a3818ce.tar.bz2
binaryen-0d3bb31a37e151a7d4dcf32575f5789f0a3818ce.zip
GUFA: Refine casts (#5805)
If we see (ref.cast $A) but we have inferred that a more refined type will be present there at runtime $B then we can refine the cast to (ref.cast $B). We could do the same even when a cast is not present, but that would increase code size. This optimization keeps code size constant.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/gufa-refs.wast41
-rw-r--r--test/lit/passes/gufa-vs-cfp.wast14
2 files changed, 48 insertions, 7 deletions
diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast
index 928796823..50658ef34 100644
--- a/test/lit/passes/gufa-refs.wast
+++ b/test/lit/passes/gufa-refs.wast
@@ -2554,7 +2554,7 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.cast null $struct
+ ;; CHECK-NEXT: (ref.cast null none
;; CHECK-NEXT: (select (result i31ref)
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: (i31.new
@@ -2593,7 +2593,9 @@
)
;; A null or an i31 will reach the cast; only the null can actually pass
;; through (an i31 would fail the cast). Given that, we can infer a null for
- ;; the value of the cast.
+ ;; the value of the cast. (The cast itself will also be turned into a cast
+ ;; to null, but it is dropped right before we return a null, so that has no
+ ;; benefit in this case.)
(drop
(ref.cast null $struct
(select
@@ -5642,3 +5644,38 @@
)
)
)
+
+(module
+ ;; CHECK: (type $A (struct ))
+ (type $A (struct))
+
+ ;; CHECK: (type $B (sub $A (struct )))
+ (type $B (sub $A (struct)))
+
+ ;; CHECK: (type $none_=>_ref|$A| (func (result (ref $A))))
+
+ ;; CHECK: (type $none_=>_anyref (func (result anyref)))
+
+ ;; CHECK: (export "func" (func $func))
+
+ ;; CHECK: (func $func (type $none_=>_ref|$A|) (result (ref $A))
+ ;; CHECK-NEXT: (ref.cast $B
+ ;; CHECK-NEXT: (call $get-B-def-any)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func (export "func") (result (ref $A))
+ ;; Call a function that actually returns a B, though it is defined as
+ ;; returning an anyref. Then cast it to A. We can infer that it will be a B,
+ ;; so we can cast to B here instead.
+ (ref.cast $A
+ (call $get-B-def-any)
+ )
+ )
+
+ ;; CHECK: (func $get-B-def-any (type $none_=>_anyref) (result anyref)
+ ;; CHECK-NEXT: (struct.new_default $B)
+ ;; CHECK-NEXT: )
+ (func $get-B-def-any (result anyref)
+ (struct.new $B)
+ )
+)
diff --git a/test/lit/passes/gufa-vs-cfp.wast b/test/lit/passes/gufa-vs-cfp.wast
index 2171a9fc1..0db24bbad 100644
--- a/test/lit/passes/gufa-vs-cfp.wast
+++ b/test/lit/passes/gufa-vs-cfp.wast
@@ -876,7 +876,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $substruct 0
- ;; CHECK-NEXT: (ref.cast null $substruct
+ ;; CHECK-NEXT: (ref.cast $substruct
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -904,6 +904,8 @@
)
(drop
(struct.get $substruct 0
+ ;; This cast will be refined to be non-nullable, as the LocalGraph
+ ;; analysis will show that it must be so.
(ref.cast null $substruct
(local.get $ref)
)
@@ -949,10 +951,8 @@
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (struct.get $substruct 0
- ;; CHECK-NEXT: (ref.cast null $substruct
- ;; CHECK-NEXT: (local.get $ref)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.cast $substruct
+ ;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
@@ -981,6 +981,10 @@
)
(drop
(struct.get $substruct 0
+ ;; This cast will be refined to be non-nullable, as the LocalGraph
+ ;; analysis will show that it must be so. After that, the dropped
+ ;; struct.get can be removed as it has no side effects (the only
+ ;; possible effect was a trap on null).
(ref.cast null $substruct
(local.get $ref)
)