[turbofan] First rudimentary inlining heuristic.
This is a first prototype for a rudimentary inlining heuristic allowing enabling of general inlining based existing budget flags. Also note that this approach does not yet work for multi-level inlining, for now the list of candidates is processed exactly once. R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/1406543002 Cr-Commit-Position: refs/heads/master@{#31249}
This commit is contained in:
parent
6628b77d57
commit
8ff6a0c005
@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/compiler/js-inlining-heuristic.h"
|
||||
|
||||
#include "src/compiler/dead-code-elimination.h" // TODO(mstarzinger): Remove!
|
||||
#include "src/compiler/node-matchers.h"
|
||||
#include "src/objects-inl.h"
|
||||
|
||||
@ -24,9 +25,88 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
|
||||
return inliner_.ReduceJSCallFunction(node, function);
|
||||
}
|
||||
|
||||
// All other functions are only handled with general inlining.
|
||||
if (mode_ == kRestrictedInlining) return NoChange();
|
||||
return inliner_.ReduceJSCallFunction(node, function);
|
||||
// Handling of special inlining modes right away:
|
||||
// - For restricted inlining: stop all handling at this point.
|
||||
// - For stressing inlining: immediately handle all functions.
|
||||
switch (mode_) {
|
||||
case kRestrictedInlining:
|
||||
return NoChange();
|
||||
case kStressInlining:
|
||||
return inliner_.ReduceJSCallFunction(node, function);
|
||||
case kGeneralInlining:
|
||||
break;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Everything below this line is part of the inlining heuristic.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Built-in functions are handled by the JSBuiltinReducer.
|
||||
if (function->shared()->HasBuiltinFunctionId()) return NoChange();
|
||||
|
||||
// Quick check on source code length to avoid parsing large candidate.
|
||||
if (function->shared()->SourceSize() > FLAG_max_inlined_source_size) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// Quick check on the size of the AST to avoid parsing large candidate.
|
||||
if (function->shared()->ast_node_count() > FLAG_max_inlined_nodes) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// Gather feedback on how often this call site has been hit before.
|
||||
CallFunctionParameters p = CallFunctionParametersOf(node->op());
|
||||
CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
|
||||
int calls = nexus.ExtractCallCount();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Everything above this line is part of the inlining heuristic.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// In the general case we remember the candidate for later.
|
||||
candidates_.push_back({function, node, calls});
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
void JSInliningHeuristic::ProcessCandidates() {
|
||||
if (candidates_.empty()) return; // Nothing to do without candidates.
|
||||
std::sort(candidates_.begin(), candidates_.end(), Compare);
|
||||
if (FLAG_trace_turbo_inlining) PrintCandidates();
|
||||
|
||||
int cumulative_count = 0;
|
||||
for (const Candidate& candidate : candidates_) {
|
||||
if (cumulative_count > FLAG_max_inlined_nodes_cumulative) break;
|
||||
inliner_.ReduceJSCallFunction(candidate.node, candidate.function);
|
||||
cumulative_count += candidate.function->shared()->ast_node_count();
|
||||
}
|
||||
|
||||
// TODO(mstarzinger): Temporary workaround to eliminate dead control from the
|
||||
// graph being introduced by the inliner. Make this part of the pipeline.
|
||||
GraphReducer graph_reducer(local_zone_, jsgraph_->graph(), jsgraph_->Dead());
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, jsgraph_->graph(),
|
||||
jsgraph_->common());
|
||||
graph_reducer.AddReducer(&dead_code_elimination);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool JSInliningHeuristic::Compare(const Candidate& left,
|
||||
const Candidate& right) {
|
||||
return left.calls > right.calls;
|
||||
}
|
||||
|
||||
|
||||
void JSInliningHeuristic::PrintCandidates() {
|
||||
PrintF("Candidates for inlining (size=%zu):\n", candidates_.size());
|
||||
for (const Candidate& candidate : candidates_) {
|
||||
PrintF(" id:%d, calls:%d, size[source]:%d, size[ast]:%d / %s\n",
|
||||
candidate.node->id(), candidate.calls,
|
||||
candidate.function->shared()->SourceSize(),
|
||||
candidate.function->shared()->ast_node_count(),
|
||||
candidate.function->shared()->DebugName()->ToCString().get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -13,18 +13,37 @@ namespace compiler {
|
||||
|
||||
class JSInliningHeuristic final : public AdvancedReducer {
|
||||
public:
|
||||
enum Mode { kRestrictedInlining, kGeneralInlining };
|
||||
enum Mode { kGeneralInlining, kRestrictedInlining, kStressInlining };
|
||||
JSInliningHeuristic(Editor* editor, Mode mode, Zone* local_zone,
|
||||
CompilationInfo* info, JSGraph* jsgraph)
|
||||
: AdvancedReducer(editor),
|
||||
mode_(mode),
|
||||
inliner_(editor, local_zone, info, jsgraph) {}
|
||||
local_zone_(local_zone),
|
||||
jsgraph_(jsgraph),
|
||||
inliner_(editor, local_zone, info, jsgraph),
|
||||
candidates_(local_zone) {}
|
||||
|
||||
Reduction Reduce(Node* node) final;
|
||||
|
||||
// Processes the list of candidates gathered while the reducer was running,
|
||||
// and inlines call sites that the heuristic determines to be important.
|
||||
void ProcessCandidates();
|
||||
|
||||
private:
|
||||
struct Candidate {
|
||||
Handle<JSFunction> function; // The call target being inlined.
|
||||
Node* node; // The call site at which to inline.
|
||||
int calls; // Number of times the call site was hit.
|
||||
};
|
||||
|
||||
static bool Compare(const Candidate& left, const Candidate& right);
|
||||
void PrintCandidates();
|
||||
|
||||
Mode const mode_;
|
||||
Zone* local_zone_;
|
||||
JSGraph* jsgraph_;
|
||||
JSInliner inliner_;
|
||||
ZoneVector<Candidate> candidates_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -542,6 +542,7 @@ struct InliningPhase {
|
||||
AddReducer(data, &graph_reducer, &context_specialization);
|
||||
AddReducer(data, &graph_reducer, &inlining);
|
||||
graph_reducer.ReduceGraph();
|
||||
inlining.ProcessCandidates();
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user