blob: a2fe437114626766b08d1caaa0f2b6f487c807be [file] [log] [blame] [edit]
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (ref.cast (ref $B)
;; CHECK-NEXT: (br_if $label$1
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (ref.cast (ref $B)
;; CHECK-NEXT: (br_if $label$1
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (ref.cast (ref $C)
;; CHECK-NEXT: (br_if $label$1
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (ref.cast (ref $B)
;; CHECK-NEXT: (br_if $label$1
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (local.set $temp
;; CHECK-NEXT: (ref.cast (ref $B)
;; CHECK-NEXT: (br_if $label$1
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_if $label$1
;; 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 $label$1 (result (ref $A))
;; CHECK-NEXT: (br_if $label$1
;; 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)
)
)
)
)