summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-12-06 15:25:16 -0800
committerGitHub <noreply@github.com>2023-12-06 15:25:16 -0800
commitf722171f73732c6852cc4d283cc006ca56142ebf (patch)
treefa0c80c4488c4fcde03e63772d1d057bf965ae8d
parent66277f9b767cb1b45ce12b77109c2538b6cb9c12 (diff)
downloadbinaryen-f722171f73732c6852cc4d283cc006ca56142ebf.tar.gz
binaryen-f722171f73732c6852cc4d283cc006ca56142ebf.tar.bz2
binaryen-f722171f73732c6852cc4d283cc006ca56142ebf.zip
Add no-inline IR annotation, and passes to set it based on function name (#6146)
Any function can now be annotated as not to be inlined fully (normally) or not to be inlined partially. In the future we'll want to read those annotations from the proposed wasm metadata section on code hints, and from wat text as well, but for now add trivial passes that set those fields based on function name wildcards, e.g.: --no-inline=*leave-alone* --inlining That will not inline any function whose name contains "leave-alone" in the name. --no-inline disables all inlining (full or partial) while --no-full-inline and --no-partial-inline affect only full or partial inlining.
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/Inlining.cpp22
-rw-r--r--src/passes/NoInline.cpp77
-rw-r--r--src/passes/pass.cpp7
-rw-r--r--src/passes/passes.h3
-rw-r--r--src/wasm.h6
-rw-r--r--test/lit/help/wasm-opt.test8
-rw-r--r--test/lit/help/wasm2js.test8
-rw-r--r--test/lit/passes/no-inline.wast925
9 files changed, 1049 insertions, 8 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index 53f52e23f..279c50983 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -70,6 +70,7 @@ set(passes_SOURCES
MultiMemoryLowering.cpp
NameList.cpp
NameTypes.cpp
+ NoInline.cpp
OnceReduction.cpp
OptimizeAddedConstants.cpp
OptimizeCasts.cpp
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index 20172d88d..e1e2dd022 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -686,8 +686,10 @@ struct FunctionSplitter {
auto outlinedFunctionSize = info.size - Measurer::measure(iff);
// If outlined function will be worth normal inline, skip the intermediate
- // state and inline fully now.
- if (outlinedFunctionWorthInlining(info, outlinedFunctionSize)) {
+ // state and inline fully now. Note that if full inlining is disabled we
+ // will not do this, and instead inline partially.
+ if (!func->noFullInline &&
+ outlinedFunctionWorthInlining(info, outlinedFunctionSize)) {
return InliningMode::Full;
}
@@ -771,10 +773,12 @@ struct FunctionSplitter {
// Success, this matches the pattern.
// If the outlined function will be worth inlining normally, skip the
- // intermediate state and inline fully now.
+ // intermediate state and inline fully now. (As above, if full inlining is
+ // disabled, we only partially inline.)
if (numIfs == 1) {
auto outlinedFunctionSize = Measurer::measure(iff->ifTrue);
- if (outlinedFunctionWorthInlining(info, outlinedFunctionSize)) {
+ if (!func->noFullInline &&
+ outlinedFunctionWorthInlining(info, outlinedFunctionSize)) {
return InliningMode::Full;
}
}
@@ -1197,7 +1201,9 @@ struct Inlining : public Pass {
// See explanation in doInlining() for the parameter nameHint.
Index inlinedNameHint = 0;
+ // Decide for a given function whether to inline, and if so in what mode.
InliningMode getInliningMode(Name name) {
+ auto* func = module->getFunction(name);
auto& info = infos[name];
if (info.inliningMode != InliningMode::Unknown) {
@@ -1205,19 +1211,19 @@ struct Inlining : public Pass {
}
// Check if the function itself is worth inlining as it is.
- if (info.worthFullInlining(getPassOptions())) {
- info.inliningMode = InliningMode::Full;
- return info.inliningMode;
+ if (!func->noFullInline && info.worthFullInlining(getPassOptions())) {
+ return info.inliningMode = InliningMode::Full;
}
// Otherwise, check if we can at least inline part of it, if we are
// interested in such things.
- if (functionSplitter) {
+ if (!func->noPartialInline && functionSplitter) {
info.inliningMode = functionSplitter->getSplitDrivenInliningMode(
module->getFunction(name), info);
return info.inliningMode;
}
+ // Cannot be fully or partially inlined => uninlineable.
info.inliningMode = InliningMode::Uninlineable;
return info.inliningMode;
}
diff --git a/src/passes/NoInline.cpp b/src/passes/NoInline.cpp
new file mode 100644
index 000000000..59e4f7e2c
--- /dev/null
+++ b/src/passes/NoInline.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Mark functions as no-inline based on name wildcards. For example:
+//
+// --no-inline=*leave-alone* --inlining
+//
+// That will mark all functions with names like "runtime-leave-alone-1234" as
+// no-inline, and as a result the inlining pass that happens afterwards will not
+// inline them.
+//
+// Note that this is itself a pass, which does work - it marks things in the
+// IR - and so the order of operations matters. If we did
+//
+// --inlining --no-inline=*leave-alone*
+//
+// then we'd first perform the inlining and then the marking, which would mean
+// the marking has no effect.
+//
+
+#include "pass.h"
+#include "support/string.h"
+#include "wasm.h"
+
+namespace wasm {
+
+namespace {
+
+enum NoInlineMode { Full = 0, Partial = 1, Both = 2 };
+
+struct NoInline : public Pass {
+ NoInlineMode mode;
+
+ NoInline(NoInlineMode mode) : mode(mode) {}
+
+ void run(Module* module) override {
+ std::string pattern = getPassOptions().getArgument(
+ name, "Usage usage: wasm-opt --" + name + "=WILDCARD");
+
+ for (auto& func : module->functions) {
+ if (!String::wildcardMatch(pattern, func->name.toString())) {
+ continue;
+ }
+
+ if (mode == Full || mode == Both) {
+ func->noFullInline = true;
+ }
+ if (mode == Partial || mode == Both) {
+ func->noPartialInline = true;
+ }
+ }
+ }
+};
+
+} // anonymous namespace
+
+Pass* createNoInlinePass() { return new NoInline(NoInlineMode::Both); }
+Pass* createNoFullInlinePass() { return new NoInline(NoInlineMode::Full); }
+Pass* createNoPartialInlinePass() {
+ return new NoInline(NoInlineMode::Partial);
+}
+
+} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 38b6c73a6..525248924 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -294,6 +294,13 @@ void PassRegistry::registerPasses() {
createMultiMemoryLoweringWithBoundsChecksPass);
registerPass("nm", "name list", createNameListPass);
registerPass("name-types", "(re)name all heap types", createNameTypesPass);
+ registerPass("no-inline", "mark functions as no-inline", createNoInlinePass);
+ registerPass("no-full-inline",
+ "mark functions as no-inline (for full inlining only)",
+ createNoFullInlinePass);
+ registerPass("no-partial-inline",
+ "mark functions as no-inline (for partial inlining only)",
+ createNoPartialInlinePass);
registerPass("once-reduction",
"reduces calls to code that only runs once",
createOnceReductionPass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index b0b42d5de..e6ff7709e 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -92,6 +92,9 @@ Pass* createMultiMemoryLoweringPass();
Pass* createMultiMemoryLoweringWithBoundsChecksPass();
Pass* createNameListPass();
Pass* createNameTypesPass();
+Pass* createNoInlinePass();
+Pass* createNoFullInlinePass();
+Pass* createNoPartialInlinePass();
Pass* createOnceReductionPass();
Pass* createOptimizeAddedConstantsPass();
Pass* createOptimizeAddedConstantsPropagatePass();
diff --git a/src/wasm.h b/src/wasm.h
index a7a2e0b1e..24138c99d 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -2072,6 +2072,12 @@ public:
delimiterLocations;
BinaryLocations::FunctionLocations funcLocation;
+ // Inlining metadata: whether to disallow full and/or partial inlining (for
+ // details on what those mean, see Inlining.cpp).
+ bool noFullInline = false;
+ bool noPartialInline = false;
+
+ // Methods
Signature getSig() { return type.getSignature(); }
Type getParams() { return getSig().params; }
Type getResults() { return getSig().results; }
diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test
index b18c312ff..a45096e39 100644
--- a/test/lit/help/wasm-opt.test
+++ b/test/lit/help/wasm-opt.test
@@ -297,6 +297,14 @@
;; CHECK-NEXT:
;; CHECK-NEXT: --nm name list
;; CHECK-NEXT:
+;; CHECK-NEXT: --no-full-inline mark functions as no-inline (for
+;; CHECK-NEXT: full inlining only)
+;; CHECK-NEXT:
+;; CHECK-NEXT: --no-inline mark functions as no-inline
+;; CHECK-NEXT:
+;; CHECK-NEXT: --no-partial-inline mark functions as no-inline (for
+;; CHECK-NEXT: partial inlining only)
+;; CHECK-NEXT:
;; CHECK-NEXT: --once-reduction reduces calls to code that only
;; CHECK-NEXT: runs once
;; CHECK-NEXT:
diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test
index 129374049..9303642be 100644
--- a/test/lit/help/wasm2js.test
+++ b/test/lit/help/wasm2js.test
@@ -256,6 +256,14 @@
;; CHECK-NEXT:
;; CHECK-NEXT: --nm name list
;; CHECK-NEXT:
+;; CHECK-NEXT: --no-full-inline mark functions as no-inline (for
+;; CHECK-NEXT: full inlining only)
+;; CHECK-NEXT:
+;; CHECK-NEXT: --no-inline mark functions as no-inline
+;; CHECK-NEXT:
+;; CHECK-NEXT: --no-partial-inline mark functions as no-inline (for
+;; CHECK-NEXT: partial inlining only)
+;; CHECK-NEXT:
;; CHECK-NEXT: --once-reduction reduces calls to code that only
;; CHECK-NEXT: runs once
;; CHECK-NEXT:
diff --git a/test/lit/passes/no-inline.wast b/test/lit/passes/no-inline.wast
new file mode 100644
index 000000000..3321dc1ad
--- /dev/null
+++ b/test/lit/passes/no-inline.wast
@@ -0,0 +1,925 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
+
+;; Enable both full and partial inlining, and show how we filter out functions
+;; using --no-*-inline. The functions with "yes" in their names will always be
+;; inlined, while the ones with "maybe" will be filtered out in some modes.
+
+;; RUN: foreach %s %t wasm-opt --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix YES_ALL
+;; RUN: foreach %s %t wasm-opt --no-partial-inline=*maybe* --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_PART
+;; RUN: foreach %s %t wasm-opt --no-full-inline=*maybe* --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_FULL
+;; RUN: foreach %s %t wasm-opt --no-inline=*maybe* --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_BOTH
+
+(module
+ ;; YES_ALL: (type $0 (func))
+
+ ;; YES_ALL: (type $1 (func (param i32)))
+
+ ;; YES_ALL: (import "a" "b" (func $import))
+ ;; NO_PART: (type $0 (func))
+
+ ;; NO_PART: (type $1 (func (param i32)))
+
+ ;; NO_PART: (import "a" "b" (func $import))
+ ;; NO_FULL: (type $0 (func))
+
+ ;; NO_FULL: (type $1 (func (param i32)))
+
+ ;; NO_FULL: (import "a" "b" (func $import))
+ ;; NO_BOTH: (type $0 (func))
+
+ ;; NO_BOTH: (type $1 (func (param i32)))
+
+ ;; NO_BOTH: (import "a" "b" (func $import))
+ (import "a" "b" (func $import))
+
+ (func $full-yes-inline (param $x i32)
+ (call $import)
+ )
+
+ ;; NO_FULL: (func $full-maybe-inline (param $x i32)
+ ;; NO_FULL-NEXT: (call $import)
+ ;; NO_FULL-NEXT: )
+ ;; NO_BOTH: (func $full-maybe-inline (param $x i32)
+ ;; NO_BOTH-NEXT: (call $import)
+ ;; NO_BOTH-NEXT: )
+ (func $full-maybe-inline (param $x i32)
+ (call $import)
+ )
+
+ (func $partial-yes-inline (param $x i32)
+ (if
+ (local.get $x)
+ (return)
+ )
+ (loop $l
+ (call $import)
+ (br $l)
+ )
+ )
+
+ ;; NO_PART: (func $partial-maybe-inline (param $x i32)
+ ;; NO_PART-NEXT: (if
+ ;; NO_PART-NEXT: (local.get $x)
+ ;; NO_PART-NEXT: (return)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (loop $l
+ ;; NO_PART-NEXT: (call $import)
+ ;; NO_PART-NEXT: (br $l)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_BOTH: (func $partial-maybe-inline (param $x i32)
+ ;; NO_BOTH-NEXT: (if
+ ;; NO_BOTH-NEXT: (local.get $x)
+ ;; NO_BOTH-NEXT: (return)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (loop $l
+ ;; NO_BOTH-NEXT: (call $import)
+ ;; NO_BOTH-NEXT: (br $l)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ (func $partial-maybe-inline (param $x i32)
+ (if
+ (local.get $x)
+ (return)
+ )
+ (loop $l
+ (call $import)
+ (br $l)
+ )
+ )
+
+ ;; YES_ALL: (func $caller
+ ;; YES_ALL-NEXT: (local $0 i32)
+ ;; YES_ALL-NEXT: (local $1 i32)
+ ;; YES_ALL-NEXT: (local $2 i32)
+ ;; YES_ALL-NEXT: (local $3 i32)
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$full-yes-inline
+ ;; YES_ALL-NEXT: (local.set $0
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $import)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$full-maybe-inline$1
+ ;; YES_ALL-NEXT: (local.set $1
+ ;; YES_ALL-NEXT: (i32.const 1)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $import)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$2
+ ;; YES_ALL-NEXT: (local.set $2
+ ;; YES_ALL-NEXT: (i32.const 2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (i32.eqz
+ ;; YES_ALL-NEXT: (local.get $2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; YES_ALL-NEXT: (local.get $2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-maybe-inline$3
+ ;; YES_ALL-NEXT: (local.set $3
+ ;; YES_ALL-NEXT: (i32.const 3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (i32.eqz
+ ;; YES_ALL-NEXT: (local.get $3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $byn-split-outlined-A$partial-maybe-inline
+ ;; YES_ALL-NEXT: (local.get $3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; NO_PART: (func $caller
+ ;; NO_PART-NEXT: (local $0 i32)
+ ;; NO_PART-NEXT: (local $1 i32)
+ ;; NO_PART-NEXT: (local $2 i32)
+ ;; NO_PART-NEXT: (block
+ ;; NO_PART-NEXT: (block $__inlined_func$full-yes-inline
+ ;; NO_PART-NEXT: (local.set $0
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $import)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (block
+ ;; NO_PART-NEXT: (block $__inlined_func$full-maybe-inline$1
+ ;; NO_PART-NEXT: (local.set $1
+ ;; NO_PART-NEXT: (i32.const 1)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $import)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (block
+ ;; NO_PART-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$2
+ ;; NO_PART-NEXT: (local.set $2
+ ;; NO_PART-NEXT: (i32.const 2)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (if
+ ;; NO_PART-NEXT: (i32.eqz
+ ;; NO_PART-NEXT: (local.get $2)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; NO_PART-NEXT: (local.get $2)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $partial-maybe-inline
+ ;; NO_PART-NEXT: (i32.const 3)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_FULL: (func $caller
+ ;; NO_FULL-NEXT: (local $0 i32)
+ ;; NO_FULL-NEXT: (local $1 i32)
+ ;; NO_FULL-NEXT: (local $2 i32)
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$full-yes-inline
+ ;; NO_FULL-NEXT: (local.set $0
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $import)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $full-maybe-inline
+ ;; NO_FULL-NEXT: (i32.const 1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$1
+ ;; NO_FULL-NEXT: (local.set $1
+ ;; NO_FULL-NEXT: (i32.const 2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (i32.eqz
+ ;; NO_FULL-NEXT: (local.get $1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; NO_FULL-NEXT: (local.get $1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-maybe-inline$2
+ ;; NO_FULL-NEXT: (local.set $2
+ ;; NO_FULL-NEXT: (i32.const 3)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (i32.eqz
+ ;; NO_FULL-NEXT: (local.get $2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $byn-split-outlined-A$partial-maybe-inline
+ ;; NO_FULL-NEXT: (local.get $2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_BOTH: (func $caller
+ ;; NO_BOTH-NEXT: (local $0 i32)
+ ;; NO_BOTH-NEXT: (local $1 i32)
+ ;; NO_BOTH-NEXT: (block
+ ;; NO_BOTH-NEXT: (block $__inlined_func$full-yes-inline
+ ;; NO_BOTH-NEXT: (local.set $0
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $import)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $full-maybe-inline
+ ;; NO_BOTH-NEXT: (i32.const 1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (block
+ ;; NO_BOTH-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$1
+ ;; NO_BOTH-NEXT: (local.set $1
+ ;; NO_BOTH-NEXT: (i32.const 2)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (if
+ ;; NO_BOTH-NEXT: (i32.eqz
+ ;; NO_BOTH-NEXT: (local.get $1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; NO_BOTH-NEXT: (local.get $1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $partial-maybe-inline
+ ;; NO_BOTH-NEXT: (i32.const 3)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ (func $caller
+ (call $full-yes-inline
+ (i32.const 0)
+ )
+ (call $full-maybe-inline
+ (i32.const 1)
+ )
+ (call $partial-yes-inline
+ (i32.const 2)
+ )
+ (call $partial-maybe-inline
+ (i32.const 3)
+ )
+ )
+
+ ;; YES_ALL: (func $caller-2
+ ;; YES_ALL-NEXT: (local $0 i32)
+ ;; YES_ALL-NEXT: (local $1 i32)
+ ;; YES_ALL-NEXT: (local $2 i32)
+ ;; YES_ALL-NEXT: (local $3 i32)
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$full-yes-inline$4
+ ;; YES_ALL-NEXT: (local.set $0
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $import)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$full-maybe-inline$5
+ ;; YES_ALL-NEXT: (local.set $1
+ ;; YES_ALL-NEXT: (i32.const 1)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $import)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$6
+ ;; YES_ALL-NEXT: (local.set $2
+ ;; YES_ALL-NEXT: (i32.const 2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (i32.eqz
+ ;; YES_ALL-NEXT: (local.get $2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; YES_ALL-NEXT: (local.get $2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-maybe-inline$7
+ ;; YES_ALL-NEXT: (local.set $3
+ ;; YES_ALL-NEXT: (i32.const 3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (i32.eqz
+ ;; YES_ALL-NEXT: (local.get $3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (call $byn-split-outlined-A$partial-maybe-inline
+ ;; YES_ALL-NEXT: (local.get $3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; NO_PART: (func $caller-2
+ ;; NO_PART-NEXT: (local $0 i32)
+ ;; NO_PART-NEXT: (local $1 i32)
+ ;; NO_PART-NEXT: (local $2 i32)
+ ;; NO_PART-NEXT: (block
+ ;; NO_PART-NEXT: (block $__inlined_func$full-yes-inline$3
+ ;; NO_PART-NEXT: (local.set $0
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $import)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (block
+ ;; NO_PART-NEXT: (block $__inlined_func$full-maybe-inline$4
+ ;; NO_PART-NEXT: (local.set $1
+ ;; NO_PART-NEXT: (i32.const 1)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $import)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (block
+ ;; NO_PART-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$5
+ ;; NO_PART-NEXT: (local.set $2
+ ;; NO_PART-NEXT: (i32.const 2)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (if
+ ;; NO_PART-NEXT: (i32.eqz
+ ;; NO_PART-NEXT: (local.get $2)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; NO_PART-NEXT: (local.get $2)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $partial-maybe-inline
+ ;; NO_PART-NEXT: (i32.const 3)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_FULL: (func $caller-2
+ ;; NO_FULL-NEXT: (local $0 i32)
+ ;; NO_FULL-NEXT: (local $1 i32)
+ ;; NO_FULL-NEXT: (local $2 i32)
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$full-yes-inline$3
+ ;; NO_FULL-NEXT: (local.set $0
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $import)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $full-maybe-inline
+ ;; NO_FULL-NEXT: (i32.const 1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$4
+ ;; NO_FULL-NEXT: (local.set $1
+ ;; NO_FULL-NEXT: (i32.const 2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (i32.eqz
+ ;; NO_FULL-NEXT: (local.get $1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; NO_FULL-NEXT: (local.get $1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-maybe-inline$5
+ ;; NO_FULL-NEXT: (local.set $2
+ ;; NO_FULL-NEXT: (i32.const 3)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (i32.eqz
+ ;; NO_FULL-NEXT: (local.get $2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $byn-split-outlined-A$partial-maybe-inline
+ ;; NO_FULL-NEXT: (local.get $2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_BOTH: (func $caller-2
+ ;; NO_BOTH-NEXT: (local $0 i32)
+ ;; NO_BOTH-NEXT: (local $1 i32)
+ ;; NO_BOTH-NEXT: (block
+ ;; NO_BOTH-NEXT: (block $__inlined_func$full-yes-inline$2
+ ;; NO_BOTH-NEXT: (local.set $0
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $import)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $full-maybe-inline
+ ;; NO_BOTH-NEXT: (i32.const 1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (block
+ ;; NO_BOTH-NEXT: (block $__inlined_func$byn-split-inlineable-A$partial-yes-inline$3
+ ;; NO_BOTH-NEXT: (local.set $1
+ ;; NO_BOTH-NEXT: (i32.const 2)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (if
+ ;; NO_BOTH-NEXT: (i32.eqz
+ ;; NO_BOTH-NEXT: (local.get $1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $byn-split-outlined-A$partial-yes-inline
+ ;; NO_BOTH-NEXT: (local.get $1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $partial-maybe-inline
+ ;; NO_BOTH-NEXT: (i32.const 3)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ (func $caller-2
+ ;; Same as $caller, to prevent the functions from having a single use (which
+ ;; is always inlined).
+ (call $full-yes-inline
+ (i32.const 0)
+ )
+ (call $full-maybe-inline
+ (i32.const 1)
+ )
+ (call $partial-yes-inline
+ (i32.const 2)
+ )
+ (call $partial-maybe-inline
+ (i32.const 3)
+ )
+ )
+)
+
+;; YES_ALL: (func $byn-split-outlined-A$partial-yes-inline (param $x i32)
+;; YES_ALL-NEXT: (loop $l
+;; YES_ALL-NEXT: (call $import)
+;; YES_ALL-NEXT: (br $l)
+;; YES_ALL-NEXT: )
+;; YES_ALL-NEXT: )
+
+;; YES_ALL: (func $byn-split-outlined-A$partial-maybe-inline (param $x i32)
+;; YES_ALL-NEXT: (loop $l
+;; YES_ALL-NEXT: (call $import)
+;; YES_ALL-NEXT: (br $l)
+;; YES_ALL-NEXT: )
+;; YES_ALL-NEXT: )
+
+;; NO_PART: (func $byn-split-outlined-A$partial-yes-inline (param $x i32)
+;; NO_PART-NEXT: (loop $l
+;; NO_PART-NEXT: (call $import)
+;; NO_PART-NEXT: (br $l)
+;; NO_PART-NEXT: )
+;; NO_PART-NEXT: )
+
+;; NO_FULL: (func $byn-split-outlined-A$partial-yes-inline (param $x i32)
+;; NO_FULL-NEXT: (loop $l
+;; NO_FULL-NEXT: (call $import)
+;; NO_FULL-NEXT: (br $l)
+;; NO_FULL-NEXT: )
+;; NO_FULL-NEXT: )
+
+;; NO_FULL: (func $byn-split-outlined-A$partial-maybe-inline (param $x i32)
+;; NO_FULL-NEXT: (loop $l
+;; NO_FULL-NEXT: (call $import)
+;; NO_FULL-NEXT: (br $l)
+;; NO_FULL-NEXT: )
+;; NO_FULL-NEXT: )
+
+;; NO_BOTH: (func $byn-split-outlined-A$partial-yes-inline (param $x i32)
+;; NO_BOTH-NEXT: (loop $l
+;; NO_BOTH-NEXT: (call $import)
+;; NO_BOTH-NEXT: (br $l)
+;; NO_BOTH-NEXT: )
+;; NO_BOTH-NEXT: )
+(module
+ ;; YES_ALL: (type $0 (func))
+
+ ;; YES_ALL: (import "out" "func" (func $import))
+ ;; NO_PART: (type $0 (func))
+
+ ;; NO_PART: (type $1 (func (param i32)))
+
+ ;; NO_PART: (import "out" "func" (func $import))
+ ;; NO_FULL: (type $0 (func))
+
+ ;; NO_FULL: (import "out" "func" (func $import))
+ ;; NO_BOTH: (type $0 (func))
+
+ ;; NO_BOTH: (type $1 (func (param i32)))
+
+ ;; NO_BOTH: (import "out" "func" (func $import))
+ (import "out" "func" (func $import))
+
+ ;; NO_PART: (func $maybe-partial-or-full-1 (param $x i32)
+ ;; NO_PART-NEXT: (if
+ ;; NO_PART-NEXT: (local.get $x)
+ ;; NO_PART-NEXT: (call $import)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_BOTH: (func $maybe-partial-or-full-1 (param $x i32)
+ ;; NO_BOTH-NEXT: (if
+ ;; NO_BOTH-NEXT: (local.get $x)
+ ;; NO_BOTH-NEXT: (call $import)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ (func $maybe-partial-or-full-1 (param $x i32)
+ ;; This function can be partially inlined, but after doing so we want to
+ ;; inline the remainder as well, so instead we fully inline it. When full
+ ;; inlining is disabled but partial inlining is enabled, we should only
+ ;; partially inline it.
+ (if
+ (local.get $x)
+ (call $import)
+ )
+ )
+
+ ;; NO_PART: (func $maybe-partial-or-full-2 (param $x i32)
+ ;; NO_PART-NEXT: (if
+ ;; NO_PART-NEXT: (local.get $x)
+ ;; NO_PART-NEXT: (return)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (nop)
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (drop
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_BOTH: (func $maybe-partial-or-full-2 (param $x i32)
+ ;; NO_BOTH-NEXT: (if
+ ;; NO_BOTH-NEXT: (local.get $x)
+ ;; NO_BOTH-NEXT: (return)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (nop)
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (drop
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ (func $maybe-partial-or-full-2 (param $x i32)
+ ;; As above, but for another form of partial inlining. Here we need to add
+ ;; some extra things to the function size for partial inlining to kick in.
+ (if
+ (local.get $x)
+ (return)
+ )
+ (nop)
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ (drop
+ (i32.const 0)
+ )
+ )
+
+ ;; YES_ALL: (func $caller
+ ;; YES_ALL-NEXT: (local $0 i32)
+ ;; YES_ALL-NEXT: (local $1 i32)
+ ;; YES_ALL-NEXT: (local $2 i32)
+ ;; YES_ALL-NEXT: (local $3 i32)
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$maybe-partial-or-full-1
+ ;; YES_ALL-NEXT: (local.set $0
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (local.get $0)
+ ;; YES_ALL-NEXT: (call $import)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$maybe-partial-or-full-1$1
+ ;; YES_ALL-NEXT: (local.set $1
+ ;; YES_ALL-NEXT: (i32.const 1)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (local.get $1)
+ ;; YES_ALL-NEXT: (call $import)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$maybe-partial-or-full-2$2
+ ;; YES_ALL-NEXT: (local.set $2
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (local.get $2)
+ ;; YES_ALL-NEXT: (br $__inlined_func$maybe-partial-or-full-2$2)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (nop)
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (block $__inlined_func$maybe-partial-or-full-2$3
+ ;; YES_ALL-NEXT: (local.set $3
+ ;; YES_ALL-NEXT: (i32.const 1)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (block
+ ;; YES_ALL-NEXT: (if
+ ;; YES_ALL-NEXT: (local.get $3)
+ ;; YES_ALL-NEXT: (br $__inlined_func$maybe-partial-or-full-2$3)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (nop)
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: (drop
+ ;; YES_ALL-NEXT: (i32.const 0)
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; YES_ALL-NEXT: )
+ ;; NO_PART: (func $caller
+ ;; NO_PART-NEXT: (call $maybe-partial-or-full-1
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $maybe-partial-or-full-1
+ ;; NO_PART-NEXT: (i32.const 1)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $maybe-partial-or-full-2
+ ;; NO_PART-NEXT: (i32.const 0)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: (call $maybe-partial-or-full-2
+ ;; NO_PART-NEXT: (i32.const 1)
+ ;; NO_PART-NEXT: )
+ ;; NO_PART-NEXT: )
+ ;; NO_FULL: (func $caller
+ ;; NO_FULL-NEXT: (local $0 i32)
+ ;; NO_FULL-NEXT: (local $1 i32)
+ ;; NO_FULL-NEXT: (local $2 i32)
+ ;; NO_FULL-NEXT: (local $3 i32)
+ ;; NO_FULL-NEXT: (local $4 i32)
+ ;; NO_FULL-NEXT: (local $5 i32)
+ ;; NO_FULL-NEXT: (local $6 i32)
+ ;; NO_FULL-NEXT: (local $7 i32)
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-B$maybe-partial-or-full-1
+ ;; NO_FULL-NEXT: (local.set $0
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (local.get $0)
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-outlined-B$maybe-partial-or-full-1$4
+ ;; NO_FULL-NEXT: (local.set $4
+ ;; NO_FULL-NEXT: (local.get $0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $import)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-B$maybe-partial-or-full-1$1
+ ;; NO_FULL-NEXT: (local.set $1
+ ;; NO_FULL-NEXT: (i32.const 1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (local.get $1)
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-outlined-B$maybe-partial-or-full-1$5
+ ;; NO_FULL-NEXT: (local.set $5
+ ;; NO_FULL-NEXT: (local.get $1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (call $import)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-partial-or-full-2$2
+ ;; NO_FULL-NEXT: (local.set $2
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (i32.eqz
+ ;; NO_FULL-NEXT: (local.get $2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-outlined-A$maybe-partial-or-full-2$6
+ ;; NO_FULL-NEXT: (local.set $6
+ ;; NO_FULL-NEXT: (local.get $2)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (nop)
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-inlineable-A$maybe-partial-or-full-2$3
+ ;; NO_FULL-NEXT: (local.set $3
+ ;; NO_FULL-NEXT: (i32.const 1)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (if
+ ;; NO_FULL-NEXT: (i32.eqz
+ ;; NO_FULL-NEXT: (local.get $3)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block $__inlined_func$byn-split-outlined-A$maybe-partial-or-full-2$7
+ ;; NO_FULL-NEXT: (local.set $7
+ ;; NO_FULL-NEXT: (local.get $3)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (block
+ ;; NO_FULL-NEXT: (nop)
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: (drop
+ ;; NO_FULL-NEXT: (i32.const 0)
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_FULL-NEXT: )
+ ;; NO_BOTH: (func $caller
+ ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-1
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-1
+ ;; NO_BOTH-NEXT: (i32.const 1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-2
+ ;; NO_BOTH-NEXT: (i32.const 0)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-2
+ ;; NO_BOTH-NEXT: (i32.const 1)
+ ;; NO_BOTH-NEXT: )
+ ;; NO_BOTH-NEXT: )
+ (func $caller
+ ;; In YES_ALL we will fully inline all of these. In NO_FULL we will partially
+ ;; inline. In NO_PART and NO_BOTH we will not inline at all (in theory we
+ ;; could do full inlining when only partial inlining is disabled, but we only
+ ;; see that full inlining is possible as a result of partial inlining, so if
+ ;; partial is disabled we don't get there, and full inlining is not
+ ;; justified).
+ (call $maybe-partial-or-full-1
+ (i32.const 0)
+ )
+ (call $maybe-partial-or-full-1
+ (i32.const 1)
+ )
+ (call $maybe-partial-or-full-2
+ (i32.const 0)
+ )
+ (call $maybe-partial-or-full-2
+ (i32.const 1)
+ )
+ )
+)