| ;; 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-reftest -all -S -o - | filecheck %s |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref $A)))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref (exact $A))))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $A (ref $A)) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $A (ref $A)) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set inexact A. |
| (struct.set $A 0 |
| (local.get $A) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A-exact) |
| ;; 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-exact (ref (exact $A))) |
| ;; Copy to exact A. |
| (struct.set $A 0 |
| (local.get $A-exact) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (struct.get $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We won't be able to optimize because the set of inexact A could go to |
| ;; anything. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref $A)))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref $B)))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $A (ref $A)) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $A (ref $A)) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set inexact A. |
| (struct.set $A 0 |
| (local.get $A) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $B (ref $B)) |
| ;; 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 $other) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $copy (param $other (ref $other)) (param $B (ref $B)) |
| ;; Copy to inexact B. |
| (struct.set $B 0 |
| (local.get $B) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (struct.get $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We won't be able to optimize because the set of inexact A could go to |
| ;; anything. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref $A)))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref (exact $B))))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $A (ref $A)) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $A (ref $A)) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set inexact A. |
| (struct.set $A 0 |
| (local.get $A) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| ;; CHECK-NEXT: (struct.set $B 0 |
| ;; CHECK-NEXT: (local.get $B-exact) |
| ;; 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 $B-exact (ref (exact $B))) |
| ;; Copy to exact B. |
| (struct.set $B 0 |
| (local.get $B-exact) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (struct.get $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We won't be able to optimize because the set of inexact A could go to |
| ;; anything. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref (exact $A))))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref $A)))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A-exact) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set exact A. |
| (struct.set $A 0 |
| (local.get $A-exact) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (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 to inexact A. |
| (struct.set $A 0 |
| (local.get $A) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (struct.get $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We won't be able to optimize because the copy to inexact A could go to |
| ;; anything. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref (exact $A))))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref $B)))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A-exact) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set exact A. |
| (struct.set $A 0 |
| (local.get $A-exact) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $B (ref $B)) |
| ;; 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 $other) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $copy (param $other (ref $other)) (param $B (ref $B)) |
| ;; Copy to inexact B. |
| (struct.set $B 0 |
| (local.get $B) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (select |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: (ref.test (ref $B) |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We can optimize! Only B will have the copied value. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref (exact $A))))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref (exact $B))))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A-exact) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set exact A. |
| (struct.set $A 0 |
| (local.get $A-exact) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| ;; CHECK-NEXT: (struct.set $B 0 |
| ;; CHECK-NEXT: (local.get $B-exact) |
| ;; 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 $B-exact (ref (exact $B))) |
| ;; Copy to exact B. |
| (struct.set $B 0 |
| (local.get $B-exact) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (select |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: (ref.test (ref $B) |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We can optimize! Only B will have the copied value. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref (exact $B))))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref (exact $A))))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $B 0 |
| ;; CHECK-NEXT: (local.get $B-exact) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set exact B. |
| (struct.set $B 0 |
| (local.get $B-exact) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| ;; CHECK-NEXT: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A-exact) |
| ;; 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-exact (ref (exact $A))) |
| ;; Copy to exact A. |
| (struct.set $A 0 |
| (local.get $A-exact) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (select |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: (ref.test (ref $B) |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; Switch the copy and set destinations from the previous case. We can still |
| ;; optimize! |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32)) (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32)) (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref (exact $B))))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref (exact $A))))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $B 0 |
| ;; CHECK-NEXT: (local.get $B-exact) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set exact B. |
| (struct.set $B 0 |
| (local.get $B-exact) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $A-exact (ref (exact $A))) |
| ;; CHECK-NEXT: (struct.set $other 1 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; 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: (struct.set $A 0 |
| ;; CHECK-NEXT: (local.get $A-exact) |
| ;; 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-exact (ref (exact $A))) |
| ;; Copy to another field and from there to exact A. |
| (struct.set $other 1 |
| (local.get $other) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ;; Copy to exact A. |
| (struct.set $A 0 |
| (local.get $A-exact) |
| (struct.get $other 1 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (select |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: (ref.test (ref $B) |
| ;; CHECK-NEXT: (ref.as_non_null |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We can still optimize after doing two copies. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (sub (struct (field (mut i32))))) |
| (type $A (sub (struct (field (mut i32))))) |
| ;; CHECK: (type $B (sub $A (struct (field (mut i32))))) |
| (type $B (sub $A (struct (field (mut i32))))) |
| ;; CHECK: (type $other (sub (struct (field (mut i32)) (field (mut i32))))) |
| (type $other (sub (struct (field (mut i32)) (field (mut i32))))) |
| ) |
| |
| ;; CHECK: (type $3 (func (param (ref $other) (ref (exact $B))))) |
| |
| ;; CHECK: (type $4 (func (param (ref $other) (ref $A)))) |
| |
| ;; CHECK: (type $5 (func (param (ref $A)) (result i32))) |
| |
| ;; CHECK: (func $init (type $3) (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| ;; CHECK-NEXT: (struct.set $other 0 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (struct.set $B 0 |
| ;; CHECK-NEXT: (local.get $B-exact) |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $init (param $other (ref $other)) (param $B-exact (ref (exact $B))) |
| (struct.set $other 0 |
| (local.get $other) |
| (i32.const 10) |
| ) |
| ;; Set exact B. |
| (struct.set $B 0 |
| (local.get $B-exact) |
| (i32.const 20) |
| ) |
| ) |
| |
| ;; CHECK: (func $copy (type $4) (param $other (ref $other)) (param $A (ref $A)) |
| ;; CHECK-NEXT: (struct.set $other 1 |
| ;; CHECK-NEXT: (local.get $other) |
| ;; 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: (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 to another field and from there to inexact A. |
| (struct.set $other 1 |
| (local.get $other) |
| (struct.get $other 0 |
| (local.get $other) |
| ) |
| ) |
| ;; Copy to A. |
| (struct.set $A 0 |
| (local.get $A) |
| (struct.get $other 1 |
| (local.get $other) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $get (type $5) (param $A (ref $A)) (result i32) |
| ;; CHECK-NEXT: (struct.get $A 0 |
| ;; CHECK-NEXT: (local.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $get (param $A (ref $A)) (result i32) |
| ;; We cannot optimize because the copy to inexact A could write to anything. |
| (struct.get $A 0 |
| (local.get $A) |
| ) |
| ) |
| ) |