blob: a5af3e26c824c22b9cd74803ed3da242e30dcfcb [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt --closed-world --cfp -all -S -o - | filecheck %s
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new_default $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Copy the default value from $A to $B. Note that we do not detect that $B
;; is never allocated in this pass.
(local $A (ref $A))
(local.set $A
(struct.new_default $A)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Same, but copy a non-default value.
(local $A (ref $A))
(local.set $A
(struct.new $A
(i32.const 10)
)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Now the copy has to look through fallthroughs on both the source and
;; destination.
(local $A (ref $A))
(local.set $A
(struct.new $A
(i32.const 10)
)
)
(struct.set $B 0
(block (result (ref null $B))
(local.get $B)
)
(block (result i32)
(struct.get $A 0
(local.get $A)
)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $B
;; CHECK-NEXT: (struct.new $B
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Now copy from $A to $B, but also allocate a $B with a matching value. We
;; should still optimize.
(local $A (ref $A))
(local.set $A
(struct.new $A
(i32.const 10)
)
)
;; This is new.
(local.set $B
(struct.new $B
(i32.const 10)
)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Now instead of allocating $B with the same value, we set $B with the same
;; value. We can still optimize.
(local $A (ref $A))
(local.set $A
(struct.new $A
(i32.const 10)
)
)
;; This is a set now.
(struct.set $B 0
(local.get $B)
(i32.const 10)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $B
;; CHECK-NEXT: (struct.new $B
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Same, but now allocate $B with a conflicting value. We cannot optimize.
(local $A (ref $A))
(local.set $A
(struct.new $A
(i32.const 10)
)
)
(local.set $B
(struct.new $B
;; Does not match.
(i32.const 20)
)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This cannot be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local $A (ref $A))
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $B (ref $B)) (result i32)
;; Same, but now the conflicting value comes from a set rather than an
;; allocation.
(local $A (ref $A))
(local.set $A
(struct.new $A
(i32.const 10)
)
)
;; This is a set now.
(struct.set $B 0
(local.get $B)
(i32.const 20)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This cannot be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; Now the copied value comes from a set.
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; The copied value comes from both a set and an allocation, but they match.
(local.set $A
(struct.new $A
(i32.const 10)
)
)
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (local.set $A
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (struct.get $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; Now the source values don't match, so we cannot optimize.
(local.set $A
(struct.new $A
(i32.const 10)
)
)
(struct.set $A 0
(local.get $A)
(i32.const 20)
)
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; This should be optimized.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $other) (ref $struct))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $other
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $other (ref $other)) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $struct (ref $struct))
;; Copy from $other to $struct.
(struct.set $struct 0
(local.get $struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub (ref null $sub))
;; We never wrote to $super, so the only value we can read from it is what
;; was written to $struct (which also may have been a $sub at runtime).
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $other) (ref (exact $struct)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $other
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; Same as above, but now we copy to exact $struct.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param (ref $other) (ref $struct))))
;; CHECK: (func $init (type $5)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above, but now with a different value in the subtype $sub1. We
;; also add an additional subtype, $sub2, which can still be optimized.
(drop
(struct.new $other
(i32.const 10)
)
)
(drop
(struct.new $sub1
(i32.const 20)
)
)
)
;; CHECK: (func $copy (type $6) (param $other (ref $other)) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $struct (ref $struct))
;; Copy from $other to $struct.
(struct.set $struct 0
(local.get $struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $5)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
;; The copy might have written to $sub1 or $sub2, but only $sub2 does not
;; already have another conflicting value. We can optimize $sub2 but not
;; $sub1.
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $5)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param (ref $other) (ref (exact $struct)))))
;; CHECK: (func $init (type $5)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above.
(drop
(struct.new $other
(i32.const 10)
)
)
(drop
(struct.new $sub1
(i32.const 20)
)
)
)
;; CHECK: (func $copy (type $6) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; Now the copy is to exact $struct.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $5)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $5)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param (ref $sub1))))
;; CHECK: (type $7 (func (param (ref $other) (ref $struct))))
;; CHECK: (func $init (type $6) (param $sub1 (ref $sub1))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $sub1 (ref $sub1))
;; Now the value is set to an inexact reference to $sub1. This won't make a
;; difference.
(drop
(struct.new $other
(i32.const 10)
)
)
(struct.set $sub1 0
(local.get $sub1)
(i32.const 20)
)
)
;; CHECK: (func $copy (type $7) (param $other (ref $other)) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $struct (ref $struct))
;; Copy from $other to $struct.
(struct.set $struct 0
(local.get $struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $5)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $5)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $5 (func))
;; CHECK: (type $6 (func (param (ref $sub1))))
;; CHECK: (type $7 (func (param (ref $other) (ref (exact $struct)))))
;; CHECK: (func $init (type $6) (param $sub1 (ref $sub1))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $sub1 (ref $sub1))
;; Same as above.
(drop
(struct.new $other
(i32.const 10)
)
)
(struct.set $sub1 0
(local.get $sub1)
(i32.const 20)
)
)
;; CHECK: (func $copy (type $7) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; Now the copy is to exact $struct.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $5)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $5)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $other) (ref $struct))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $super
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Now the different value is in $super. Since it's set in an exact $super,
;; it won't interfere with the copy.
(drop
(struct.new $other
(i32.const 10)
)
)
(drop
(struct.new $super
(i32.const 20)
)
)
)
;; CHECK: (func $copy (type $5) (param $other (ref $other)) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $struct (ref $struct))
;; Copy from $other to $struct.
(struct.set $struct 0
(local.get $struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $other) (ref (exact $struct)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $super
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above.
(drop
(struct.new $other
(i32.const 10)
)
)
(drop
(struct.new $super
(i32.const 20)
)
)
)
;; CHECK: (func $copy (type $5) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; Copy from $other to exact $struct.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $super))))
;; CHECK: (type $6 (func (param (ref $other) (ref $struct))))
;; CHECK: (func $init (type $5) (param $super (ref $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $super (ref $super))
;; Now the different value is in an inexact $super.
(drop
(struct.new $other
(i32.const 10)
)
)
(struct.set $super 0
(local.get $super)
(i32.const 20)
)
)
;; CHECK: (func $copy (type $6) (param $other (ref $other)) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $struct (ref $struct))
;; Copy from $other to $struct.
(struct.set $struct 0
(local.get $struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub 0
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub 0
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $super))))
;; CHECK: (type $6 (func (param (ref $other) (ref (exact $struct)))))
;; CHECK: (func $init (type $5) (param $super (ref $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $super (ref $super))
;; Same as above.
(drop
(struct.new $other
(i32.const 10)
)
)
(struct.set $super 0
(local.get $super)
(i32.const 20)
)
)
;; CHECK: (func $copy (type $6) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
;; Copy from $other to exact $struct.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct)))
(type $super (sub (struct)))
;; CHECK: (type $A (sub $super (struct (field (mut i32)))))
(type $A (sub $super (struct (field (mut i32)))))
;; CHECK: (type $B (sub $super (struct (field (mut i32)))))
(type $B (sub $super (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $super))))
;; CHECK: (type $6 (func (param (ref $other) (ref $A))))
;; CHECK: (func $init (type $5) (param $super (ref $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $super (ref $super))
(drop
(struct.new $other
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $6) (param $other (ref $other)) (param $A (ref $A))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $A (ref $A))
;; Copy from $other to $A. The fact that the field is missing in $super
;; should not cause problems.
(struct.set $A 0
(local.get $A)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $B (ref null $B))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $A (ref null $A))
(local $B (ref null $B))
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $A (ref null (exact $A)))
;; CHECK-NEXT: (local $B (ref null (exact $B)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $A (ref null (exact $A)))
(local $B (ref null (exact $B)))
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct)))
(type $super (sub (struct)))
;; CHECK: (type $A (sub $super (struct (field (mut i32)))))
(type $A (sub $super (struct (field (mut i32)))))
;; CHECK: (type $B (sub $super (struct (field (mut i32)))))
(type $B (sub $super (struct (field (mut i32)))))
;; CHECK: (type $other (struct (field (mut i32))))
(type $other (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $super))))
;; CHECK: (type $6 (func (param (ref $other) (ref (exact $A)))))
;; CHECK: (func $init (type $5) (param $super (ref $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $other
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $super (ref $super))
(drop
(struct.new $other
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $6) (param $other (ref $other)) (param $exact-A (ref (exact $A)))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $exact-A)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $other (ref $other)) (param $exact-A (ref (exact $A)))
;; Same as above, but now the copy is to exact $A.
(struct.set $A 0
(local.get $exact-A)
(struct.get $other 0
(local.get $other)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $B (ref null $B))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $A (ref null $A))
(local $B (ref null $B))
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $A (ref null (exact $A)))
;; CHECK-NEXT: (local $B (ref null (exact $B)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $A (ref null (exact $A)))
(local $B (ref null (exact $B)))
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above.
(drop
(struct.new $sub1
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $struct (ref $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct))
;; Copy from $struct to itself. This propagates the write from $sub1 to
;; $sub2.
(struct.set $struct 0
(local.get $struct)
(struct.get $struct 0
(local.get $struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct) (ref (exact $struct)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above.
(drop
(struct.new $sub1
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
;; Now copy from $struct to exact $struct. This does not propagate to $sub2.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $struct 0
(local.get $struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct) (ref (exact $struct)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above.
(drop
(struct.new $sub1
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
;; Now copy from exact $struct to $struct. This does nothing, since exact
;; $struct is not written to originally.
(struct.set $struct 0
(local.get $struct)
(struct.get $struct 0
(local.get $exact-struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref (exact $struct)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above.
(drop
(struct.new $sub1
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $exact-struct (ref (exact $struct)))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $exact-struct (ref (exact $struct)))
;; Now copy from exact $struct to exact $struct.
(struct.set $struct 0
(local.get $exact-struct)
(struct.get $struct 0
(local.get $exact-struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $struct2 (sub $super (struct (field (mut i32)))))
(type $struct2 (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct) (ref $super))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $sub
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $struct (ref $struct)) (param $super (ref $super))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct)) (param $super (ref $super))
;; Copy from $struct to $super.
(struct.set $super 0
(local.get $super)
(struct.get $struct 0
(local.get $struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $struct2 (ref null $struct2))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $struct2 (ref null $struct2))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $struct2 (ref null (exact $struct2)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $struct2 (ref null (exact $struct2)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $struct2 (sub $super (struct (field (mut i32)))))
(type $struct2 (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct) (ref (exact $super)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $sub
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $struct (ref $struct)) (param $exact-super (ref (exact $super)))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $exact-super)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct)) (param $exact-super (ref (exact $super)))
;; Copy from $struct to exact $super.
(struct.set $super 0
(local.get $exact-super)
(struct.get $struct 0
(local.get $struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $struct2 (ref null $struct2))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $struct2 (ref null $struct2))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $struct2 (ref null (exact $struct2)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $struct2 (ref null (exact $struct2)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $struct2 (sub $super (struct (field (mut i32)))))
(type $struct2 (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref (exact $struct)) (ref $super))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $sub
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $exact-struct (ref (exact $struct))) (param $super (ref $super))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $exact-struct (ref (exact $struct))) (param $super (ref $super))
;; Copy from exact $struct to $super.
(struct.set $super 0
(local.get $super)
(struct.get $struct 0
(local.get $exact-struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $struct2 (ref null $struct2))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $struct2 (ref null $struct2))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $struct2 (ref null (exact $struct2)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $struct2 (ref null (exact $struct2)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32)))))
;; CHECK: (type $struct2 (sub $super (struct (field (mut i32)))))
(type $struct2 (sub $super (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $struct (struct (field (mut i32)))))
(type $sub (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref (exact $struct)) (ref (exact $super)))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $sub
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $exact-struct (ref (exact $struct))) (param $exact-super (ref (exact $super)))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $exact-super)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $exact-struct (ref (exact $struct))) (param $exact-super (ref (exact $super)))
;; Copy from exact $struct to exact $super.
(struct.set $super 0
(local.get $exact-super)
(struct.get $struct 0
(local.get $exact-struct)
)
)
)
;; CHECK: (func $gets (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $struct2 (ref null $struct2))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $struct2 (ref null $struct2))
(local $sub (ref null $sub))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $exact-gets (type $4)
;; CHECK-NEXT: (local $super (ref null (exact $super)))
;; CHECK-NEXT: (local $struct (ref null (exact $struct)))
;; CHECK-NEXT: (local $struct2 (ref null (exact $struct2)))
;; CHECK-NEXT: (local $sub (ref null (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $struct2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $super (ref null (exact $super)))
(local $struct (ref null (exact $struct)))
(local $struct2 (ref null (exact $struct2)))
(local $sub (ref null (exact $sub)))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $struct2 0
(local.get $struct2)
)
)
(drop
(struct.get $sub 0
(local.get $sub)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $struct (sub (struct (field (mut i32)))))
(type $struct (sub (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $3 (func))
;; CHECK: (type $4 (func (param (ref $struct) (ref $sub1))))
;; CHECK: (func $init (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $struct
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $struct
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4) (param $struct (ref $struct)) (param $sub1 (ref $sub1))
;; CHECK-NEXT: (struct.set $sub1 0
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct)) (param $sub1 (ref $sub1))
;; Copy from $struct to $sub1.
(struct.set $sub1 0
(local.get $sub1)
(struct.get $struct 0
(local.get $struct)
)
)
)
;; CHECK: (func $gets (type $3)
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $3)
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $struct (ref null $struct))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $struct (sub (struct (field (mut i32)))))
(type $struct (sub (struct (field (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32)))))
)
;; CHECK: (type $3 (func))
;; CHECK: (type $4 (func (param (ref $struct) (ref (exact $sub1)))))
;; CHECK: (func $init (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $struct
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $struct
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4) (param $struct (ref $struct)) (param $exact-sub1 (ref (exact $sub1)))
;; CHECK-NEXT: (struct.set $sub1 0
;; CHECK-NEXT: (local.get $exact-sub1)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $struct (ref $struct)) (param $exact-sub1 (ref (exact $sub1)))
;; Copy from $struct to exact $sub1.
(struct.set $sub1 0
(local.get $exact-sub1)
(struct.get $struct 0
(local.get $struct)
)
)
)
;; CHECK: (func $gets (type $3)
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $gets
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $exact-gets (type $3)
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null (exact $sub1)))
;; CHECK-NEXT: (local $sub2 (ref null (exact $sub2)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $exact-gets
(local $struct (ref null $struct))
(local $sub1 (ref null (exact $sub1)))
(local $sub2 (ref null (exact $sub2)))
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $super (sub (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct) (ref $struct))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 666)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $sub1
(i32.const 666)
(i32.const 10)
(i32.const 0)
)
)
)
;; CHECK: (func $copy (type $5) (param $src (ref $struct)) (param $dst (ref $struct))
;; CHECK-NEXT: (struct.set $struct 2
;; CHECK-NEXT: (local.get $dst)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $src)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $src (ref $struct)) (param $dst (ref $struct))
;; Copy from index 1 to index 2 in the same type. The copied value will
;; conflict with the initial value and inhibit optimization.
(struct.set $struct 2
(local.get $dst)
(struct.get $struct 1
(local.get $src)
)
)
)
;; CHECK: (func $get-0 (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 666)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 666)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 666)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get-0
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 0
(local.get $super)
)
)
(drop
(struct.get $struct 0
(local.get $struct)
)
)
(drop
(struct.get $sub1 0
(local.get $sub1)
)
)
(drop
(struct.get $sub2 0
(local.get $sub2)
)
)
)
;; CHECK: (func $get-1 (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get-1
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 1
(local.get $super)
)
)
(drop
(struct.get $struct 1
(local.get $struct)
)
)
(drop
(struct.get $sub1 1
(local.get $sub1)
)
)
(drop
(struct.get $sub2 1
(local.get $sub2)
)
)
)
;; CHECK: (func $get-2 (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 2
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 2
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub1 2
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get-2
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 2
(local.get $super)
)
)
(drop
(struct.get $struct 2
(local.get $struct)
)
)
(drop
(struct.get $sub1 2
(local.get $sub1)
)
)
(drop
(struct.get $sub2 2
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $super (sub (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $struct) (ref $struct))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 666)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; Same as above, except now field 2 is initialized with the same value as
;; field 1, so the copy will not do anything.
(drop
(struct.new $sub1
(i32.const 666)
(i32.const 10)
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $5) (param $src (ref $struct)) (param $dst (ref $struct))
;; CHECK-NEXT: (struct.set $struct 2
;; CHECK-NEXT: (local.get $dst)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $src)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $src (ref $struct)) (param $dst (ref $struct))
;; Copy from index 1 to index 2 in the same type.
(struct.set $struct 2
(local.get $dst)
(struct.get $struct 1
(local.get $src)
)
)
)
;; CHECK: (func $get-2 (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get-2
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 2
(local.get $super)
)
)
(drop
(struct.get $struct 2
(local.get $struct)
)
)
(drop
(struct.get $sub1 2
(local.get $sub1)
)
)
(drop
(struct.get $sub2 2
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $super (sub (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $struct (sub $super (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $struct (sub $super (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $sub1 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $sub1 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
;; CHECK: (type $sub2 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
(type $sub2 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $sub1) (ref $sub1))))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $sub1
;; CHECK-NEXT: (i32.const 666)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
;; We're back to initializing field 2 with a different value.
(drop
(struct.new $sub1
(i32.const 666)
(i32.const 10)
(i32.const 0)
)
)
)
;; CHECK: (func $copy (type $5) (param $src (ref $sub1)) (param $dst (ref $sub1))
;; CHECK-NEXT: (struct.set $sub1 2
;; CHECK-NEXT: (local.get $dst)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $src)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $src (ref $sub1)) (param $dst (ref $sub1))
;; Copy from index 1 to index 2, but now on $sub1, so we will be able to
;; optimize $sub2.
(struct.set $sub1 2
(local.get $dst)
(struct.get $sub1 1
(local.get $src)
)
)
)
;; CHECK: (func $get-2 (type $4)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $struct (ref null $struct))
;; CHECK-NEXT: (local $sub1 (ref null $sub1))
;; CHECK-NEXT: (local $sub2 (ref null $sub2))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $super 2
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 2
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $sub1 2
;; CHECK-NEXT: (local.get $sub1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get-2
(local $super (ref null $super))
(local $struct (ref null $struct))
(local $sub1 (ref null $sub1))
(local $sub2 (ref null $sub2))
(drop
(struct.get $super 2
(local.get $super)
)
)
(drop
(struct.get $struct 2
(local.get $struct)
)
)
(drop
(struct.get $sub1 2
(local.get $sub1)
)
)
(drop
(struct.get $sub2 2
(local.get $sub2)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func))
;; CHECK: (type $4 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $3)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $B (ref null $B))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $B (ref null $B))
(local $C (ref null $C))
;; Copy $A to $B.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $B to $C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
)
;; CHECK: (func $get (type $4) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func))
;; CHECK: (type $4 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $3)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $B (ref null $B))
;; CHECK-NEXT: (local $exact-B (ref null (exact $B)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $exact-B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $B (ref null $B))
(local $exact-B (ref null (exact $B)))
(local $C (ref null $C))
;; Copy $A to $B.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy exact $B to $C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $exact-B)
)
)
)
;; CHECK: (func $get (type $4) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func))
;; CHECK: (type $4 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $3)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $B (ref null $B))
;; CHECK-NEXT: (local $exact-B (ref null (exact $B)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $exact-B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $B (ref null $B))
(local $exact-B (ref null (exact $B)))
(local $C (ref null $C))
;; Copy $A to exact $B.
(struct.set $B 0
(local.get $exact-B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $B to $C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
)
;; CHECK: (func $get (type $4) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func))
;; CHECK: (type $4 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $3)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $exact-B (ref null (exact $B)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $exact-B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $exact-B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $exact-B (ref null (exact $B)))
(local $C (ref null $C))
;; Copy $A to exact $B.
(struct.set $B 0
(local.get $exact-B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $exact B to $C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $exact-B)
)
)
)
;; CHECK: (func $get (type $4) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $sub 0
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $sub (ref null $sub))
(local $super (ref null $super))
(local $C (ref null $C))
;; Copy $A to $sub.
(struct.set $sub 0
(local.get $sub)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $super to $C.
(struct.set $C 0
(local.get $C)
(struct.get $super 0
(local.get $super)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (local $exact-super (ref null (exact $super)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $sub 0
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $sub (ref null $sub))
(local $exact-super (ref null (exact $super)))
(local $C (ref null $C))
;; Copy $A to $sub.
(struct.set $sub 0
(local.get $sub)
(struct.get $A 0
(local.get $A)
)
)
;; Copy exact $super to $C. This does not propagate the value.
(struct.set $C 0
(local.get $C)
(struct.get $super 0
(local.get $exact-super)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $exact-sub (ref null (exact $sub)))
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $sub 0
;; CHECK-NEXT: (local.get $exact-sub)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $exact-sub (ref null (exact $sub)))
(local $super (ref null $super))
(local $C (ref null $C))
;; Copy $A to exact $sub.
(struct.set $sub 0
(local.get $exact-sub)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $super to $C.
(struct.set $C 0
(local.get $C)
(struct.get $super 0
(local.get $super)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $exact-sub (ref null (exact $sub)))
;; CHECK-NEXT: (local $exact-super (ref null (exact $super)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $sub 0
;; CHECK-NEXT: (local.get $exact-sub)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $exact-sub (ref null (exact $sub)))
(local $exact-super (ref null (exact $super)))
(local $C (ref null $C))
;; Copy $A to exact $sub.
(struct.set $sub 0
(local.get $exact-sub)
(struct.get $A 0
(local.get $A)
)
)
;; Copy exact $super to $C. This does not propagate the value.
(struct.set $C 0
(local.get $C)
(struct.get $super 0
(local.get $exact-super)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $sub (ref null $sub))
(local $super (ref null $super))
(local $C (ref null $C))
;; Copy $A to $super.
(struct.set $super 0
(local.get $super)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $sub to $C.
(struct.set $C 0
(local.get $C)
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $exact-sub (ref null (exact $sub)))
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $exact-sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $exact-sub (ref null (exact $sub)))
(local $super (ref null $super))
(local $C (ref null $C))
;; Copy $A to $super.
(struct.set $super 0
(local.get $super)
(struct.get $A 0
(local.get $A)
)
)
;; Copy exact $sub to $C.
(struct.set $C 0
(local.get $C)
(struct.get $sub 0
(local.get $exact-sub)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (local $exact-super (ref null (exact $super)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $exact-super)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $sub (ref null $sub))
(local $exact-super (ref null (exact $super)))
(local $C (ref null $C))
;; Copy $A to exact $super.
(struct.set $super 0
(local.get $exact-super)
(struct.get $A 0
(local.get $A)
)
)
;; Copy $sub to $C. This does not propagate the value.
(struct.set $C 0
(local.get $C)
(struct.get $sub 0
(local.get $sub)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $super (sub (struct (field (mut i32)))))
(type $super (sub (struct (field (mut i32)))))
;; CHECK: (type $sub (sub $super (struct (field (mut i32)))))
(type $sub (sub $super (struct (field (mut i32)))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $4 (func))
;; CHECK: (type $5 (func (param (ref $C)) (result i32)))
;; CHECK: (func $init (type $4)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $A
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init
(drop
(struct.new $A
(i32.const 10)
)
)
)
;; CHECK: (func $copy (type $4)
;; CHECK-NEXT: (local $A (ref null $A))
;; CHECK-NEXT: (local $exact-sub (ref null (exact $sub)))
;; CHECK-NEXT: (local $exact-super (ref null (exact $super)))
;; CHECK-NEXT: (local $C (ref null $C))
;; CHECK-NEXT: (struct.set $super 0
;; CHECK-NEXT: (local.get $exact-super)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $exact-sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy
(local $A (ref null $A))
(local $exact-sub (ref null (exact $sub)))
(local $exact-super (ref null (exact $super)))
(local $C (ref null $C))
;; Copy $A to exact $super.
(struct.set $super 0
(local.get $exact-super)
(struct.get $A 0
(local.get $A)
)
)
;; Copy exact $sub to $C. This does not propagate the value.
(struct.set $C 0
(local.get $C)
(struct.get $sub 0
(local.get $exact-sub)
)
)
)
;; CHECK: (func $get (type $5) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $get (param $C (ref $C)) (result i32)
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i32 to i8.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Read truncated i8.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i16))))
(type $B (struct (field (mut i16))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x0001FFFF)
)
;; Copy i32 to i16.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Read truncated i16.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i8 to i32.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read truncated i32.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i8 to i32 with sign extension.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read truncated then sign extended i32.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i16))))
(type $B (struct (field (mut i16))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i8 to i16.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read truncated i16.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i16))))
(type $B (struct (field (mut i16))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i8 to i16 with sign extension.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read truncated then sign extended i16.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i16))))
(type $A (struct (field (mut i16))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x0001FFFF)
)
;; Copy i16 to i32.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read truncated i32.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i16))))
(type $A (struct (field (mut i16))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: (i32.const 16)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 16)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x0001FFFF)
)
;; Copy i16 to i32 with sign extension.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read truncated then sign extended i32.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i16))))
(type $A (struct (field (mut i16))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: (i32.const 65535)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x0001FFFF)
)
;; Copy i16 to i8.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read truncated i8.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i16))))
(type $A (struct (field (mut i16))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const 131071)
;; CHECK-NEXT: (i32.const 16)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 16)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x0001FFFF)
)
;; Copy i16 to i8 with sign extension. This does not make a difference.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read truncated i8.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
)
;; CHECK: (type $1 (func (param (ref $A)) (result i32)))
;; CHECK: (func $test (type $1) (param $A (ref $A)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (struct.get_u $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get_u $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0xFFFFFFFF)
)
;; Copy the i8 to itself.
(struct.set $A 0
(local.get $A)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read truncated i8.
;; TODO: We do not optimize this because the truncated copy value conflicts
;; with the untruncated value found by the initial analysis. Fix this by
;; tracking truncations and sign extensions as part of the analysis.
(struct.get $A 0
(local.get $A)
)
)
)
(module
(rec
;; CHECK: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
)
;; CHECK: (type $1 (func (param (ref $A)) (result i32)))
;; CHECK: (func $test (type $1) (param $A (ref $A)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0xFFFFFFFF)
)
;; Copy the i8 to itself with sign extension.
(struct.set $A 0
(local.get $A)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read truncated i8. Now we can optimize because the sign-extended value
;; happens to match the original value.
(struct.get $A 0
(local.get $A)
)
)
)
(module
(rec
;; CHECK: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
)
;; CHECK: (type $1 (func (param (ref $A)) (result i32)))
;; CHECK: (func $test (type $1) (param $A (ref $A)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (struct.get_s $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get_u $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy the i8 to itself with sign extension.
(struct.set $A 0
(local.get $A)
(struct.get_s $A 0
(local.get $A)
)
)
;; Now the value does not match and we don't optimize, even though we could
;; in principle.
(struct.get $A 0
(local.get $A)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (global $g i32 (i32.const 0))
(global $g i32 (i32.const 0))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get_u $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(global.get $g)
)
;; Copy the i32 with global to the i8.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Read the i8. We do not optimize this because we cannot model the
;; truncation of the global. TODO.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (global $g i32 (i32.const 0))
(global $g i32 (i32.const 0))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(global.get $g)
)
;; Copy the i8 with global to the i32.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read the i32. We still cannot optimize. TODO.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (global $g i32 (i32.const 0))
(global $g i32 (i32.const 0))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
(struct.set $A 0
(local.get $A)
(global.get $g)
)
;; Copy the i8 with global to the i32 with sign extension.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read the i32. We still cannot optimize. TODO.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
)
;; CHECK: (type $1 (func (param (ref $A)) (result i32)))
;; CHECK: (global $g i32 (i32.const 0))
(global $g i32 (i32.const 0))
;; CHECK: (func $test (type $1) (param $A (ref $A)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (struct.get_u $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get_u $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (result i32)
(struct.set $A 0
(local.get $A)
(global.get $g)
)
;; Copy the i8 holding the global to itself.
(struct.set $A 0
(local.get $A)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read the i8. We cannot model the truncated global. TODO.
(struct.get_u $A 0
(local.get $A)
)
)
)
(module
(rec
;; CHECK: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
)
;; CHECK: (type $1 (func (param (ref $A)) (result i32)))
;; CHECK: (global $g i32 (i32.const 0))
(global $g i32 (i32.const 0))
;; CHECK: (func $test (type $1) (param $A (ref $A)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (global.get $g)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (struct.get_s $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get_u $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (result i32)
(struct.set $A 0
(local.get $A)
(global.get $g)
)
;; Copy the i8 holding the global to itself with sign extension.
(struct.set $A 0
(local.get $A)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read the i8. We cannot model the truncated global. TODO.
(struct.get_u $A 0
(local.get $A)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; Copy the uninitialized i8 to i32.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Read the i32. It should still be uninitialized and optimized out.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; Copy the uninitialized i8 to i32 with sign extension.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Read the i32. It should still be uninitialized and optimized out.
(struct.get $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
)
;; CHECK: (type $2 (func (param (ref $A) (ref $B)) (result i32)))
;; CHECK: (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
;; Copy the uninitialized i32 to i8.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Read the i8. It should still be uninitialized and optimized out.
(struct.get_u $B 0
(local.get $B)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i32 to i8.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy the i8 to another i32.
(struct.set $C 0
(local.get $C)
(struct.get_u $B 0
(local.get $B)
)
)
;; Read truncated i32.
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i8))))
(type $B (struct (field (mut i8))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i32 to i8.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy the i8 to another i32 with sign extension.
(struct.set $C 0
(local.get $C)
(struct.get_s $B 0
(local.get $B)
)
)
;; Read truncated i32.
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i8))))
(type $C (struct (field (mut i8))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i8 to i32.
(struct.set $B 0
(local.get $B)
(struct.get_u $A 0
(local.get $A)
)
)
;; Copy the i32 to another i8.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Read the i8.
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i8))))
(type $A (struct (field (mut i8))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i8))))
(type $C (struct (field (mut i8))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.shr_s
;; CHECK-NEXT: (i32.shl
;; CHECK-NEXT: (i32.const 511)
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 24)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.and
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: (i32.const 255)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
(struct.set $A 0
(local.get $A)
(i32.const 0x000001FF)
)
;; Copy i8 to i32 with sign extension.
(struct.set $B 0
(local.get $B)
(struct.get_s $A 0
(local.get $A)
)
)
;; Copy the i32 to another i8.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Read the i8.
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; A and B separately copy matching values into C
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
(struct.set $B 0
(local.get $B)
(i32.const 10)
)
;; Copy A to C.
(struct.set $C 0
(local.get $C)
(struct.get $A 0
(local.get $A)
)
)
;; Copy B to C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Read C.
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.get $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
;; Now A and B separately copy different values into C
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
(struct.set $B 0
(local.get $B)
(i32.const 20)
)
;; Copy A to C.
(struct.set $C 0
(local.get $C)
(struct.get $A 0
(local.get $A)
)
)
;; Copy B to C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Read C. We cannot optimize because there are multiple values.
(struct.get $C 0
(local.get $C)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C))))
;; CHECK: (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; Copy A to both B and C.
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
;; Copy A to B.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy A to C.
(struct.set $C 0
(local.get $C)
(struct.get $A 0
(local.get $A)
)
)
;; Read B. We can optimize.
(drop
(struct.get $B 0
(local.get $B)
)
)
;; Read C. We can optimize this, too.
(drop
(struct.get $C 0
(local.get $C)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C))))
;; CHECK: (func $copy (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; Create a loop copying A -> B -> C -> A.
;; Copy A to B.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy B to C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Copy C to A.
(struct.set $A 0
(local.get $A)
(struct.get $C 0
(local.get $C)
)
)
)
;; CHECK: (func $get (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; Since no value ever entered the loop, these all get optimized out.
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
(drop
(struct.get $C 0
(local.get $C)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C))))
;; CHECK: (type $4 (func (param (ref $A))))
;; CHECK: (func $init (type $4) (param $A (ref $A))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $A (ref $A))
;; Now we inject a value into the loop.
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
)
;; CHECK: (func $copy (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; Create a loop copying A -> B -> C -> A.
;; Copy A to B.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy B to C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Copy C to A.
(struct.set $A 0
(local.get $A)
(struct.get $C 0
(local.get $C)
)
)
)
;; CHECK: (func $get (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; These all get optimized to the one injected value.
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
(drop
(struct.get $C 0
(local.get $C)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $A (struct (field (mut i32))))
(type $A (struct (field (mut i32))))
;; CHECK: (type $B (struct (field (mut i32))))
(type $B (struct (field (mut i32))))
;; CHECK: (type $C (struct (field (mut i32))))
(type $C (struct (field (mut i32))))
)
;; CHECK: (type $3 (func (param (ref $A) (ref $B) (ref $C))))
;; CHECK: (type $4 (func (param (ref $A) (ref $C))))
;; CHECK: (func $init (type $4) (param $A (ref $A)) (param $C (ref $C))
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (i32.const 10)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (i32.const 20)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $init (param $A (ref $A)) (param $C (ref $C))
;; Now we inject two different values into the loop in different places. We
;; won't be able to optimize anything.
(struct.set $A 0
(local.get $A)
(i32.const 10)
)
(struct.set $C 0
(local.get $C)
(i32.const 20)
)
)
;; CHECK: (func $copy (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (struct.set $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (struct.get $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.set $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: (struct.get $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $copy (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; Create a loop copying A -> B -> C -> A.
;; Copy A to B.
(struct.set $B 0
(local.get $B)
(struct.get $A 0
(local.get $A)
)
)
;; Copy B to C.
(struct.set $C 0
(local.get $C)
(struct.get $B 0
(local.get $B)
)
)
;; Copy C to A.
(struct.set $A 0
(local.get $A)
(struct.get $C 0
(local.get $C)
)
)
)
;; CHECK: (func $get (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $A 0
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $B 0
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $C 0
;; CHECK-NEXT: (local.get $C)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $get (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
;; These cannot be optimized.
(drop
(struct.get $A 0
(local.get $A)
)
)
(drop
(struct.get $B 0
(local.get $B)
)
)
(drop
(struct.get $C 0
(local.get $C)
)
)
)
)