diff options
author | Alon Zakai <azakai@google.com> | 2024-07-12 16:15:53 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-12 16:15:53 -0700 |
commit | d2a48afe09dd5b22079c748a97ebaebaf69a19a7 (patch) | |
tree | 4396b8e939bc85b4adced74aa6f6c20bce03e488 /test/lit/passes/monomorphize-drop.wast | |
parent | 20c10df0cc5e5ffb9b8a0ca8cf4895d3416c6771 (diff) | |
download | binaryen-d2a48afe09dd5b22079c748a97ebaebaf69a19a7.tar.gz binaryen-d2a48afe09dd5b22079c748a97ebaebaf69a19a7.tar.bz2 binaryen-d2a48afe09dd5b22079c748a97ebaebaf69a19a7.zip |
Monomorphize dropped functions (#6734)
We now consider a drop to be part of the call context: If we see
(drop
(call $foo)
)
(func $foo (result i32)
(i32.const 42)
)
Then we'd monomorphize to this:
(call $foo_1) ;; call the specialized function instead
(func $foo_1 ;; the specialized function returns nothing
(drop ;; the drop was moved into here
(i32.const 42)
)
)
With the drop now in the called function, we may be able to optimize out unused work.
Refactor a bit of code out of DAE that we can reuse here, into a new return-utils.h.
Diffstat (limited to 'test/lit/passes/monomorphize-drop.wast')
-rw-r--r-- | test/lit/passes/monomorphize-drop.wast | 1191 |
1 files changed, 1191 insertions, 0 deletions
diff --git a/test/lit/passes/monomorphize-drop.wast b/test/lit/passes/monomorphize-drop.wast new file mode 100644 index 000000000..63923f768 --- /dev/null +++ b/test/lit/passes/monomorphize-drop.wast @@ -0,0 +1,1191 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; As in monomorphize-types.wast, test in both "always" mode, which always +;; monomorphizes, and in "careful" mode which does it only when it appears to +;; actually help. + +;; RUN: foreach %s %t wasm-opt --monomorphize-always -all -S -o - | filecheck %s --check-prefix ALWAYS +;; RUN: foreach %s %t wasm-opt --monomorphize -all -S -o - | filecheck %s --check-prefix CAREFUL + +(module + ;; Test that dropped functions are monomorphized, and the drop is reverse- + ;; inlined into the called function, enabling more optimizations. + + ;; ALWAYS: (type $0 (func (result i32))) + + ;; ALWAYS: (type $1 (func (param i32))) + + ;; ALWAYS: (type $2 (func (param i32 i32) (result i32))) + + ;; ALWAYS: (type $3 (func (param i32) (result i32))) + + ;; ALWAYS: (type $4 (func)) + + ;; ALWAYS: (type $5 (func (param i32 i32))) + + ;; ALWAYS: (func $work (type $2) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS-NEXT: (i32.mul + ;; ALWAYS-NEXT: (i32.xor + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.div_s + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (type $0 (func (result i32))) + + ;; CAREFUL: (type $1 (func (param i32))) + + ;; CAREFUL: (type $2 (func (param i32 i32) (result i32))) + + ;; CAREFUL: (type $3 (func (param i32) (result i32))) + + ;; CAREFUL: (type $4 (func)) + + ;; CAREFUL: (type $5 (func (param i32 i32))) + + ;; CAREFUL: (func $work (type $2) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL-NEXT: (i32.mul + ;; CAREFUL-NEXT: (i32.div_s + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.xor + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $work (param $x i32) (param $y i32) (result i32) + ;; Do some nontrivial work that we return. If this is dropped then we don't + ;; need that work. + (i32.mul + (i32.xor + (local.get $x) + (local.get $y) + ) + (i32.div_s + (local.get $x) + (local.get $y) + ) + ) + ) + + ;; ALWAYS: (func $calls (type $1) (param $x i32) + ;; ALWAYS-NEXT: (call $work_5) + ;; ALWAYS-NEXT: (call $work_5) + ;; ALWAYS-NEXT: (call $work_6 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (call $work_7 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $calls (type $1) (param $x i32) + ;; CAREFUL-NEXT: (call $work_5) + ;; CAREFUL-NEXT: (call $work_5) + ;; CAREFUL-NEXT: (call $work_6 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (call $work_7 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $calls (param $x i32) + ;; Both of these can call the same monomorphized function. In CAREFUL mode + ;; that function's body can also be optimized into a nop. + (drop + (call $work + (i32.const 3) + (i32.const 4) + ) + ) + (drop + (call $work + (i32.const 3) + (i32.const 4) + ) + ) + ;; Another call, now with an unknown parameter. This calls a different + ;; monomorphized function, but once again the body can be optimized into a + ;; nop in CAREFUL. + (drop + (call $work + (i32.const 3) + (local.get $x) + ) + ) + ;; Two unknown parameters. Yet another monomorphized function, but the same + ;; outcome. + (drop + (call $work + (local.get $x) + (local.get $x) + ) + ) + ) + + ;; ALWAYS: (func $call-undropped-trivial (type $3) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (call $work + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-undropped-trivial (type $3) (param $x i32) (result i32) + ;; CAREFUL-NEXT: (call $work + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-undropped-trivial (param $x i32) (result i32) + ;; A call of the same target that is dropped in the previous function, but + ;; now without a drop. We know nothing nontrivial here, so we do nothing. + (call $work + (local.get $x) + (local.get $x) + ) + ) + + ;; ALWAYS: (func $call-undropped (type $0) (result i32) + ;; ALWAYS-NEXT: (call $work_8) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-undropped (type $0) (result i32) + ;; CAREFUL-NEXT: (call $work_8) + ;; CAREFUL-NEXT: ) + (func $call-undropped (result i32) + ;; As above but now with constant params. We can monomorphize here - there + ;; is no issue in optimizing here without a drop and with a drop elsewhere - + ;; but we do call a different function of course, that returns an i32. + (call $work + (i32.const 3) + (i32.const 4) + ) + ) + + ;; ALWAYS: (func $call-no-params-return (type $0) (result i32) + ;; ALWAYS-NEXT: (return_call $work + ;; ALWAYS-NEXT: (i32.const 10) + ;; ALWAYS-NEXT: (i32.const 20) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-no-params-return (type $0) (result i32) + ;; CAREFUL-NEXT: (return_call $work + ;; CAREFUL-NEXT: (i32.const 10) + ;; CAREFUL-NEXT: (i32.const 20) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-no-params-return (result i32) + ;; Return calls can be monomorphized too, but we have that as a TODO atm. + (return_call $work + (i32.const 10) + (i32.const 20) + ) + ) +) + +;; ALWAYS: (func $work_5 (type $4) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $work_6 (type $1) (param $0 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $work_7 (type $5) (param $0 i32) (param $1 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (local.get $1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $work_8 (type $0) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.mul +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $work_5 (type $4) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_6 (type $1) (param $0 i32) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (i32.div_s +;; CAREFUL-NEXT: (i32.const 3) +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_7 (type $5) (param $0 i32) (param $1 i32) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (i32.div_s +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: (local.get $1) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $work_8 (type $0) (result i32) +;; CAREFUL-NEXT: (i32.const 0) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $0 (func)) + + ;; ALWAYS: (type $1 (func (param i32 i32) (result i32))) + + ;; ALWAYS: (type $2 (func (result i32))) + + ;; ALWAYS: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) + ;; CAREFUL: (type $0 (func)) + + ;; CAREFUL: (type $1 (func (param i32 i32) (result i32))) + + ;; CAREFUL: (type $2 (func (result i32))) + + ;; CAREFUL: (import "a" "b" (func $import (type $1) (param i32 i32) (result i32))) + (import "a" "b" (func $import (param i32 i32) (result i32))) + + ;; ALWAYS: (func $no-params (type $2) (result i32) + ;; ALWAYS-NEXT: (i32.const 42) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $no-params (type $2) (result i32) + ;; CAREFUL-NEXT: (i32.const 42) + ;; CAREFUL-NEXT: ) + (func $no-params (result i32) + ;; A function that will be dropped, and has no params. + (i32.const 42) + ) + + ;; ALWAYS: (func $call-no-params (type $2) (result i32) + ;; ALWAYS-NEXT: (call $no-params_6) + ;; ALWAYS-NEXT: (call $no-params) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-no-params (type $2) (result i32) + ;; CAREFUL-NEXT: (call $no-params_6) + ;; CAREFUL-NEXT: (call $no-params) + ;; CAREFUL-NEXT: ) + (func $call-no-params (result i32) + ;; We can optimize the drop into the target. + (drop + (call $no-params) + ) + ;; Without a drop, the call context is trivial and we do nothing. + (call $no-params) + ) + + ;; ALWAYS: (func $call-import (type $0) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $import + ;; ALWAYS-NEXT: (i32.const 3) + ;; ALWAYS-NEXT: (i32.const 4) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-import (type $0) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $import + ;; CAREFUL-NEXT: (i32.const 3) + ;; CAREFUL-NEXT: (i32.const 4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-import + ;; Calling an import allows no optimizations. + (drop + (call $import + (i32.const 3) + (i32.const 4) + ) + ) + ) + + ;; ALWAYS: (func $import-work (type $1) (param $x i32) (param $y i32) (result i32) + ;; ALWAYS-NEXT: (call $import + ;; ALWAYS-NEXT: (i32.xor + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.div_s + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (local.get $y) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $import-work (type $1) (param $0 i32) (param $1 i32) (result i32) + ;; CAREFUL-NEXT: (call $import + ;; CAREFUL-NEXT: (i32.xor + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.div_s + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (local.get $1) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $import-work (param $x i32) (param $y i32) (result i32) + ;; Do some work and also call an import. + (call $import + (i32.xor + (local.get $x) + (local.get $y) + ) + (i32.div_s + (local.get $x) + (local.get $y) + ) + ) + ) + + ;; ALWAYS: (func $call-import-work (type $0) + ;; ALWAYS-NEXT: (call $import-work_7) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-import-work (type $0) + ;; CAREFUL-NEXT: (call $import-work_7) + ;; CAREFUL-NEXT: ) + (func $call-import-work + ;; This is monomorphized with the drop. + (drop + (call $import-work + (i32.const 3) + (i32.const 4) + ) + ) + ) +) + +;; ALWAYS: (func $no-params_6 (type $0) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 42) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $import-work_7 (type $0) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local $y i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 3) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (local.set $y +;; ALWAYS-NEXT: (i32.const 4) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (call $import +;; ALWAYS-NEXT: (i32.xor +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.div_s +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (local.get $y) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $no-params_6 (type $0) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $import-work_7 (type $0) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import +;; CAREFUL-NEXT: (i32.const 7) +;; CAREFUL-NEXT: (i32.const 0) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $0 (func (param i32))) + + ;; ALWAYS: (type $1 (func)) + + ;; ALWAYS: (type $2 (func (result i32))) + + ;; ALWAYS: (type $3 (func (param i32) (result i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $2) (result i32))) + ;; CAREFUL: (type $0 (func (param i32))) + + ;; CAREFUL: (type $1 (func)) + + ;; CAREFUL: (type $2 (func (result i32))) + + ;; CAREFUL: (type $3 (func (param i32) (result i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $2) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (func $return-normal (type $3) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (return + ;; ALWAYS-NEXT: (i32.const 0) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-normal (type $3) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (return + ;; CAREFUL-NEXT: (i32.const 0) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) + (func $return-normal (param $x i32) (result i32) + ;; This function has a return, which needs to be handled in the + ;; monomorphized function, as we'll no longer return a value. + (if + (local.get $x) + (then + (drop + (call $import) + ) + (return + (i32.const 0) + ) + ) + ) + ;; Also return a value by flowing it out. + (i32.const 1) + ) + + ;; ALWAYS: (func $call-return-normal (type $0) (param $x i32) + ;; ALWAYS-NEXT: (call $return-normal_3) + ;; ALWAYS-NEXT: (call $return-normal_4) + ;; ALWAYS-NEXT: (call $return-normal_5 + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-normal (type $0) (param $x i32) + ;; CAREFUL-NEXT: (call $return-normal_3) + ;; CAREFUL-NEXT: (call $return-normal_4) + ;; CAREFUL-NEXT: (call $return-normal_5 + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-return-normal (param $x i32) + ;; Call the above function with 0, 1, and an unknown value, to test the two + ;; code paths there + the case of the input being unknown. We monomorphize + ;; them all (differently). + (drop + (call $return-normal + (i32.const 0) + ) + ) + (drop + (call $return-normal + (i32.const 1) + ) + ) + (drop + (call $return-normal + (local.get $x) + ) + ) + ) +) + +;; ALWAYS: (func $return-normal_3 (type $1) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-normal_4 (type $1) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-normal_5 (type $0) (param $0 i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (local.get $0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block +;; ALWAYS-NEXT: (drop +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (return) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-normal_3 (type $1) +;; CAREFUL-NEXT: (nop) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-normal_4 (type $1) +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (block +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: (return) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-normal_5 (type $0) (param $0 i32) +;; CAREFUL-NEXT: (if +;; CAREFUL-NEXT: (local.get $0) +;; CAREFUL-NEXT: (then +;; CAREFUL-NEXT: (drop +;; CAREFUL-NEXT: (call $import) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $0 (func (result i32))) + + ;; ALWAYS: (type $1 (func (param i32) (result i32))) + + ;; ALWAYS: (type $2 (func (param i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $0) (result i32))) + ;; CAREFUL: (type $0 (func (result i32))) + + ;; CAREFUL: (type $1 (func (param i32) (result i32))) + + ;; CAREFUL: (type $2 (func (param i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $0) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (func $return-call (type $1) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-call (type $1) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) + (func $return-call (param $x i32) (result i32) + ;; As above, but now with a return_call. We do not monomorphize the drop + ;; part, as if we included the drop we'd turn the call into a non-return + ;; call, which can break things. + (if + (local.get $x) + (then + (return_call $import) + ) + ) + (i32.const 1) + ) + + ;; ALWAYS: (func $call-return-call (type $2) (param $x i32) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call_3) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call_4) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-call (type $2) (param $x i32) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call_3) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call_4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-return-call (param $x i32) + ;; As above, but due to the return call we won't monomorphize the drop. As + ;; a result we monomorphize the first two, leaving drops here, and do + ;; nothing for the last (as the call context is trivial). + (drop + (call $return-call + (i32.const 0) + ) + ) + (drop + (call $return-call + (i32.const 1) + ) + ) + (drop + (call $return-call + (local.get $x) + ) + ) + ) +) + +;; ALWAYS: (func $return-call_3 (type $0) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call_4 (type $0) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-call_3 (type $0) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call_4 (type $0) (result i32) +;; CAREFUL-NEXT: (return_call $import) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $i (func (result i32))) + ;; CAREFUL: (type $i (func (result i32))) + (type $i (func (result i32))) + + ;; ALWAYS: (type $1 (func (param i32) (result i32))) + + ;; ALWAYS: (type $2 (func (param i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $i) (result i32))) + ;; CAREFUL: (type $1 (func (param i32) (result i32))) + + ;; CAREFUL: (type $2 (func (param i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $i) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (table $table 10 10 funcref) + ;; CAREFUL: (table $table 10 10 funcref) + (table $table 10 10 funcref) + + ;; ALWAYS: (func $return-call-indirect (type $1) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) + ;; ALWAYS-NEXT: (call $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $return-call-indirect (type $1) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) + ;; CAREFUL-NEXT: (call $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) + (func $return-call-indirect (param $x i32) (result i32) + ;; As above, but now with a return_call_indirect. The outcome below is + ;; similar. + (if + (local.get $x) + (then + (return_call_indirect (type $i) + (call $import) + ) + ) + ) + (i32.const 1) + ) + + ;; ALWAYS: (func $call-return-call-indirect (type $2) (param $x i32) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-indirect_3) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-indirect_4) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-indirect + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-call-indirect (type $2) (param $x i32) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-indirect_3) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-indirect_4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-indirect + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + (func $call-return-call-indirect (param $x i32) + (drop + (call $return-call-indirect + (i32.const 0) + ) + ) + (drop + (call $return-call-indirect + (i32.const 1) + ) + ) + (drop + (call $return-call-indirect + (local.get $x) + ) + ) + ) +) + +;; ALWAYS: (func $return-call-indirect_3 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_indirect $table (type $i) +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-indirect_4 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_indirect $table (type $i) +;; ALWAYS-NEXT: (call $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-call-indirect_3 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-indirect_4 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call_indirect $table (type $i) +;; CAREFUL-NEXT: (call $import) +;; CAREFUL-NEXT: ) +;; CAREFUL-NEXT: ) +(module + ;; ALWAYS: (type $i (func (result i32))) + ;; CAREFUL: (type $i (func (result i32))) + (type $i (func (result i32))) + + ;; ALWAYS: (type $1 (func (param i32) (result i32))) + + ;; ALWAYS: (import "a" "c" (func $import (type $i) (result i32))) + ;; CAREFUL: (type $1 (func (param i32) (result i32))) + + ;; CAREFUL: (import "a" "c" (func $import (type $i) (result i32))) + (import "a" "c" (func $import (result i32))) + + ;; ALWAYS: (table $table 10 10 funcref) + ;; CAREFUL: (table $table 10 10 funcref) + (table $table 10 10 funcref) + + ;; ALWAYS: (elem declare func $import) + + ;; ALWAYS: (func $return-call-ref (type $1) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_ref $i + ;; ALWAYS-NEXT: (ref.func $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (i32.const 1) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (elem declare func $import) + + ;; CAREFUL: (func $return-call-ref (type $1) (param $0 i32) (result i32) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $0) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (i32.const 1) + ;; CAREFUL-NEXT: ) + (func $return-call-ref (param $x i32) (result i32) + ;; As above, but now with a return_call_ref. The outcome below is similar. + (if + (local.get $x) + (then + (return_call_ref $i + (ref.func $import) + ) + ) + ) + (i32.const 1) + ) + + ;; ALWAYS: (func $call-return-call-ref (type $1) (param $x i32) (result i32) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-ref_3) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-ref_4) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (drop + ;; ALWAYS-NEXT: (call $return-call-ref + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_indirect $table (type $i) + ;; ALWAYS-NEXT: (i32.const 7) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (if + ;; ALWAYS-NEXT: (local.get $x) + ;; ALWAYS-NEXT: (then + ;; ALWAYS-NEXT: (return_call_ref $i + ;; ALWAYS-NEXT: (ref.func $import) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: ) + ;; ALWAYS-NEXT: (unreachable) + ;; ALWAYS-NEXT: ) + ;; CAREFUL: (func $call-return-call-ref (type $1) (param $x i32) (result i32) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-ref_3) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-ref_4) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (drop + ;; CAREFUL-NEXT: (call $return-call-ref + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_indirect $table (type $i) + ;; CAREFUL-NEXT: (i32.const 7) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (if + ;; CAREFUL-NEXT: (local.get $x) + ;; CAREFUL-NEXT: (then + ;; CAREFUL-NEXT: (return_call_ref $i + ;; CAREFUL-NEXT: (ref.func $import) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: ) + ;; CAREFUL-NEXT: (unreachable) + ;; CAREFUL-NEXT: ) + (func $call-return-call-ref (param $x i32) (result i32) + ;; As before, a set of three calls (with similar outcomes as before: the + ;; first two are monomorphized without the drop; the last is unchanged). + (drop + (call $return-call-ref + (i32.const 0) + ) + ) + (drop + (call $return-call-ref + (i32.const 1) + ) + ) + (drop + (call $return-call-ref + (local.get $x) + ) + ) + + ;; Also add some return calls here, to show that it is fine for the caller + ;; to have them: we can still monomorphize some of the previous calls + ;; (without their drops). + (if + (local.get $x) + (then + (return_call $import) + ) + ) + (if + (local.get $x) + (then + (return_call_indirect (type $i) + (i32.const 7) + ) + ) + ) + (if + (local.get $x) + (then + (return_call_ref $i + (ref.func $import) + ) + ) + ) + (unreachable) + ) +) + +;; ALWAYS: (func $return-call-ref_3 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 0) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_ref $i +;; ALWAYS-NEXT: (ref.func $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; ALWAYS: (func $return-call-ref_4 (type $i) (result i32) +;; ALWAYS-NEXT: (local $x i32) +;; ALWAYS-NEXT: (local.set $x +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (block (result i32) +;; ALWAYS-NEXT: (if +;; ALWAYS-NEXT: (local.get $x) +;; ALWAYS-NEXT: (then +;; ALWAYS-NEXT: (return_call_ref $i +;; ALWAYS-NEXT: (ref.func $import) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: (i32.const 1) +;; ALWAYS-NEXT: ) +;; ALWAYS-NEXT: ) + +;; CAREFUL: (func $return-call-ref_3 (type $i) (result i32) +;; CAREFUL-NEXT: (i32.const 1) +;; CAREFUL-NEXT: ) + +;; CAREFUL: (func $return-call-ref_4 (type $i) (result i32) +;; CAREFUL-NEXT: (return_call $import) +;; CAREFUL-NEXT: ) |