| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. | |
| ;; RUN: wasm-opt %s -all --optimize-level=3 --generate-stack-ir --optimize-stack-ir --print-stack-ir | filecheck %s | |
| ;; Also test with roundtrip to verify that parsing does not undo this | |
| ;; optimization. | |
| ;; RUN: wasm-opt %s -all --optimize-level=3 --generate-stack-ir --optimize-stack-ir --roundtrip --print-stack-ir | filecheck %s --check-prefix=ROUNDTRIP | |
| (module | |
| ;; CHECK: (type $0 (func (result i32 f64 anyref))) | |
| ;; CHECK: (type $1 (func (param f64) (result i32 f64 anyref))) | |
| ;; CHECK: (type $2 (func (param i32 f64 anyref))) | |
| ;; CHECK: (type $3 (func (result i32 f64))) | |
| ;; CHECK: (type $4 (func (result i32 f64 anyref eqref))) | |
| ;; CHECK: (type $5 (func (result i32 f64 anyref anyref))) | |
| ;; CHECK: (type $6 (func (param f64) (result i32 anyref anyref))) | |
| ;; CHECK: (func $multivalue-return (type $0) (result i32 f64 anyref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: tuple.make 3 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (type $0 (func (result i32 f64 anyref))) | |
| ;; ROUNDTRIP: (type $1 (func (param f64) (result i32 f64 anyref))) | |
| ;; ROUNDTRIP: (type $2 (func (param i32 f64 anyref))) | |
| ;; ROUNDTRIP: (type $3 (func (result i32 f64))) | |
| ;; ROUNDTRIP: (type $4 (func (result i32 f64 anyref eqref))) | |
| ;; ROUNDTRIP: (type $5 (func (result i32 f64 anyref anyref))) | |
| ;; ROUNDTRIP: (type $6 (func (param f64) (result i32 anyref anyref))) | |
| ;; ROUNDTRIP: (func $multivalue-return (type $0) (result i32 f64 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $1 f64) | |
| ;; ROUNDTRIP-NEXT: (local $2 anyref) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return (result i32 f64 anyref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; We can remove all these tuple operations after optiming and | |
| ;; roundtripping (though a few locals will be added in roundtripping FIXME). | |
| (tuple.make 3 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-too-short (type $3) (result i32 f64) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 1 | |
| ;; CHECK-NEXT: tuple.make 2 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-too-short (type $3) (result i32 f64) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $1 f64) | |
| ;; ROUNDTRIP-NEXT: (local $2 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_4 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_5 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $2 | |
| ;; ROUNDTRIP-NEXT: local.set $1 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp | |
| ;; ROUNDTRIP-NEXT: local.get $1 | |
| ;; ROUNDTRIP-NEXT: tuple.make 2 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-too-short (result i32 f64) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As above, but we only return 2 of the tuple's 3 items (i.e., we are too | |
| ;; short to fit the pattern), so we do not optimize here. | |
| (tuple.make 2 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-extra (type $4) (result i32 f64 anyref eqref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: ref.null none | |
| ;; CHECK-NEXT: tuple.make 4 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-extra (type $4) (result i32 f64 anyref eqref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $1 f64) | |
| ;; ROUNDTRIP-NEXT: (local $2 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: ref.null none | |
| ;; ROUNDTRIP-NEXT: tuple.make 4 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-extra (result i32 f64 anyref eqref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As above, but we add an item to the tuple. We can optimize here. | |
| (tuple.make 4 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| (ref.null eq) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-extra-middle (type $5) (result i32 f64 anyref anyref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 1 | |
| ;; CHECK-NEXT: ref.null none | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: tuple.make 4 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-extra-middle (type $5) (result i32 f64 anyref anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $1 f64) | |
| ;; ROUNDTRIP-NEXT: (local $2 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_4 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_5 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $2 | |
| ;; ROUNDTRIP-NEXT: local.set $1 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp | |
| ;; ROUNDTRIP-NEXT: local.get $1 | |
| ;; ROUNDTRIP-NEXT: ref.null none | |
| ;; ROUNDTRIP-NEXT: local.get $2 | |
| ;; ROUNDTRIP-NEXT: tuple.make 4 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-extra-middle (result i32 f64 anyref anyref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As the last case, but the extra item is in the middle. We cannot | |
| ;; optimize. | |
| (tuple.make 4 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp) | |
| ) | |
| (ref.null eq) | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-bad-get (type $1) (param $other f64) (result i32 f64 anyref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $other | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: tuple.make 3 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-bad-get (type $1) (param $other f64) (result i32 f64 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $2 f64) | |
| ;; ROUNDTRIP-NEXT: (local $3 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_5 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_6 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $3 | |
| ;; ROUNDTRIP-NEXT: local.set $2 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp | |
| ;; ROUNDTRIP-NEXT: local.get $other | |
| ;; ROUNDTRIP-NEXT: local.get $3 | |
| ;; ROUNDTRIP-NEXT: tuple.make 3 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-bad-get (param $other f64) (result i32 f64 anyref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As the first case, but one get has the wrong index, so we do | |
| ;; not optimize. | |
| (tuple.make 3 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (local.get $other) ;; this changed | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-non-get (type $0) (result i32 f64 anyref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 1 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: tuple.make 3 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-non-get (type $0) (result i32 f64 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $1 f64) | |
| ;; ROUNDTRIP-NEXT: (local $2 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_4 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_5 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $2 | |
| ;; ROUNDTRIP-NEXT: local.set $1 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp | |
| ;; ROUNDTRIP-NEXT: local.get $1 | |
| ;; ROUNDTRIP-NEXT: local.get $2 | |
| ;; ROUNDTRIP-NEXT: tuple.make 3 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-non-get (result i32 f64 anyref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As the first case, but one get is replaced by a non-get, so we do | |
| ;; not optimize. | |
| (tuple.make 3 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (nop) ;; this breaks the pattern, appearing where the get | |
| ;; should be | |
| (local.get $temp) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-bad-extract (type $6) (param $other f64) (result i32 anyref anyref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: tuple.make 3 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-bad-extract (type $6) (param $other f64) (result i32 anyref anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $2 f64) | |
| ;; ROUNDTRIP-NEXT: (local $3 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_5 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_6 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $3 | |
| ;; ROUNDTRIP-NEXT: local.set $2 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp | |
| ;; ROUNDTRIP-NEXT: local.get $3 | |
| ;; ROUNDTRIP-NEXT: local.get $3 | |
| ;; ROUNDTRIP-NEXT: tuple.make 3 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-bad-extract (param $other f64) (result i32 anyref anyref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As the first case, but one extract has the wrong index, so we | |
| ;; do not optimize. | |
| (tuple.make 3 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 2 ;; this changed from 1 to 2 | |
| (local.get $temp) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multivalue-return-non-extract (type $1) (param $other f64) (result i32 f64 anyref) | |
| ;; CHECK-NEXT: (local $temp (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: local.set $scratch | |
| ;; CHECK-NEXT: local.get $scratch | |
| ;; CHECK-NEXT: tuple.extract 3 1 | |
| ;; CHECK-NEXT: local.get $temp | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: tuple.make 3 | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multivalue-return-non-extract (type $1) (param $other f64) (result i32 f64 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp i32) | |
| ;; ROUNDTRIP-NEXT: (local $scratch i32) | |
| ;; ROUNDTRIP-NEXT: (local $3 f64) | |
| ;; ROUNDTRIP-NEXT: (local $4 f64) | |
| ;; ROUNDTRIP-NEXT: (local $5 f64) | |
| ;; ROUNDTRIP-NEXT: (local $6 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $7 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_8 (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_9 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_10 i32) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_11 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_12 i32) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_13 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_14 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch_8 | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch_8 | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch_8 | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $6 | |
| ;; ROUNDTRIP-NEXT: local.set $3 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp | |
| ;; ROUNDTRIP-NEXT: local.get $temp | |
| ;; ROUNDTRIP-NEXT: local.get $3 | |
| ;; ROUNDTRIP-NEXT: local.get $6 | |
| ;; ROUNDTRIP-NEXT: local.set $7 | |
| ;; ROUNDTRIP-NEXT: local.set $4 | |
| ;; ROUNDTRIP-NEXT: local.get $4 | |
| ;; ROUNDTRIP-NEXT: local.get $7 | |
| ;; ROUNDTRIP-NEXT: drop | |
| ;; ROUNDTRIP-NEXT: local.set $5 | |
| ;; ROUNDTRIP-NEXT: drop | |
| ;; ROUNDTRIP-NEXT: local.get $5 | |
| ;; ROUNDTRIP-NEXT: local.get $6 | |
| ;; ROUNDTRIP-NEXT: tuple.make 3 | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multivalue-return-non-extract (param $other f64) (result i32 f64 anyref) | |
| (local $temp (tuple i32 f64 anyref)) | |
| ;; As the first case, but one extract is replaced with something else, so we | |
| ;; do not optimize. | |
| (tuple.make 3 | |
| (tuple.extract 3 0 | |
| (local.tee $temp | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp) | |
| (nop) ;; this breaks the pattern, appearing where the tuple.extract | |
| ;; should be | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multiple-multivalue-return (type $2) (param $0 i32) (param $1 f64) (param $2 anyref) | |
| ;; CHECK-NEXT: (local $temp3 (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: (local $temp2 (tuple i32 f64)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: call $multiple-multivalue-return | |
| ;; CHECK-NEXT: call $multivalue-return-too-short | |
| ;; CHECK-NEXT: ref.null none | |
| ;; CHECK-NEXT: call $multiple-multivalue-return | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: call $multiple-multivalue-return | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multiple-multivalue-return (type $2) (param $0 i32) (param $1 f64) (param $2 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp3 i32) | |
| ;; ROUNDTRIP-NEXT: (local $temp2 i32) | |
| ;; ROUNDTRIP-NEXT: (local $5 f64) | |
| ;; ROUNDTRIP-NEXT: (local $6 f64) | |
| ;; ROUNDTRIP-NEXT: (local $7 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_9 (tuple i32 f64)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_10 (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: call $multiple-multivalue-return | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return-too-short | |
| ;; ROUNDTRIP-NEXT: ref.null none | |
| ;; ROUNDTRIP-NEXT: call $multiple-multivalue-return | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: call $multiple-multivalue-return | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multiple-multivalue-return (param i32 f64 anyref) | |
| (local $temp3 (tuple i32 f64 anyref)) | |
| (local $temp2 (tuple i32 f64)) | |
| ;; Multiple optimizations in one function, including a case where we reuse | |
| ;; the local index. | |
| (call $multiple-multivalue-return | |
| (tuple.extract 3 0 | |
| (local.tee $temp3 | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp3) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp3) | |
| ) | |
| ) | |
| (call $multiple-multivalue-return | |
| (tuple.extract 2 0 | |
| (local.tee $temp2 | |
| (call $multivalue-return-too-short) | |
| ) | |
| ) | |
| (tuple.extract 2 1 | |
| (local.get $temp2) | |
| ) | |
| (ref.null any) | |
| ) | |
| (call $multiple-multivalue-return | |
| (tuple.extract 3 0 | |
| (local.tee $temp3 | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp3) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp3) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $multiple-multivalue-return-local-reuse (type $2) (param $0 i32) (param $1 f64) (param $2 anyref) | |
| ;; CHECK-NEXT: (local $temp3 (tuple i32 f64 anyref)) | |
| ;; CHECK-NEXT: (local $temp2 (tuple i32 f64)) | |
| ;; CHECK-NEXT: call $multivalue-return | |
| ;; CHECK-NEXT: local.tee $temp3 | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp3 | |
| ;; CHECK-NEXT: tuple.extract 3 1 | |
| ;; CHECK-NEXT: local.get $temp3 | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: call $multiple-multivalue-return | |
| ;; CHECK-NEXT: local.get $temp3 | |
| ;; CHECK-NEXT: tuple.extract 3 0 | |
| ;; CHECK-NEXT: local.get $temp3 | |
| ;; CHECK-NEXT: tuple.extract 3 1 | |
| ;; CHECK-NEXT: local.get $temp3 | |
| ;; CHECK-NEXT: tuple.extract 3 2 | |
| ;; CHECK-NEXT: call $multiple-multivalue-return | |
| ;; CHECK-NEXT: ) | |
| ;; ROUNDTRIP: (func $multiple-multivalue-return-local-reuse (type $2) (param $0 i32) (param $1 f64) (param $2 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $temp3 i32) | |
| ;; ROUNDTRIP-NEXT: (local $temp2 i32) | |
| ;; ROUNDTRIP-NEXT: (local $5 f64) | |
| ;; ROUNDTRIP-NEXT: (local $6 f64) | |
| ;; ROUNDTRIP-NEXT: (local $7 anyref) | |
| ;; ROUNDTRIP-NEXT: (local $scratch (tuple i32 f64 anyref)) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_9 f64) | |
| ;; ROUNDTRIP-NEXT: (local $scratch_10 i32) | |
| ;; ROUNDTRIP-NEXT: call $multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.tee $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 0 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 1 | |
| ;; ROUNDTRIP-NEXT: local.get $scratch | |
| ;; ROUNDTRIP-NEXT: tuple.extract 3 2 | |
| ;; ROUNDTRIP-NEXT: local.set $7 | |
| ;; ROUNDTRIP-NEXT: local.set $5 | |
| ;; ROUNDTRIP-NEXT: local.tee $temp3 | |
| ;; ROUNDTRIP-NEXT: local.get $5 | |
| ;; ROUNDTRIP-NEXT: local.get $7 | |
| ;; ROUNDTRIP-NEXT: call $multiple-multivalue-return | |
| ;; ROUNDTRIP-NEXT: local.get $temp3 | |
| ;; ROUNDTRIP-NEXT: local.get $5 | |
| ;; ROUNDTRIP-NEXT: local.get $7 | |
| ;; ROUNDTRIP-NEXT: call $multiple-multivalue-return | |
| ;; ROUNDTRIP-NEXT: ) | |
| (func $multiple-multivalue-return-local-reuse (param i32 f64 anyref) | |
| (local $temp3 (tuple i32 f64 anyref)) | |
| (local $temp2 (tuple i32 f64)) | |
| ;; As the last case, we have two things to possibly optimize. Here we reuse | |
| ;; the tee'd value after the first one, which prevents any optimizations of | |
| ;; this pattern. | |
| (call $multiple-multivalue-return | |
| (tuple.extract 3 0 | |
| (local.tee $temp3 | |
| (call $multivalue-return) | |
| ) | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp3) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp3) | |
| ) | |
| ) | |
| (call $multiple-multivalue-return | |
| (tuple.extract 3 0 | |
| (local.get $temp3) ;; this changed | |
| ) | |
| (tuple.extract 3 1 | |
| (local.get $temp3) | |
| ) | |
| (tuple.extract 3 2 | |
| (local.get $temp3) | |
| ) | |
| ) | |
| ) | |
| ) |