blob: 3febcbff7efdca04c131604f5b595317e1f77891 [file] [log] [blame] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; Part of cast-and-recast.wast, but containing tuples. This is split out
;; because we do not roundtrip tuple-containing code properly. We also use only
;; one roundtrip because of the accumulation of tuple logic, which would
;; otherwise make the output here very hard to read.
;; RUN: wasm-opt %s -all --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: (func $test-local-tuple-1 (type $5) (param $B (ref $B)) (param $x i32) (result anyref i32)
;; CHECK-NEXT: (local $2 (tuple (ref $B) i32))
;; CHECK-NEXT: (local $3 (ref $B))
;; CHECK-NEXT: (local $4 (tuple (ref $A) i32))
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (block $label$1 (type $3) (result (ref $A) i32)
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (br_if $label$1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test-local-tuple-1 (param $B (ref $B)) (param $x i32) (result anyref i32)
;; A dropped tuple that contains a ref. As it is dropped, we do not need to
;; do anything for this br_if. However, due to our general handling of
;; tuples the code here will grow quite a bit due the roundtrip, but we can
;; at least verify that there is no ref.cast added anywhere here.
(block $out (result (ref $A) i32)
(tuple.drop 2
(br_if $out
(tuple.make 2
(local.get $B)
(i32.const 3)
)
(local.get $x)
)
)
(unreachable)
)
)
;; CHECK: (func $test-local-tuple-2 (type $9) (param $B (ref $B)) (param $x i32) (result i32 i32)
;; CHECK-NEXT: (local $temp i32)
;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (local $4 (tuple i32 i32))
;; CHECK-NEXT: (local $5 i32)
;; CHECK-NEXT: (local $6 (tuple i32 i32))
;; CHECK-NEXT: (local.set $6
;; CHECK-NEXT: (block $label$1 (type $4) (result i32 i32)
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (br_if $label$1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (i32.const -1)
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $temp
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (local.set $5
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $5)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test-local-tuple-2 (param $B (ref $B)) (param $x i32) (result i32 i32)
(local $temp (tuple i32 i32))
;; This tuple is not dropped, but it contains no references, so we do not
;; need to do anything for the br_if, and we add no casts.
(block $out (result i32 i32)
(local.set $temp
(br_if $out
(tuple.make 2
(i32.const -1)
(i32.const 3)
)
(local.get $x)
)
)
(unreachable)
)
)
;; CHECK: (func $test-local-tuple-3 (type $5) (param $B (ref $B)) (param $x i32) (result anyref i32)
;; CHECK-NEXT: (local $temp (ref $B))
;; CHECK-NEXT: (local $3 i32)
;; CHECK-NEXT: (local $4 (tuple (ref $B) i32))
;; CHECK-NEXT: (local $5 (ref $B))
;; CHECK-NEXT: (local $6 (tuple (ref $B) i32))
;; CHECK-NEXT: (local.set $6
;; CHECK-NEXT: (block $label$1 (type $6) (result (ref $B) i32)
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (br_if $label$1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $temp
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $5
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $5)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test-local-tuple-3 (param $B (ref $B)) (param $x i32) (result anyref i32)
(local $temp (tuple (ref $B) i32))
;; This is not dropped and has a reference, but it has the right type, so no
;; cast is needed.
(block $out (result (ref $B) i32)
(local.set $temp
(br_if $out
(tuple.make 2
(local.get $B)
(i32.const 3)
)
(local.get $x)
)
)
(unreachable)
)
)
;; CHECK: (func $test-local-tuple-4-bad (type $5) (param $B (ref $B)) (param $x i32) (result anyref i32)
;; CHECK-NEXT: (local $temp (ref $B))
;; CHECK-NEXT: (local $3 (ref $A))
;; CHECK-NEXT: (local $4 i32)
;; CHECK-NEXT: (local $5 i32)
;; CHECK-NEXT: (local $6 (tuple (ref $B) i32))
;; CHECK-NEXT: (local $7 (ref $B))
;; CHECK-NEXT: (local $8 (ref $B))
;; CHECK-NEXT: (local $9 (tuple (ref $A) i32))
;; CHECK-NEXT: (local.set $9
;; CHECK-NEXT: (block $label$1 (type $3) (result (ref $A) i32)
;; CHECK-NEXT: (local.set $6
;; CHECK-NEXT: (br_if $label$1
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $7
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $5
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $6)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $7)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $temp
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $8
;; CHECK-NEXT: (ref.cast (ref $B)
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (local.get $5)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $8)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $9)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $9)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test-local-tuple-4-bad (param $B (ref $B)) (param $x i32) (result anyref i32)
(local $temp (tuple (ref $B) i32))
;; As above, but none of the mitigating circumstances happens: we have a
;; tuple with a reference that is refined compared to the break target. As a
;; result we must fix this up, which we do by adding locals, saving the
;; br_if's output to them, and then loading from those locals and casting.
;;
;; Comparing to $test-local-tuple-4, we end up with 3 more locals, and also
;; there is now a ref.cast.
(block $out (result (ref $A) i32)
(local.set $temp
(br_if $out
(tuple.make 2
(local.get $B)
(i32.const 3)
)
(local.get $x)
)
)
(unreachable)
)
)
;; CHECK: (func $test-local-tuple-4-bad-dupes (type $10) (param $B (ref $B)) (param $x i32) (result i32 anyref i32)
;; CHECK-NEXT: (local $temp (ref $B))
;; CHECK-NEXT: (local $3 (ref $B))
;; CHECK-NEXT: (local $4 (ref $A))
;; CHECK-NEXT: (local $5 i32)
;; CHECK-NEXT: (local $scratch i32)
;; CHECK-NEXT: (local $7 i32)
;; CHECK-NEXT: (local $8 i32)
;; CHECK-NEXT: (local $9 i32)
;; CHECK-NEXT: (local $10 (tuple i32 (ref $B) i32))
;; CHECK-NEXT: (local $11 (ref $B))
;; CHECK-NEXT: (local $12 i32)
;; CHECK-NEXT: (local $13 (ref $B))
;; CHECK-NEXT: (local $14 i32)
;; CHECK-NEXT: (local $15 (ref $B))
;; CHECK-NEXT: (local $16 (tuple i32 (ref $A) i32))
;; CHECK-NEXT: (local.set $16
;; CHECK-NEXT: (block $label$1 (type $7) (result i32 (ref $A) i32)
;; CHECK-NEXT: (local.set $10
;; CHECK-NEXT: (br_if $label$1
;; CHECK-NEXT: (tuple.make 3
;; CHECK-NEXT: (i32.const -3)
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $9
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (local.set $12
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $4
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $11
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $8
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $10)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $11)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $12)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $scratch
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (local.set $14
;; CHECK-NEXT: (local.get $9)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $13
;; CHECK-NEXT: (ref.cast (ref $B)
;; CHECK-NEXT: (local.get $4)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $7
;; CHECK-NEXT: (local.get $8)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $13)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $14)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $temp
;; CHECK-NEXT: (block (result (ref $B))
;; CHECK-NEXT: (local.set $15
;; CHECK-NEXT: (local.get $3)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $5
;; CHECK-NEXT: (local.get $7)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $15)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 3
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $16)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $16)
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $16)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test-local-tuple-4-bad-dupes (param $B (ref $B)) (param $x i32) (result i32 anyref i32)
(local $temp (tuple (ref $B) i32))
;; As above, but now the tuple has multiple appearances of the same type in
;; it, each of which needs its own scratch local. We can see in the output
;; that the tuple.extracts use different locals for the first and last i32.
;; For easier reading, here is the wami output of the binary:
;;
;; (func $func4 (param $var0 (ref $type1)) (param $var1 i32) (result i32) (result anyref) (result i32)
;; (local $var2 (ref $type1))
;; (local $var3 (ref $type1))
;; (local $var4 (ref $type0))
;; (local $var5 i32)
;; (local $var6 i32)
;; (local $var7 i32)
;; (local $var8 i32)
;; (local $var9 i32)
;; block $label0 (result i32) (result (ref $type0)) (result i32)
;; i32.const -3
;; local.get $var0
;; i32.const 3
;; local.get $var1
;; br_if $label0
;; local.set $var8 ;; saves 3
;; local.set $var4 ;; saves the ref
;; local.set $var9 ;; saves -3
;; local.get $var9 ;; gets -3
;; local.get $var4 ;; gets the ref
;; ref.cast $type1 ;; casts the ref
;; local.get $var8 ;; gets 3
;; local.set $var7
;; local.set $var3
;; local.tee $var6
;; drop
;; local.get $var3
;; local.get $var7
;; local.set $var5
;; local.set $var2
;; unreachable
;; end $label0
;; )
;;
(block $out (result i32 (ref $A) i32)
(local.set $temp
(br_if $out
(tuple.make 3
(i32.const -3) ;; this was added
(local.get $B)
(i32.const 3)
)
(local.get $x)
)
)
(unreachable)
)
)
)