| ;; 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) |
| ) |
| ) |
| ) |
| ) |