summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/Inlining.cpp42
1 files changed, 38 insertions, 4 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;
}