summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-07-18 13:40:20 -0700
committerGitHub <noreply@github.com>2024-07-18 13:40:20 -0700
commit7b1ef0c9023368fffd1b6eb6771cab3690295fef (patch)
treeabfafcc13a2c0ff18be3f9611466c9beb6983980
parenta744bec7bc744182822c6b86aa3159d08dea0b3c (diff)
downloadbinaryen-7b1ef0c9023368fffd1b6eb6771cab3690295fef.tar.gz
binaryen-7b1ef0c9023368fffd1b6eb6771cab3690295fef.tar.bz2
binaryen-7b1ef0c9023368fffd1b6eb6771cab3690295fef.zip
Monomorphization: Add a limit on the number of parameters (#6774)
-rw-r--r--src/passes/Monomorphize.cpp20
-rw-r--r--test/lit/passes/monomorphize-limits.wast400
2 files changed, 420 insertions, 0 deletions
diff --git a/src/passes/Monomorphize.cpp b/src/passes/Monomorphize.cpp
index 1fd81b9d1..f46e27d83 100644
--- a/src/passes/Monomorphize.cpp
+++ b/src/passes/Monomorphize.cpp
@@ -102,6 +102,7 @@
#include "ir/utils.h"
#include "pass.h"
#include "support/hash.h"
+#include "wasm-limits.h"
#include "wasm-type.h"
#include "wasm.h"
@@ -109,6 +110,15 @@ namespace wasm {
namespace {
+// A limit on the number of parameters we are willing to have on monomorphized
+// functions. Large numbers can lead to large stack frames, which can be slow
+// and lead to stack overflows.
+// TODO: Tune this and perhaps make it a flag.
+const Index MaxParams = 20;
+// This must be less than the corresponding Web limitation, so we do not emit
+// invalid binaries.
+static_assert(MaxParams < WebLimitations::MaxFunctionParams);
+
// Core information about a call: the call itself, and if it is dropped, the
// drop.
struct CallInfo {
@@ -628,6 +638,16 @@ struct Monomorphize : public Pass {
std::unique_ptr<Function> monoFunc =
makeMonoFunctionWithContext(func, context, wasm);
+ // If we ended up with too many params, give up. In theory we could try to
+ // monomorphize in ways that use less params, but this is a rare situation
+ // that is not easy to handle (when we move something into the context, it
+ // *removes* a param, which is good, but if it has many children and end up
+ // not moved, that is where the problem happens, so we'd need to backtrack).
+ // TODO: Consider doing more here.
+ if (monoFunc->getNumParams() >= MaxParams) {
+ return;
+ }
+
// Decide whether it is worth using the monomorphized function.
auto worthwhile = true;
if (onlyWhenHelpful) {
diff --git a/test/lit/passes/monomorphize-limits.wast b/test/lit/passes/monomorphize-limits.wast
new file mode 100644
index 000000000..7b3baee5e
--- /dev/null
+++ b/test/lit/passes/monomorphize-limits.wast
@@ -0,0 +1,400 @@
+;; 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
+ ;; ALWAYS: (type $0 (func))
+
+ ;; ALWAYS: (type $1 (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
+
+ ;; ALWAYS: (func $caller-consts (type $0)
+ ;; ALWAYS-NEXT: (call $many-params_3)
+ ;; ALWAYS-NEXT: )
+ ;; CAREFUL: (type $0 (func))
+
+ ;; CAREFUL: (type $1 (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
+
+ ;; CAREFUL: (func $caller-consts (type $0)
+ ;; CAREFUL-NEXT: (call $many-params_3)
+ ;; CAREFUL-NEXT: )
+ (func $caller-consts
+ ;; The called func has a large number of params, in fact too many for us to
+ ;; allow in monomorphized functions. However, all the params are constant,
+ ;; so they go into the call context and are no longer params, and we can
+ ;; optimize.
+ (call $many-params
+ (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0)
+ (i32.const 5) (i32.const 5) (i32.const 5) (i32.const 5) (i32.const 5)
+ (i32.const 15) (i32.const 15) (i32.const 15) (i32.const 15) (i32.const 15)
+ (i32.const 20) (i32.const 20) (i32.const 20) (i32.const 20) (i32.const 20)
+ (i32.const 25) (i32.const 25) (i32.const 25) (i32.const 25) (i32.const 25)
+ )
+ )
+
+ ;; ALWAYS: (func $caller-locals (type $1) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (param $7 i32) (param $8 i32) (param $9 i32) (param $10 i32) (param $11 i32) (param $12 i32) (param $13 i32) (param $14 i32) (param $15 i32) (param $16 i32) (param $17 i32) (param $18 i32) (param $19 i32) (param $20 i32) (param $21 i32) (param $22 i32) (param $23 i32) (param $24 i32)
+ ;; ALWAYS-NEXT: (call $many-params
+ ;; ALWAYS-NEXT: (local.get $0)
+ ;; ALWAYS-NEXT: (local.get $1)
+ ;; ALWAYS-NEXT: (local.get $2)
+ ;; ALWAYS-NEXT: (local.get $3)
+ ;; ALWAYS-NEXT: (local.get $4)
+ ;; ALWAYS-NEXT: (local.get $5)
+ ;; ALWAYS-NEXT: (local.get $6)
+ ;; ALWAYS-NEXT: (local.get $7)
+ ;; ALWAYS-NEXT: (local.get $8)
+ ;; ALWAYS-NEXT: (local.get $9)
+ ;; ALWAYS-NEXT: (local.get $10)
+ ;; ALWAYS-NEXT: (local.get $11)
+ ;; ALWAYS-NEXT: (local.get $12)
+ ;; ALWAYS-NEXT: (local.get $13)
+ ;; ALWAYS-NEXT: (local.get $14)
+ ;; ALWAYS-NEXT: (local.get $15)
+ ;; ALWAYS-NEXT: (local.get $16)
+ ;; ALWAYS-NEXT: (local.get $17)
+ ;; ALWAYS-NEXT: (local.get $18)
+ ;; ALWAYS-NEXT: (local.get $19)
+ ;; ALWAYS-NEXT: (local.get $20)
+ ;; ALWAYS-NEXT: (local.get $21)
+ ;; ALWAYS-NEXT: (local.get $22)
+ ;; ALWAYS-NEXT: (local.get $23)
+ ;; ALWAYS-NEXT: (local.get $24)
+ ;; ALWAYS-NEXT: )
+ ;; ALWAYS-NEXT: )
+ ;; CAREFUL: (func $caller-locals (type $1) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (param $7 i32) (param $8 i32) (param $9 i32) (param $10 i32) (param $11 i32) (param $12 i32) (param $13 i32) (param $14 i32) (param $15 i32) (param $16 i32) (param $17 i32) (param $18 i32) (param $19 i32) (param $20 i32) (param $21 i32) (param $22 i32) (param $23 i32) (param $24 i32)
+ ;; CAREFUL-NEXT: (call $many-params
+ ;; CAREFUL-NEXT: (local.get $0)
+ ;; CAREFUL-NEXT: (local.get $1)
+ ;; CAREFUL-NEXT: (local.get $2)
+ ;; CAREFUL-NEXT: (local.get $3)
+ ;; CAREFUL-NEXT: (local.get $4)
+ ;; CAREFUL-NEXT: (local.get $5)
+ ;; CAREFUL-NEXT: (local.get $6)
+ ;; CAREFUL-NEXT: (local.get $7)
+ ;; CAREFUL-NEXT: (local.get $8)
+ ;; CAREFUL-NEXT: (local.get $9)
+ ;; CAREFUL-NEXT: (local.get $10)
+ ;; CAREFUL-NEXT: (local.get $11)
+ ;; CAREFUL-NEXT: (local.get $12)
+ ;; CAREFUL-NEXT: (local.get $13)
+ ;; CAREFUL-NEXT: (local.get $14)
+ ;; CAREFUL-NEXT: (local.get $15)
+ ;; CAREFUL-NEXT: (local.get $16)
+ ;; CAREFUL-NEXT: (local.get $17)
+ ;; CAREFUL-NEXT: (local.get $18)
+ ;; CAREFUL-NEXT: (local.get $19)
+ ;; CAREFUL-NEXT: (local.get $20)
+ ;; CAREFUL-NEXT: (local.get $21)
+ ;; CAREFUL-NEXT: (local.get $22)
+ ;; CAREFUL-NEXT: (local.get $23)
+ ;; CAREFUL-NEXT: (local.get $24)
+ ;; CAREFUL-NEXT: )
+ ;; CAREFUL-NEXT: )
+ (func $caller-locals
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ ;; As above, but now we send unknown local values. These would remain as
+ ;; parameters, so we do not optimize.
+ (call $many-params
+ (local.get 0) (local.get 1) (local.get 2) (local.get 3) (local.get 4)
+ (local.get 5) (local.get 6) (local.get 7) (local.get 8) (local.get 9)
+ (local.get 10) (local.get 11) (local.get 12) (local.get 13) (local.get 14)
+ (local.get 15) (local.get 16) (local.get 17) (local.get 18) (local.get 19)
+ (local.get 20) (local.get 21) (local.get 22) (local.get 23) (local.get 24)
+ )
+ )
+
+ ;; ALWAYS: (func $many-params (type $1) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (param $7 i32) (param $8 i32) (param $9 i32) (param $10 i32) (param $11 i32) (param $12 i32) (param $13 i32) (param $14 i32) (param $15 i32) (param $16 i32) (param $17 i32) (param $18 i32) (param $19 i32) (param $20 i32) (param $21 i32) (param $22 i32) (param $23 i32) (param $24 i32)
+ ;; ALWAYS-NEXT: (nop)
+ ;; ALWAYS-NEXT: )
+ ;; CAREFUL: (func $many-params (type $1) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (param $7 i32) (param $8 i32) (param $9 i32) (param $10 i32) (param $11 i32) (param $12 i32) (param $13 i32) (param $14 i32) (param $15 i32) (param $16 i32) (param $17 i32) (param $18 i32) (param $19 i32) (param $20 i32) (param $21 i32) (param $22 i32) (param $23 i32) (param $24 i32)
+ ;; CAREFUL-NEXT: (nop)
+ ;; CAREFUL-NEXT: )
+ (func $many-params
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ )
+)
+
+;; ALWAYS: (func $many-params_3 (type $0)
+;; ALWAYS-NEXT: (local $0 i32)
+;; ALWAYS-NEXT: (local $1 i32)
+;; ALWAYS-NEXT: (local $2 i32)
+;; ALWAYS-NEXT: (local $3 i32)
+;; ALWAYS-NEXT: (local $4 i32)
+;; ALWAYS-NEXT: (local $5 i32)
+;; ALWAYS-NEXT: (local $6 i32)
+;; ALWAYS-NEXT: (local $7 i32)
+;; ALWAYS-NEXT: (local $8 i32)
+;; ALWAYS-NEXT: (local $9 i32)
+;; ALWAYS-NEXT: (local $10 i32)
+;; ALWAYS-NEXT: (local $11 i32)
+;; ALWAYS-NEXT: (local $12 i32)
+;; ALWAYS-NEXT: (local $13 i32)
+;; ALWAYS-NEXT: (local $14 i32)
+;; ALWAYS-NEXT: (local $15 i32)
+;; ALWAYS-NEXT: (local $16 i32)
+;; ALWAYS-NEXT: (local $17 i32)
+;; ALWAYS-NEXT: (local $18 i32)
+;; ALWAYS-NEXT: (local $19 i32)
+;; ALWAYS-NEXT: (local $20 i32)
+;; ALWAYS-NEXT: (local $21 i32)
+;; ALWAYS-NEXT: (local $22 i32)
+;; ALWAYS-NEXT: (local $23 i32)
+;; ALWAYS-NEXT: (local $24 i32)
+;; ALWAYS-NEXT: (local.set $0
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $1
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $2
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $3
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $4
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $5
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $6
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $7
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $8
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $9
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $10
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $11
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $12
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $13
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $14
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $15
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $16
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $17
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $18
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $19
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $20
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $21
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $22
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $23
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (local.set $24
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (nop)
+;; ALWAYS-NEXT: )
+
+;; CAREFUL: (func $many-params_3 (type $0)
+;; CAREFUL-NEXT: (nop)
+;; CAREFUL-NEXT: )
+(module
+ ;; ALWAYS: (type $array (array (mut i32)))
+ ;; CAREFUL: (type $0 (func))
+
+ ;; CAREFUL: (type $array (array (mut i32)))
+ (type $array (array (mut i32)))
+
+ ;; ALWAYS: (type $1 (func))
+
+ ;; ALWAYS: (type $2 (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
+
+ ;; ALWAYS: (type $3 (func (param (ref $array))))
+
+ ;; ALWAYS: (func $caller-consts (type $1)
+ ;; ALWAYS-NEXT: (call $target_3)
+ ;; ALWAYS-NEXT: )
+ ;; CAREFUL: (type $2 (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
+
+ ;; CAREFUL: (type $3 (func (param (ref $array))))
+
+ ;; CAREFUL: (func $caller-consts (type $0)
+ ;; CAREFUL-NEXT: (call $target_3)
+ ;; CAREFUL-NEXT: )
+ (func $caller-consts
+ ;; The called function has just one param, but the value sent has many
+ ;; children of its own. Here the children are constant, so they go into the
+ ;; call context, and we can optimize.
+ (call $target
+ (array.new_fixed $array 25
+ (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0)
+ (i32.const 5) (i32.const 5) (i32.const 5) (i32.const 5) (i32.const 5)
+ (i32.const 15) (i32.const 15) (i32.const 15) (i32.const 15) (i32.const 15)
+ (i32.const 20) (i32.const 20) (i32.const 20) (i32.const 20) (i32.const 20)
+ (i32.const 25) (i32.const 25) (i32.const 25) (i32.const 25) (i32.const 25)
+ )
+ )
+ )
+
+ ;; ALWAYS: (func $caller-locals (type $2) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (param $7 i32) (param $8 i32) (param $9 i32) (param $10 i32) (param $11 i32) (param $12 i32) (param $13 i32) (param $14 i32) (param $15 i32) (param $16 i32) (param $17 i32) (param $18 i32) (param $19 i32) (param $20 i32) (param $21 i32) (param $22 i32) (param $23 i32) (param $24 i32)
+ ;; ALWAYS-NEXT: (call $target
+ ;; ALWAYS-NEXT: (array.new_fixed $array 25
+ ;; ALWAYS-NEXT: (local.get $0)
+ ;; ALWAYS-NEXT: (local.get $1)
+ ;; ALWAYS-NEXT: (local.get $2)
+ ;; ALWAYS-NEXT: (local.get $3)
+ ;; ALWAYS-NEXT: (local.get $4)
+ ;; ALWAYS-NEXT: (local.get $5)
+ ;; ALWAYS-NEXT: (local.get $6)
+ ;; ALWAYS-NEXT: (local.get $7)
+ ;; ALWAYS-NEXT: (local.get $8)
+ ;; ALWAYS-NEXT: (local.get $9)
+ ;; ALWAYS-NEXT: (local.get $10)
+ ;; ALWAYS-NEXT: (local.get $11)
+ ;; ALWAYS-NEXT: (local.get $12)
+ ;; ALWAYS-NEXT: (local.get $13)
+ ;; ALWAYS-NEXT: (local.get $14)
+ ;; ALWAYS-NEXT: (local.get $15)
+ ;; ALWAYS-NEXT: (local.get $16)
+ ;; ALWAYS-NEXT: (local.get $17)
+ ;; ALWAYS-NEXT: (local.get $18)
+ ;; ALWAYS-NEXT: (local.get $19)
+ ;; ALWAYS-NEXT: (local.get $20)
+ ;; ALWAYS-NEXT: (local.get $21)
+ ;; ALWAYS-NEXT: (local.get $22)
+ ;; ALWAYS-NEXT: (local.get $23)
+ ;; ALWAYS-NEXT: (local.get $24)
+ ;; ALWAYS-NEXT: )
+ ;; ALWAYS-NEXT: )
+ ;; ALWAYS-NEXT: )
+ ;; CAREFUL: (func $caller-locals (type $2) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (param $4 i32) (param $5 i32) (param $6 i32) (param $7 i32) (param $8 i32) (param $9 i32) (param $10 i32) (param $11 i32) (param $12 i32) (param $13 i32) (param $14 i32) (param $15 i32) (param $16 i32) (param $17 i32) (param $18 i32) (param $19 i32) (param $20 i32) (param $21 i32) (param $22 i32) (param $23 i32) (param $24 i32)
+ ;; CAREFUL-NEXT: (call $target
+ ;; CAREFUL-NEXT: (array.new_fixed $array 25
+ ;; CAREFUL-NEXT: (local.get $0)
+ ;; CAREFUL-NEXT: (local.get $1)
+ ;; CAREFUL-NEXT: (local.get $2)
+ ;; CAREFUL-NEXT: (local.get $3)
+ ;; CAREFUL-NEXT: (local.get $4)
+ ;; CAREFUL-NEXT: (local.get $5)
+ ;; CAREFUL-NEXT: (local.get $6)
+ ;; CAREFUL-NEXT: (local.get $7)
+ ;; CAREFUL-NEXT: (local.get $8)
+ ;; CAREFUL-NEXT: (local.get $9)
+ ;; CAREFUL-NEXT: (local.get $10)
+ ;; CAREFUL-NEXT: (local.get $11)
+ ;; CAREFUL-NEXT: (local.get $12)
+ ;; CAREFUL-NEXT: (local.get $13)
+ ;; CAREFUL-NEXT: (local.get $14)
+ ;; CAREFUL-NEXT: (local.get $15)
+ ;; CAREFUL-NEXT: (local.get $16)
+ ;; CAREFUL-NEXT: (local.get $17)
+ ;; CAREFUL-NEXT: (local.get $18)
+ ;; CAREFUL-NEXT: (local.get $19)
+ ;; CAREFUL-NEXT: (local.get $20)
+ ;; CAREFUL-NEXT: (local.get $21)
+ ;; CAREFUL-NEXT: (local.get $22)
+ ;; CAREFUL-NEXT: (local.get $23)
+ ;; CAREFUL-NEXT: (local.get $24)
+ ;; CAREFUL-NEXT: )
+ ;; CAREFUL-NEXT: )
+ ;; CAREFUL-NEXT: )
+ (func $caller-locals
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ (param i32) (param i32) (param i32) (param i32) (param i32)
+ ;; As above, but now we send unknown local values in the nested child. Those
+ ;; would remain as parameters, so we do not optimize.
+ (call $target
+ (array.new_fixed $array 25
+ (local.get 0) (local.get 1) (local.get 2) (local.get 3) (local.get 4)
+ (local.get 5) (local.get 6) (local.get 7) (local.get 8) (local.get 9)
+ (local.get 10) (local.get 11) (local.get 12) (local.get 13) (local.get 14)
+ (local.get 15) (local.get 16) (local.get 17) (local.get 18) (local.get 19)
+ (local.get 20) (local.get 21) (local.get 22) (local.get 23) (local.get 24)
+ )
+ )
+ )
+
+ ;; ALWAYS: (func $target (type $3) (param $array (ref $array))
+ ;; ALWAYS-NEXT: (nop)
+ ;; ALWAYS-NEXT: )
+ ;; CAREFUL: (func $target (type $3) (param $0 (ref $array))
+ ;; CAREFUL-NEXT: (nop)
+ ;; CAREFUL-NEXT: )
+ (func $target (param $array (ref $array))
+ )
+)
+;; ALWAYS: (func $target_3 (type $1)
+;; ALWAYS-NEXT: (local $array (ref $array))
+;; ALWAYS-NEXT: (local.set $array
+;; ALWAYS-NEXT: (array.new_fixed $array 25
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: (i32.const 0)
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: (i32.const 5)
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: (i32.const 15)
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: (i32.const 20)
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: (i32.const 25)
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: )
+;; ALWAYS-NEXT: (nop)
+;; ALWAYS-NEXT: )
+
+;; CAREFUL: (func $target_3 (type $0)
+;; CAREFUL-NEXT: (nop)
+;; CAREFUL-NEXT: )