summaryrefslogtreecommitdiff
path: root/test/lit
diff options
context:
space:
mode:
Diffstat (limited to 'test/lit')
-rw-r--r--test/lit/passes/type-refining.wast130
1 files changed, 130 insertions, 0 deletions
diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast
index 91f61bc15..fad016e1d 100644
--- a/test/lit/passes/type-refining.wast
+++ b/test/lit/passes/type-refining.wast
@@ -1574,3 +1574,133 @@
(ref.null $8)
)
)
+
+;; Test for a bug where we made a struct.get unreachable because it was reading
+;; a field that had no writes, but in a situation where it is invalid for the
+;; struct.get to be unreachable.
+(module
+ ;; CHECK: (type $never (sub (struct (field i32))))
+ (type $never (sub (struct (field i32))))
+
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $optimizable (struct (field (mut nullfuncref))))
+ (type $optimizable (struct (field (mut (ref null func)))))
+
+ ;; CHECK: (type $2 (func))
+
+ ;; CHECK: (global $never (ref null $never) (ref.null none))
+ (global $never (export "never") (ref null $never)
+ ;; Make the type $never public (if it were private, we'd optimize in a
+ ;; different way that avoids the bug that this tests for).
+ (ref.null $never)
+ )
+
+ ;; CHECK: (export "never" (global $never))
+
+ ;; CHECK: (func $setup (type $2)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new $optimizable
+ ;; CHECK-NEXT: (ref.null nofunc)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result (ref none))
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $setup
+ ;; A struct.new, so that we have a field to refine (which avoids the pass
+ ;; early-exiting).
+ (drop
+ (struct.new $optimizable
+ (ref.null func)
+ )
+ )
+ ;; A struct.get that reads a $never, but the actual fallthrough value is none.
+ ;; We never create this type, so the field has no possible content, and we can
+ ;; replace this with an unreachable.
+ (drop
+ (struct.get $never 0
+ (block (result (ref $never))
+ (ref.as_non_null
+ (ref.null none)
+ )
+ )
+ )
+ )
+ )
+)
+
+;; Test that we note default values.
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $A (sub (struct (field i32))))
+ (type $A (sub (struct (field i32))))
+ ;; CHECK: (type $B (sub (struct (field i32))))
+ (type $B (sub (struct (field i32))))
+ )
+ ;; CHECK: (type $2 (func (param (ref null $A) (ref null $B))))
+
+ ;; CHECK: (type $optimizable (sub (struct (field (ref $2)))))
+ (type $optimizable (sub (struct (field funcref))))
+
+ ;; CHECK: (elem declare func $test)
+
+ ;; CHECK: (export "test" (func $test))
+
+ ;; CHECK: (func $test (type $2) (param $x (ref null $A)) (param $y (ref null $B))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new $optimizable
+ ;; CHECK-NEXT: (ref.func $test)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 0
+ ;; CHECK-NEXT: (struct.new $A
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (struct.new_default $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test (export "test") (param $x (ref null $A)) (param $y (ref null $B))
+ ;; Use $A, $B as params of this export, so they are public.
+
+ ;; Make something for the pass to do, to avoid early-exit.
+ (drop
+ (struct.new $optimizable
+ (ref.func $test)
+ )
+ )
+
+ ;; Get from a struct.new. We have nothing to optimize here. (In particular, we
+ ;; cannot make this unreachable, as there is a value in the field, 0.)
+ (drop
+ (struct.get $A 0
+ (struct.new $A
+ (i32.const 0)
+ )
+ )
+ )
+
+ ;; As above. Now the value in the field comes from a default value.
+ (drop
+ (struct.get $B 0
+ (struct.new_default $B)
+ )
+ )
+ )
+)