| ;; 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) |
| ) |
| ) |
| ) |
| ) |