| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. | |
| ;; Test that our hack for br_if output types does not cause the binary to grow | |
| ;; linearly with each roundtrip (note the three roundtrips here). When we emit | |
| ;; a br_if whose output type is not refined enough (Binaryen IR uses the value's | |
| ;; type; wasm uses the target's) then we add a cast. | |
| ;; RUN: wasm-opt %s -all --roundtrip --roundtrip --roundtrip -S -o - | filecheck %s | |
| (module | |
| (rec | |
| ;; CHECK: (rec | |
| ;; CHECK-NEXT: (type $A (sub (struct))) | |
| (type $A (sub (struct))) | |
| ;; CHECK: (type $B (sub $A (struct))) | |
| (type $B (sub $A (struct))) | |
| ;; CHECK: (type $C (sub $B (struct))) | |
| (type $C (sub $B (struct))) | |
| ) | |
| ;; CHECK: (func $test (type $3) (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (ref.cast (ref $B) | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $B) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test (param $B (ref $B)) (param $x i32) (result anyref) | |
| (block $out (result (ref $A)) | |
| ;; The br_if's value is of type $B which is more precise than the block's | |
| ;; type, $A, so we emit a cast here, but only one despite the three | |
| ;; roundtrips. | |
| (br_if $out | |
| (local.get $B) | |
| (local.get $x) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $test-cast (type $3) (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (ref.cast (ref $B) | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $B) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test-cast (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; This is the result of a single roundtrip: there is a cast. We should not | |
| ;; modify this function at all in additional roundtrips. | |
| (block $out (result (ref $A)) | |
| (ref.cast (ref $B) | |
| (br_if $out | |
| (local.get $B) | |
| (local.get $x) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $test-cast-more (type $3) (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (ref.cast (ref $C) | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $B) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test-cast-more (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; As above but the cast is more refined. Again, we do not need an | |
| ;; additional cast. | |
| (block $out (result (ref $A)) | |
| (ref.cast (ref $C) ;; this changed | |
| (br_if $out | |
| (local.get $B) | |
| (local.get $x) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $test-cast-less (type $3) (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (ref.cast (ref $B) | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $B) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test-cast-less (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; As above but the cast is less refined. As a result we'd add a cast to $B | |
| ;; (but we refine casts automatically in finalize(), so this cast becomes a | |
| ;; cast to $B anyhow, and as a result we have only one cast here). | |
| (block $out (result (ref $A)) | |
| (ref.cast (ref $A) ;; this changed | |
| (br_if $out | |
| (local.get $B) | |
| (local.get $x) | |
| ) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $test-local (type $3) (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (local $temp (ref $B)) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (local.set $temp | |
| ;; CHECK-NEXT: (ref.cast (ref $B) | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $B) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (unreachable) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test-local (param $B (ref $B)) (param $x i32) (result anyref) | |
| (local $temp (ref $B)) | |
| ;; As above, but with local.set that receives the br_if's value, verifying | |
| ;; it is refined. We emit a cast here. | |
| (block $out (result (ref $A)) | |
| (local.set $temp | |
| (br_if $out | |
| (local.get $B) | |
| (local.get $x) | |
| ) | |
| ) | |
| (unreachable) | |
| ) | |
| ) | |
| ;; CHECK: (func $test-drop (type $3) (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (drop | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $B) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (unreachable) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test-drop (param $B (ref $B)) (param $x i32) (result anyref) | |
| ;; As above, but with a drop of the br_if value. We do not emit a cast here. | |
| (block $out (result (ref $A)) | |
| (drop | |
| (br_if $out | |
| (local.get $B) | |
| (local.get $x) | |
| ) | |
| ) | |
| (unreachable) | |
| ) | |
| ) | |
| ;; CHECK: (func $test-same (type $4) (param $A (ref $A)) (param $x i32) (result anyref) | |
| ;; CHECK-NEXT: (block $block (result (ref $A)) | |
| ;; CHECK-NEXT: (br_if $block | |
| ;; CHECK-NEXT: (local.get $A) | |
| ;; CHECK-NEXT: (local.get $x) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $test-same (param $A (ref $A)) (param $x i32) (result anyref) | |
| ;; As above, but now we use $A everywhere, which means there is no | |
| ;; difference between the type in Binaryen IR and wasm, so we do not need | |
| ;; to emit any extra cast here. | |
| (block $out (result (ref $A)) | |
| (br_if $out | |
| (local.get $A) | |
| (local.get $x) | |
| ) | |
| ) | |
| ) | |
| ) |