summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Inlining.cpp42
-rw-r--r--test/lit/passes/inlining_splitting.wast571
2 files changed, 573 insertions, 40 deletions
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index 511271f42..112c31036 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -552,7 +552,12 @@ struct FunctionSplitter {
// into account (like limitations on which functions can be inlined into in
// each iteration, the number of iterations, etc.). Therefore this function
// may only find out if we *can* split, but not actually do any splitting.
- InliningMode getSplitInliningMode(Function* func) {
+ //
+ // Note that to avoid wasteful work, this function may return "Full' inlining
+ // mode instead of a split inining. That is; if it detects that a partial
+ // inlining will trigger a follow up full inline of the splitted function
+ // it will instead return "InliningMode::Full" directly.
+ InliningMode getSplitDrivenInliningMode(Function* func, FunctionInfo& info) {
auto* body = func->body;
// If the body is a block, and we have breaks to that block, then we cannot
@@ -588,6 +593,13 @@ struct FunctionSplitter {
// return), and we would not even attempt to do splitting.
assert(body->is<Block>());
+ 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)) {
+ return InliningMode::Full;
+ }
+
return InliningMode::SplitPatternA;
}
@@ -666,8 +678,17 @@ struct FunctionSplitter {
assert(iff->ifTrue->type == Type::unreachable);
}
}
-
// Success, this matches the pattern.
+
+ // If the outlined function will be worth inlining normally, skip the
+ // intermediate state and inline fully now.
+ if (numIfs == 1) {
+ auto outlinedFunctionSize = Measurer::measure(iff->ifTrue);
+ if (outlinedFunctionWorthInlining(info, outlinedFunctionSize)) {
+ return InliningMode::Full;
+ }
+ }
+
return InliningMode::SplitPatternB;
}
@@ -730,6 +751,19 @@ private:
// staying constant.
std::unordered_map<Name, Split> splits;
+ bool outlinedFunctionWorthInlining(FunctionInfo& origin, Index sizeEstimate) {
+ FunctionInfo info;
+ // Start with a copy of the origin's info, and apply the size estimate.
+ // This is not accurate, for example the origin function may have
+ // loop or calls even though this section may not have.
+ // This is a conservative estimate, that is, it will return true only when
+ // it should, but might return false when a more precise analysis would
+ // return true. And it is a practical estimation to avoid extra future work.
+ info = origin;
+ info.size = sizeEstimate;
+ return info.worthFullInlining(options);
+ }
+
Function* doSplit(Function* func, InliningMode inliningMode) {
Builder builder(*module);
@@ -1084,8 +1118,8 @@ struct Inlining : public Pass {
// Otherwise, check if we can at least inline part of it, if we are
// interested in such things.
if (functionSplitter) {
- info.inliningMode =
- functionSplitter->getSplitInliningMode(module->getFunction(name));
+ info.inliningMode = functionSplitter->getSplitDrivenInliningMode(
+ module->getFunction(name), info);
return info.inliningMode;
}
diff --git a/test/lit/passes/inlining_splitting.wast b/test/lit/passes/inlining_splitting.wast
index 74039533f..d1bc934dc 100644
--- a/test/lit/passes/inlining_splitting.wast
+++ b/test/lit/passes/inlining_splitting.wast
@@ -768,7 +768,7 @@
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_65
+ ;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_67
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -783,7 +783,7 @@
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_65
+ ;; CHECK-NEXT: (call $byn-split-outlined-A$colliding-name_67
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -972,7 +972,13 @@
;; It is ok if the body is not unreachable (so long as it contains no
;; returns). We will optimize this, and just do a call to the outlined
;; code, without a return of a value here.
- (call $import)
+ (block
+ ;; We need to have a loop here to avoid normal inlining from kicking in
+ ;; on the outlined code.
+ (loop $loop
+ (call $import)
+ )
+ )
)
(local.get $x)
)
@@ -980,8 +986,6 @@
;; CHECK: (func $call-reachable-if-body (type $none_=>_none)
;; CHECK-NEXT: (local $0 anyref)
;; CHECK-NEXT: (local $1 anyref)
- ;; CHECK-NEXT: (local $2 anyref)
- ;; CHECK-NEXT: (local $3 anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$reachable-if-body (result anyref)
@@ -993,11 +997,8 @@
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$reachable-if-body
- ;; CHECK-NEXT: (local.set $2
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: (call $byn-split-outlined-B$reachable-if-body
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $0)
@@ -1016,11 +1017,8 @@
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (block $__inlined_func$byn-split-outlined-B$reachable-if-body0
- ;; CHECK-NEXT: (local.set $3
- ;; CHECK-NEXT: (local.get $1)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: (call $byn-split-outlined-B$reachable-if-body
+ ;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
@@ -1030,27 +1028,69 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-reachable-if-body
- ;; Note that the above contains
- ;;
- ;; (block $__inlined_func$byn-split-outlined-B$reachable-if-body
- ;;
- ;; which indicates that we've inlined the outlined function. That seems odd,
- ;; but it is the result of the if's body being just a call. When we outline,
- ;; we end up with a function that all it does is make that call - which is
- ;; worth inlining in the normal way (to avoid two calls). As a result of all
- ;; that, we end up inlining *all* of $reachable-if-body, just by a
- ;; roundabout way (split, outline, then inline). While this seems odd, each
- ;; step along the way makes sense, and the result is a good one (might be a
- ;; little hard to see before opts remove the extra block cruft etc.).
- ;;
- ;; We could avoid this if we detected that the if body is just a call, and
- ;; not done any outlining - just done that call. That would be more
- ;; efficient, but it would make the code more complicated, and the result is
- ;; the same.
(drop (call $reachable-if-body (ref.null any)))
(drop (call $reachable-if-body (ref.null any)))
)
+ (func $reachable-if-body-noloop (param $x anyref) (result anyref)
+ ;; As above, but without a loop.
+ (if
+ (ref.is_null
+ (local.get $x)
+ )
+ (call $import)
+ )
+ (local.get $x)
+ )
+
+ ;; CHECK: (func $call-reachable-if-body-noloop (type $none_=>_none)
+ ;; CHECK-NEXT: (local $0 anyref)
+ ;; CHECK-NEXT: (local $1 anyref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result anyref)
+ ;; CHECK-NEXT: (block $__inlined_func$reachable-if-body-noloop (result anyref)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result anyref)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (ref.is_null
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result anyref)
+ ;; CHECK-NEXT: (block $__inlined_func$reachable-if-body-noloop0 (result anyref)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result anyref)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (ref.is_null
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $import)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-reachable-if-body-noloop
+ ;; As above, but the called function has no loop. In that case, even though
+ ;; it fits the pattern for partial inlining we can just inline the entire
+ ;; thing normally.
+ (drop (call $reachable-if-body-noloop (ref.null any)))
+ (drop (call $reachable-if-body-noloop (ref.null any)))
+ )
+
;; CHECK: (func $reachable-if-body-return (type $anyref_=>_anyref) (param $x anyref) (result anyref)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (ref.is_null
@@ -1202,7 +1242,7 @@
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_74
+ ;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_76
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -1233,7 +1273,7 @@
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
- ;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_74
+ ;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_76
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -1385,7 +1425,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
-;; CHECK: (func $byn-split-outlined-A$colliding-name_65 (type $i32_=>_none) (param $x i32)
+;; CHECK: (func $byn-split-outlined-A$colliding-name_67 (type $i32_=>_none) (param $x i32)
;; CHECK-NEXT: (loop $l
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br $l)
@@ -1397,12 +1437,18 @@
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
+;; CHECK: (func $byn-split-outlined-B$reachable-if-body (type $anyref_=>_none) (param $x anyref)
+;; CHECK-NEXT: (loop $loop
+;; CHECK-NEXT: (call $import)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: )
+
;; CHECK: (func $byn-split-outlined-B$unreachable-if-body-no-result (type $anyref_=>_none) (param $x anyref)
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
-;; CHECK: (func $byn-split-outlined-B$multi-if_74 (type $anyref_=>_none) (param $x anyref)
+;; CHECK: (func $byn-split-outlined-B$multi-if_76 (type $anyref_=>_none) (param $x anyref)
;; CHECK-NEXT: (loop $x
;; CHECK-NEXT: (call $import)
;; CHECK-NEXT: (br_if $x
@@ -1611,6 +1657,7 @@
(nop)
)
)
+
;; CHECK: (func $byn-split-outlined-A$0 (type $none_=>_none)
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $__inlined_func$1
@@ -1697,3 +1744,455 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
+(module
+ (func $middle-size-A (param $x i32)
+ ;; This function is too big for normal inlining with the default size limit.
+ ;; However, if we partially inline it then the outlined code becomes small
+ ;; enough to be normally inlined. We should just inline it normally in that
+ ;; case, to avoid wasted work.
+ (if
+ (local.get $x)
+ (return)
+ )
+ ;; 6x3 = 18 items, close to the default size limit of 20. With the if, we
+ ;; hit that limit and are too big. But if we did partial inlining then the
+ ;; lines below us are small enough to then be inlined normally.
+ (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)) (drop (i32.const 0))
+ )
+
+ ;; CHECK: (type $none_=>_none (func))
+
+ ;; CHECK: (type $i32_=>_none (func (param i32)))
+
+ ;; CHECK: (type $i32_=>_i32 (func (param i32) (result i32)))
+
+ ;; CHECK: (func $call-$middle-size-A (type $none_=>_none)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block $__inlined_func$middle-size-A
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (br $__inlined_func$middle-size-A)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block $__inlined_func$middle-size-A0
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (br $__inlined_func$middle-size-A0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-$middle-size-A
+ ;; This will be normally inlined, see the comment in the above function.
+ ;; We can see it is normally inlined and not partially from the string
+ ;; "__inlined_func" in the code (instead of "split" appearing anywhere).
+ (call $middle-size-A
+ (i32.const 0)
+ )
+ (call $middle-size-A
+ (i32.const 1)
+ )
+ )
+
+ (func $big-size-A (param $x i32)
+ ;; As above, but a little larger - so large that we won't normally inline
+ ;; it.
+ (if
+ (local.get $x)
+ (return)
+ )
+ ;; 6x4 = 24 items, which is more than the inlining limit.
+ (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)) (drop (i32.const 0))
+ (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0))
+ )
+
+ ;; CHECK: (func $call-$big-size-A (type $none_=>_none)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$big-size-A
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $byn-split-outlined-A$big-size-A
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$big-size-A0
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (i32.eqz
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (call $byn-split-outlined-A$big-size-A
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-$big-size-A
+ ;; Normal inlining can't work here, so we'll just do partial inlining.
+ (call $big-size-A
+ (i32.const 0)
+ )
+ (call $big-size-A
+ (i32.const 1)
+ )
+ )
+
+ (func $middle-size-B (param $x i32) (result i32)
+ ;; As above, but for pattern B and not A.
+ (if
+ (local.get $x)
+ (block
+ (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)) (drop (i32.const 0))
+ (unreachable)
+ )
+ )
+ (local.get $x)
+ )
+
+ ;; CHECK: (func $call-$middle-size-B (type $none_=>_none)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (block $__inlined_func$middle-size-B (result i32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (block $__inlined_func$middle-size-B0 (result i32)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-$middle-size-B
+ ;; We will normally inline here.
+ (drop
+ (call $middle-size-B
+ (i32.const 0)
+ )
+ )
+ (drop
+ (call $middle-size-B
+ (i32.const 1)
+ )
+ )
+ )
+
+ (func $big-size-B (param $x i32) (result i32)
+ ;; As above, but a little larger - so large that we won't normally inline
+ ;; it.
+ (if
+ (local.get $x)
+ (block
+ (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)) (drop (i32.const 0))
+ (drop (i32.const 0)) (drop (i32.const 0)) (drop (i32.const 0))
+ (unreachable)
+ )
+ )
+ (local.get $x)
+ )
+
+ ;; CHECK: (func $call-$big-size-B (type $none_=>_none)
+ ;; CHECK-NEXT: (local $0 i32)
+ ;; CHECK-NEXT: (local $1 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$big-size-B (result i32)
+ ;; CHECK-NEXT: (local.set $0
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$big-size-B
+ ;; CHECK-NEXT: (call $byn-split-outlined-B$big-size-B
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$big-size-B0 (result i32)
+ ;; CHECK-NEXT: (local.set $1
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (block (result i32)
+ ;; CHECK-NEXT: (if
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (br $__inlined_func$byn-split-inlineable-B$big-size-B0
+ ;; CHECK-NEXT: (call $byn-split-outlined-B$big-size-B
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-$big-size-B
+ ;; We'll partially inline here.
+ (drop
+ (call $big-size-B
+ (i32.const 0)
+ )
+ )
+ (drop
+ (call $big-size-B
+ (i32.const 1)
+ )
+ )
+ )
+)
+;; CHECK: (func $byn-split-outlined-A$big-size-A (type $i32_=>_none) (param $x i32)
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: )
+
+;; CHECK: (func $byn-split-outlined-B$big-size-B (type $i32_=>_i32) (param $x i32) (result i32)
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (drop
+;; CHECK-NEXT: (i32.const 0)
+;; CHECK-NEXT: )
+;; CHECK-NEXT: (unreachable)
+;; CHECK-NEXT: )