summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/gto-mutability.wast201
-rw-r--r--test/lit/passes/gto-removals.wast389
2 files changed, 584 insertions, 6 deletions
diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast
index 8610e0760..bd657bb90 100644
--- a/test/lit/passes/gto-mutability.wast
+++ b/test/lit/passes/gto-mutability.wast
@@ -15,6 +15,8 @@
;; CHECK: (type $none_=>_ref?|$struct| (func_subtype (result (ref null $struct)) func))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (tag $tag (param (ref $struct)))
(tag $tag (param (ref $struct)))
@@ -114,6 +116,19 @@
)
(ref.null $struct)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $struct 2
+ ;; CHECK-NEXT: (ref.null $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ ;; --gto will remove fields that are not read from, so add reads to any
+ ;; that don't already have them.
+ (drop (struct.get $struct 2 (ref.null $struct)))
+ )
)
(module
@@ -127,6 +142,8 @@
;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func (param $x (ref $A))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $x)
@@ -147,6 +164,35 @@
(i32.const 20)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 0
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 1
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 1
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $A 0 (ref.null $A)))
+ (drop (struct.get $A 1 (ref.null $A)))
+ (drop (struct.get $B 0 (ref.null $B)))
+ (drop (struct.get $B 1 (ref.null $B)))
+ )
)
(module
@@ -160,6 +206,8 @@
;; CHECK: (type $ref|$B|_=>_none (func_subtype (param (ref $B)) func))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func (param $x (ref $B))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $x)
@@ -180,6 +228,35 @@
(f64.const 3.14159)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 0
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 1
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 1
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $A 0 (ref.null $A)))
+ (drop (struct.get $A 1 (ref.null $A)))
+ (drop (struct.get $B 0 (ref.null $B)))
+ (drop (struct.get $B 1 (ref.null $B)))
+ )
)
(module
@@ -193,6 +270,8 @@
;; CHECK: (type $ref|$A|_ref|$B|_=>_none (func_subtype (param (ref $A) (ref $B)) func))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func (param $x (ref $A)) (param $y (ref $B))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $x)
@@ -213,6 +292,35 @@
(f64.const 3.14159)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 0
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $A 1
+ ;; CHECK-NEXT: (ref.null $A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 0
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $B 1
+ ;; CHECK-NEXT: (ref.null $B)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $A 0 (ref.null $A)))
+ (drop (struct.get $A 1 (ref.null $A)))
+ (drop (struct.get $B 0 (ref.null $B)))
+ (drop (struct.get $B 1 (ref.null $B)))
+ )
)
(module
@@ -225,6 +333,8 @@
;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func (param $x (ref $struct))
;; CHECK-NEXT: (struct.set $struct 2
;; CHECK-NEXT: (local.get $x)
@@ -237,19 +347,42 @@
(i32.const 1)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $struct 0
+ ;; CHECK-NEXT: (ref.null $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $struct 1
+ ;; CHECK-NEXT: (ref.null $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $struct 2
+ ;; CHECK-NEXT: (ref.null $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $struct 0 (ref.null $struct)))
+ (drop (struct.get $struct 1 (ref.null $struct)))
+ (drop (struct.get $struct 2 (ref.null $struct)))
+ )
)
(module
;; Subtyping. Without a write in either supertype or subtype, we can
;; optimize the field to be immutable.
- ;; CHECK: (type $none_=>_none (func_subtype func))
-
;; CHECK: (type $super (struct_subtype (field i32) data))
(type $super (struct (field (mut i32))))
;; CHECK: (type $sub (struct_subtype (field i32) $super))
(type $sub (struct_subtype (field (mut i32)) $super))
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $super
@@ -275,6 +408,23 @@
)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $super 0
+ ;; CHECK-NEXT: (ref.null $super)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (ref.null $sub)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $super 0 (ref.null $super)))
+ (drop (struct.get $sub 0 (ref.null $sub)))
+ )
)
(module
@@ -282,11 +432,13 @@
;; CHECK: (type $super (struct_subtype (field (mut i32)) data))
(type $super (struct (field (mut i32))))
- ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) func))
-
;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super))
(type $sub (struct_subtype (field (mut i32)) $super))
+ ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) func))
+
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func (param $x (ref $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $super
@@ -320,19 +472,39 @@
(i32.const 2)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $super 0
+ ;; CHECK-NEXT: (ref.null $super)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (ref.null $sub)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $super 0 (ref.null $super)))
+ (drop (struct.get $sub 0 (ref.null $sub)))
+ )
)
(module
;; As above, but add a write in the sub, which prevents optimization.
- ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super))
- ;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func))
+ ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super))
;; CHECK: (type $super (struct_subtype (field (mut i32)) data))
(type $super (struct (field (mut i32))))
(type $sub (struct_subtype (field (mut i32)) $super))
+ ;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func))
+
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
;; CHECK: (func $func (param $x (ref $sub))
;; CHECK-NEXT: (struct.set $sub 0
;; CHECK-NEXT: (local.get $x)
@@ -345,4 +517,21 @@
(i32.const 2)
)
)
+
+ ;; CHECK: (func $field-keepalive
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $super 0
+ ;; CHECK-NEXT: (ref.null $super)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $sub 0
+ ;; CHECK-NEXT: (ref.null $sub)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $field-keepalive
+ (drop (struct.get $super 0 (ref.null $super)))
+ (drop (struct.get $sub 0 (ref.null $sub)))
+ )
)
diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast
new file mode 100644
index 000000000..2247285ca
--- /dev/null
+++ b/test/lit/passes/gto-removals.wast
@@ -0,0 +1,389 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+;; RUN: foreach %s %t wasm-opt --nominal --gto -all -S -o - | filecheck %s
+;; (remove-unused-names is added to test fallthrough values without a block
+;; name getting in the way)
+
+(module
+ ;; A struct with a field that is never read or written, so it can be
+ ;; removed.
+
+ ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
+
+ ;; CHECK: (type $struct (struct_subtype data))
+ (type $struct (struct_subtype (field (mut funcref)) data))
+
+ ;; CHECK: (func $func (param $x (ref $struct))
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func (param $x (ref $struct))
+ )
+)
+
+(module
+ ;; A write does not keep a field from being removed.
+
+ ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
+
+ ;; CHECK: (type $struct (struct_subtype data))
+ (type $struct (struct_subtype (field (mut funcref)) data))
+
+ ;; CHECK: (func $func (param $x (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func (param $x (ref $struct))
+ ;; The fields of this set will be dropped, as we do not need to perform
+ ;; the write.
+ (struct.set $struct 0
+ (local.get $x)
+ (ref.null func)
+ )
+ )
+)
+
+(module
+ ;; A new does not keep a field from being removed.
+
+ ;; CHECK: (type $struct (struct_subtype data))
+ (type $struct (struct_subtype (field (mut funcref)) data))
+
+ ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
+
+ ;; CHECK: (func $func (param $x (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new_default $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func (param $x (ref $struct))
+ ;; The fields in this new will be removed.
+ (drop
+ (struct.new $struct
+ (ref.null func)
+ )
+ )
+ )
+)
+
+(module
+ ;; A new_default does not keep a field from being removed.
+
+ ;; CHECK: (type $struct (struct_subtype data))
+ (type $struct (struct_subtype (field (mut funcref)) data))
+
+ ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
+
+ ;; CHECK: (func $func (param $x (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new_default $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func (param $x (ref $struct))
+ ;; The fields in this new will be removed.
+ (drop
+ (struct.new_default $struct
+ )
+ )
+ )
+)
+
+(module
+ ;; A read *does* keep a field from being removed.
+
+ ;; CHECK: (type $struct (struct_subtype (field funcref) data))
+ (type $struct (struct_subtype (field (mut funcref)) data))
+
+ ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func))
+
+ ;; CHECK: (func $func (param $x (ref $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $struct 0
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func (param $x (ref $struct))
+ (drop
+ (struct.get $struct 0
+ (local.get $x)
+ )
+ )
+ )
+)
+
+(module
+ ;; Different struct types with different situations: some fields are read,
+ ;; some written, and some both. (Note that this also tests the interaction
+ ;; of removing with the immutability inference that --gto does.)
+
+ ;; A struct with all fields marked mutable.
+ ;; CHECK: (type $mut-struct (struct_subtype (field $r i32) (field $rw (mut i32)) (field $r-2 i32) (field $rw-2 (mut i32)) data))
+ (type $mut-struct (struct_subtype (field $r (mut i32)) (field $w (mut i32)) (field $rw (mut i32)) (field $r-2 (mut i32)) (field $w-2 (mut i32)) (field $rw-2 (mut i32)) data))
+
+ ;; A similar struct but with all fields marked immutable, and the only
+ ;; writes are from during creation (so all fields are at least writeable).
+ ;; CHECK: (type $imm-struct (struct_subtype (field $rw i32) (field $rw-2 i32) data))
+ (type $imm-struct (struct_subtype (field $w i32) (field $rw i32) (field $w-2 i32) (field $rw-2 i32) data))
+
+ ;; CHECK: (type $ref|$mut-struct|_=>_none (func_subtype (param (ref $mut-struct)) func))
+
+ ;; CHECK: (type $ref|$imm-struct|_=>_none (func_subtype (param (ref $imm-struct)) func))
+
+ ;; CHECK: (func $func-mut (param $x (ref $mut-struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mut-struct $r
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (struct.set $mut-struct $rw
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mut-struct $rw
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mut-struct $r-2
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (struct.set $mut-struct $rw-2
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $mut-struct $rw-2
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func-mut (param $x (ref $mut-struct))
+ ;; $r is only read
+ (drop
+ (struct.get $mut-struct $r
+ (local.get $x)
+ )
+ )
+ ;; $w is only written
+ (struct.set $mut-struct $w
+ (local.get $x)
+ (i32.const 0)
+ )
+ ;; $rw is both
+ (struct.set $mut-struct $rw
+ (local.get $x)
+ (i32.const 1)
+ )
+ (drop
+ (struct.get $mut-struct $rw
+ (local.get $x)
+ )
+ )
+ ;; The same, for the $*-2 fields
+ (drop
+ (struct.get $mut-struct $r-2
+ (local.get $x)
+ )
+ )
+ (struct.set $mut-struct $w-2
+ (local.get $x)
+ (i32.const 2)
+ )
+ (struct.set $mut-struct $rw-2
+ (local.get $x)
+ (i32.const 3)
+ )
+ (drop
+ (struct.get $mut-struct $rw-2
+ (local.get $x)
+ )
+ )
+ )
+
+ ;; CHECK: (func $func-imm (param $x (ref $imm-struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new $imm-struct
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 3)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $imm-struct $rw
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $imm-struct $rw-2
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func-imm (param $x (ref $imm-struct))
+ ;; create an instance
+ (drop
+ (struct.new $imm-struct
+ (i32.const 0)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ )
+ )
+ ;; $rw and $rw-2 are also read
+ (drop
+ (struct.get $imm-struct $rw
+ (local.get $x)
+ )
+ )
+ (drop
+ (struct.get $imm-struct $rw-2
+ (local.get $x)
+ )
+ )
+ )
+)
+
+(module
+ ;; A vtable-like structure created in a global location. Only some of the
+ ;; fields are accessed.
+
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
+ ;; CHECK: (type $vtable (struct_subtype (field $v1 funcref) (field $v2 funcref) data))
+ (type $vtable (struct_subtype (field $v0 funcref) (field $v1 funcref) (field $v2 funcref) (field $v3 funcref) (field $v4 funcref) data))
+
+ ;; CHECK: (global $vtable (ref $vtable) (struct.new $vtable
+ ;; CHECK-NEXT: (ref.func $func-1)
+ ;; CHECK-NEXT: (ref.func $func-2)
+ ;; CHECK-NEXT: ))
+ (global $vtable (ref $vtable) (struct.new $vtable
+ (ref.func $func-0)
+ (ref.func $func-1)
+ (ref.func $func-2)
+ (ref.func $func-3)
+ (ref.func $func-4)
+ ))
+
+ ;; CHECK: (func $test
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $vtable $v1
+ ;; CHECK-NEXT: (global.get $vtable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.get $vtable $v2
+ ;; CHECK-NEXT: (global.get $vtable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ ;; To differ from previous tests, do not read the very first field.
+ (drop
+ (struct.get $vtable 1
+ (global.get $vtable)
+ )
+ )
+ ;; To differ from previous tests, do reads in two adjacent fields.
+ (drop
+ (struct.get $vtable 2
+ (global.get $vtable)
+ )
+ )
+ ;; To differ from previous tests, do not read the very last field, and the
+ ;; one before it.
+ )
+
+ ;; CHECK: (func $func-0
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func-0)
+ ;; CHECK: (func $func-1
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func-1)
+ ;; CHECK: (func $func-2
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func-2)
+ ;; CHECK: (func $func-3
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func-3)
+ ;; CHECK: (func $func-4
+ ;; CHECK-NEXT: (nop)
+ ;; CHECK-NEXT: )
+ (func $func-4)
+)
+
+(module
+ ;; Similar to the above, but with different types in each field, to verify
+ ;; that we emit valid code and are not confused by the names being right
+ ;; by coincidence.
+
+
+ ;; CHECK: (type $vtable (struct_subtype (field $v1 i64) (field $v2 f32) data))
+ (type $vtable (struct_subtype (field $v0 i32) (field $v1 i64) (field $v2 f32) (field $v3 f64) (field $v4 anyref) data))
+
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
+ ;; CHECK: (global $vtable (ref $vtable) (struct.new $vtable
+ ;; CHECK-NEXT: (i64.const 1)
+ ;; CHECK-NEXT: (f32.const 2.200000047683716)
+ ;; CHECK-NEXT: ))
+ (global $vtable (ref $vtable) (struct.new $vtable
+ (i32.const 0)
+ (i64.const 1)
+ (f32.const 2.2)
+ (f64.const 3.3)
+ (ref.null data)
+ ))
+
+ ;; CHECK: (func $test
+ ;; CHECK-NEXT: (local $i64 i64)
+ ;; CHECK-NEXT: (local $f32 f32)
+ ;; CHECK-NEXT: (local.set $i64
+ ;; CHECK-NEXT: (struct.get $vtable $v1
+ ;; CHECK-NEXT: (global.get $vtable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $f32
+ ;; CHECK-NEXT: (struct.get $vtable $v2
+ ;; CHECK-NEXT: (global.get $vtable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test
+ (local $i64 i64)
+ (local $f32 f32)
+ (local.set $i64
+ (struct.get $vtable 1
+ (global.get $vtable)
+ )
+ )
+ (local.set $f32
+ (struct.get $vtable 2
+ (global.get $vtable)
+ )
+ )
+ )
+)