diff options
Diffstat (limited to 'test/lit/cast-and-recast-tuple.wast')
-rw-r--r-- | test/lit/cast-and-recast-tuple.wast | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/test/lit/cast-and-recast-tuple.wast b/test/lit/cast-and-recast-tuple.wast new file mode 100644 index 000000000..7f0886fce --- /dev/null +++ b/test/lit/cast-and-recast-tuple.wast @@ -0,0 +1,444 @@ +;; 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) + ) + ) +) |