diff options
-rw-r--r-- | src/passes/Inlining.cpp | 42 | ||||
-rw-r--r-- | test/lit/passes/inlining_splitting.wast | 571 |
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: ) |