summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/gto-mutability.wast324
1 files changed, 324 insertions, 0 deletions
diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast
index 3b01572c8..3cf0e7701 100644
--- a/test/lit/passes/gto-mutability.wast
+++ b/test/lit/passes/gto-mutability.wast
@@ -688,3 +688,327 @@
)
)
+;; $sub has a field we can make immutable. That it does not exist in the super
+;; should not confuse us.
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $super (sub (struct)))
+ (type $super (sub (struct)))
+ ;; CHECK: (type $sub (sub $super (struct (field (ref string)))))
+ (type $sub (sub $super (struct (field (mut (ref string))))))
+ )
+
+ ;; CHECK: (type $2 (func))
+
+ ;; CHECK: (func $test (type $2)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (struct.new $sub
+ ;; CHECK-NEXT: (string.const "foo")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ ;; Write and read the field.
+ (drop
+ (struct.get $sub 0
+ (struct.new $sub
+ (string.const "foo")
+ )
+ )
+ )
+ )
+)
+
+;; As above, but with another type in the middle, $mid, which also contains the
+;; field. We can optimize both $mid and $sub.
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $super (sub (struct)))
+ (type $super (sub (struct)))
+ ;; CHECK: (type $mid (sub $super (struct (field (ref string)))))
+ (type $mid (sub $super (struct (field (mut (ref string))))))
+ ;; CHECK: (type $sub (sub $mid (struct (field (ref string)))))
+ (type $sub (sub $mid (struct (field (mut (ref string))))))
+ )
+
+ ;; CHECK: (type $3 (func))
+
+ ;; CHECK: (func $test (type $3)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (struct.new $sub
+ ;; CHECK-NEXT: (string.const "foo")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mid 0
+ ;; CHECK-NEXT: (struct.new $mid
+ ;; CHECK-NEXT: (string.const "bar")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ (drop
+ (struct.get $sub 0
+ (struct.new $sub
+ (string.const "foo")
+ )
+ )
+ )
+ (drop
+ (struct.get $mid 0
+ (struct.new $mid
+ (string.const "bar")
+ )
+ )
+ )
+ )
+)
+
+;; As above, but add another irrelevant field first. We can still optimize the
+;; string, but the new mutable i32 must remain mutable, as it has a set.
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
+ (type $super (sub (struct (field (mut i32)))))
+ ;; CHECK: (type $mid (sub $super (struct (field (mut i32)) (field (ref string)))))
+ (type $mid (sub $super (struct (field (mut i32)) (field (mut (ref string))))))
+ ;; CHECK: (type $sub (sub $mid (struct (field (mut i32)) (field (ref string)))))
+ (type $sub (sub $mid (struct (field (mut i32)) (field (mut (ref string))))))
+ )
+
+ ;; CHECK: (type $3 (func))
+
+ ;; CHECK: (func $test (type $3)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 1
+ ;; CHECK-NEXT: (struct.new $sub
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (string.const "foo")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mid 1
+ ;; CHECK-NEXT: (struct.new $mid
+ ;; CHECK-NEXT: (i32.const 1337)
+ ;; CHECK-NEXT: (string.const "bar")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (struct.set $super 0
+ ;; CHECK-NEXT: (struct.new $super
+ ;; CHECK-NEXT: (i32.const 98765)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $super 0
+ ;; CHECK-NEXT: (struct.new $super
+ ;; CHECK-NEXT: (i32.const 999999)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ (drop
+ (struct.get $sub 1
+ (struct.new $sub
+ (i32.const 42)
+ (string.const "foo")
+ )
+ )
+ )
+ (drop
+ (struct.get $mid 1
+ (struct.new $mid
+ (i32.const 1337)
+ (string.const "bar")
+ )
+ )
+ )
+ ;; A set and get of the first field.
+ (struct.set $super 0
+ (struct.new $super
+ (i32.const 98765)
+ )
+ (i32.const 42)
+ )
+ (drop
+ (struct.get $super 0
+ (struct.new $super
+ (i32.const 999999)
+ )
+ )
+ )
+ )
+)
+
+;; As above, but without a set of the first field. Now we can optimize both
+;; fields.
+(module
+ (rec
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $super (sub (struct (field i32))))
+ (type $super (sub (struct (field (mut i32)))))
+ ;; CHECK: (type $mid (sub $super (struct (field i32) (field (ref string)))))
+ (type $mid (sub $super (struct (field (mut i32)) (field (mut (ref string))))))
+ ;; CHECK: (type $sub (sub $mid (struct (field i32) (field (ref string)))))
+ (type $sub (sub $mid (struct (field (mut i32)) (field (mut (ref string))))))
+ )
+
+ ;; CHECK: (type $3 (func))
+
+ ;; CHECK: (func $test (type $3)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 1
+ ;; CHECK-NEXT: (struct.new $sub
+ ;; CHECK-NEXT: (i32.const 42)
+ ;; CHECK-NEXT: (string.const "foo")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mid 1
+ ;; CHECK-NEXT: (struct.new $mid
+ ;; CHECK-NEXT: (i32.const 1337)
+ ;; CHECK-NEXT: (string.const "bar")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $super 0
+ ;; CHECK-NEXT: (struct.new $super
+ ;; CHECK-NEXT: (i32.const 999999)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ (drop
+ (struct.get $sub 1
+ (struct.new $sub
+ (i32.const 42)
+ (string.const "foo")
+ )
+ )
+ )
+ (drop
+ (struct.get $mid 1
+ (struct.new $mid
+ (i32.const 1337)
+ (string.const "bar")
+ )
+ )
+ )
+ ;; Only a get of the first field.
+ (drop
+ (struct.get $super 0
+ (struct.new $super
+ (i32.const 999999)
+ )
+ )
+ )
+ )
+)
+
+;; The super is public, but we can still optimize the field in the sub.
+(module
+ ;; CHECK: (type $super (sub (struct)))
+ (type $super (sub (struct)))
+
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $sub (sub $super (struct (field stringref))))
+ (type $sub (sub $super (struct (field (mut stringref)))))
+
+ ;; CHECK: (type $2 (func))
+
+ ;; CHECK: (global $global (ref $super) (struct.new_default $super))
+ (global $global (ref $super) (struct.new_default $super))
+ ;; CHECK: (export "global" (global $global))
+ (export "global" (global $global))
+
+ ;; CHECK: (func $test (type $2)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (struct.new $sub
+ ;; CHECK-NEXT: (string.const "foo")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ ;; Write and read the field.
+ (drop
+ (struct.get $sub 0
+ (struct.new $sub
+ (string.const "foo")
+ )
+ )
+ )
+ )
+)
+
+;; As above, and now the super has the field as well, preventing optimization.
+(module
+ ;; CHECK: (type $super (sub (struct (field (mut stringref)))))
+ (type $super (sub (struct (field (mut stringref)))))
+
+ ;; CHECK: (type $sub (sub $super (struct (field (mut stringref)))))
+ (type $sub (sub $super (struct (field (mut stringref)))))
+
+ ;; CHECK: (type $2 (func))
+
+ ;; CHECK: (global $global (ref $super) (struct.new_default $super))
+ (global $global (ref $super) (struct.new_default $super))
+ ;; CHECK: (export "global" (global $global))
+ (export "global" (global $global))
+
+ ;; CHECK: (func $test (type $2)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (struct.new $sub
+ ;; CHECK-NEXT: (string.const "foo")
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ ;; Write and read the field.
+ (drop
+ (struct.get $sub 0
+ (struct.new $sub
+ (string.const "foo")
+ )
+ )
+ )
+ )
+)
+
+;; Two mutable fields with a chain of three subtypes. The super is public,
+;; preventing optimization of the field it has (but not the other; the other
+;; is removable anyhow, though, so this just checks for the lack of an error
+;; when deciding not to make the fields immutable or not).
+(module
+ ;; CHECK: (type $super (sub (struct (field (mut i32)))))
+ (type $super (sub (struct (field (mut i32)))))
+ ;; CHECK: (rec
+ ;; CHECK-NEXT: (type $mid (sub $super (struct (field (mut i32)))))
+ (type $mid (sub $super (struct (field (mut i32)) (field (mut f64)))))
+ ;; CHECK: (type $sub (sub $mid (struct (field (mut i32)))))
+ (type $sub (sub $mid (struct (field (mut i32)) (field (mut f64)))))
+
+ ;; CHECK: (global $global (ref $super) (struct.new_default $sub))
+ (global $global (ref $super) (struct.new_default $sub))
+
+ ;; CHECK: (export "global" (global $global))
+ (export "global" (global $global))
+)
+