summaryrefslogtreecommitdiff
path: root/test/lit/passes/monomorphize-drop.wast
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-07-12 16:15:53 -0700
committerGitHub <noreply@github.com>2024-07-12 16:15:53 -0700
commitd2a48afe09dd5b22079c748a97ebaebaf69a19a7 (patch)
tree4396b8e939bc85b4adced74aa6f6c20bce03e488 /test/lit/passes/monomorphize-drop.wast
parent20c10df0cc5e5ffb9b8a0ca8cf4895d3416c6771 (diff)
downloadbinaryen-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.wast1191
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: )