[VM] Add support for skipping a prologue range of blocks (for inlining heuristics)

Issue https://github.com/dart-lang/sdk/issues/31495

Change-Id: I876f4e064cfd21f5c3e99b531ff69776eba99635
Reviewed-on: https://dart-review.googlesource.com/25060
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
Martin Kustermann 2017-12-01 00:03:56 +00:00 committed by commit-bot@chromium.org
parent 9174a627f5
commit 3347b700df
9 changed files with 79 additions and 21 deletions

View file

@ -26,7 +26,8 @@ DECLARE_FLAG(bool, verify_compiler);
FlowGraph::FlowGraph(const ParsedFunction& parsed_function,
GraphEntryInstr* graph_entry,
intptr_t max_block_id)
intptr_t max_block_id,
PrologueInfo prologue_info)
: thread_(Thread::Current()),
parent_(),
current_ssa_temp_index_(0),
@ -43,6 +44,7 @@ FlowGraph::FlowGraph(const ParsedFunction& parsed_function,
constant_dead_(NULL),
constant_empty_context_(NULL),
licm_allowed_(true),
prologue_info_(prologue_info),
loop_headers_(NULL),
loop_invariant_loads_(NULL),
deferred_prefixes_(parsed_function.deferred_prefixes()),
@ -1410,8 +1412,16 @@ intptr_t FlowGraph::InstructionCount() const {
intptr_t size = 0;
// Iterate each block, skipping the graph entry.
for (intptr_t i = 1; i < preorder_.length(); ++i) {
for (ForwardInstructionIterator it(preorder_[i]); !it.Done();
it.Advance()) {
BlockEntryInstr* block = preorder_[i];
// Skip any blocks from the prologue to make them not count towards the
// inlining instruction budget.
const intptr_t block_id = block->block_id();
if (prologue_info_.Contains(block_id)) {
continue;
}
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
++size;
}
}

View file

@ -73,12 +73,32 @@ struct ConstantPoolTrait {
}
};
struct PrologueInfo {
// The first blockid used for prologue building. This information can be used
// by the inliner for budget calculations: The prologue code falls away when
// inlining, so we should not include it in the budget.
const intptr_t min_block_id;
// The last blockid used for prologue building. This information can be used
// by the inliner for budget calculations: The prologue code falls away when
// inlining, so we should not include it in the budget.
const intptr_t max_block_id;
PrologueInfo(intptr_t min, intptr_t max)
: min_block_id(min), max_block_id(max) {}
bool Contains(intptr_t block_id) const {
return min_block_id <= block_id && block_id <= max_block_id;
}
};
// Class to encapsulate the construction and manipulation of the flow graph.
class FlowGraph : public ZoneAllocated {
public:
FlowGraph(const ParsedFunction& parsed_function,
GraphEntryInstr* graph_entry,
intptr_t max_block_id);
intptr_t max_block_id,
PrologueInfo prologue_info);
// Function properties.
const ParsedFunction& parsed_function() const { return parsed_function_; }
@ -235,6 +255,8 @@ class FlowGraph : public ZoneAllocated {
// after this point.
void disallow_licm() { licm_allowed_ = false; }
PrologueInfo prologue_info() const { return prologue_info_; }
const ZoneGrowableArray<BlockEntryInstr*>& LoopHeaders() {
if (loop_headers_ == NULL) {
loop_headers_ = ComputeLoops();
@ -401,6 +423,8 @@ class FlowGraph : public ZoneAllocated {
bool licm_allowed_;
const PrologueInfo prologue_info_;
ZoneGrowableArray<BlockEntryInstr*>* loop_headers_;
ZoneGrowableArray<BitVector*>* loop_invariant_loads_;
ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;

View file

@ -2911,6 +2911,9 @@ void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
TokenPosition::kNoSource);
}
if (HasParallelMove()) {
if (Assembler::EmittingComments()) {
compiler->EmitComment(parallel_move());
}
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
}

View file

@ -152,6 +152,13 @@ class GraphInfoCollector : public ValueObject {
instruction_count_ = 0;
for (BlockIterator block_it = graph.postorder_iterator(); !block_it.Done();
block_it.Advance()) {
// Skip any blocks from the prologue to make them not count towards the
// inlining instruction budget.
const intptr_t block_id = block_it.Current()->block_id();
if (graph.prologue_info().Contains(block_id)) {
continue;
}
for (ForwardInstructionIterator it(block_it.Current()); !it.Done();
it.Advance()) {
Instruction* current = it.Current();

View file

@ -4428,9 +4428,11 @@ FlowGraph* FlowGraphBuilder::BuildGraph() {
graph_entry_->RelinkToOsrEntry(Z, last_used_block_id_);
}
FlowGraph* graph =
new (Z) FlowGraph(parsed_function(), graph_entry_, last_used_block_id_);
PrologueInfo prologue_info(-1, -1);
FlowGraph* graph = new (Z) FlowGraph(parsed_function(), graph_entry_,
last_used_block_id_, prologue_info);
graph->set_await_token_positions(await_token_positions_);
return graph;
}

View file

@ -3484,9 +3484,10 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfStaticFieldInitializer() {
}
body += Return(TokenPosition::kNoSource);
PrologueInfo prologue_info(-1, -1);
return new (Z)
FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_,
flow_graph_builder_->last_used_block_id_);
flow_graph_builder_->last_used_block_id_, prologue_info);
}
FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldAccessor(
@ -3542,9 +3543,10 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldAccessor(
}
body += Return(TokenPosition::kNoSource);
PrologueInfo prologue_info(-1, -1);
return new (Z)
FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_,
flow_graph_builder_->last_used_block_id_);
flow_graph_builder_->last_used_block_id_, prologue_info);
}
void StreamingFlowGraphBuilder::SetupDefaultParameterValues() {
@ -3887,9 +3889,10 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
// Return the result.
body += Return(function_node_helper.end_position_);
PrologueInfo prologue_info(-1, -1);
return new (Z)
FlowGraph(*parsed_function(), flow_graph_builder_->graph_entry_,
flow_graph_builder_->last_used_block_id_);
flow_graph_builder_->last_used_block_id_, prologue_info);
}
LocalVariable* StreamingFlowGraphBuilder::LookupParameterDirect(
@ -4245,8 +4248,10 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(bool constructor) {
graph_entry->RelinkToOsrEntry(Z,
flow_graph_builder_->last_used_block_id_ + 1);
}
return new (Z) FlowGraph(*parsed_function(), graph_entry,
flow_graph_builder_->last_used_block_id_);
PrologueInfo prologue_info(-1, -1);
return new (Z)
FlowGraph(*parsed_function(), graph_entry,
flow_graph_builder_->last_used_block_id_, prologue_info);
}
FlowGraph* StreamingFlowGraphBuilder::BuildGraph(intptr_t kernel_offset) {

View file

@ -2212,8 +2212,10 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
body += BuildImplicitClosureCreation(function);
body += Return(TokenPosition::kNoSource);
return new (Z)
FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_);
// There is no prologue code for a method extractor.
PrologueInfo prologue_info(-1, -1);
return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
prologue_info);
}
FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
@ -2326,8 +2328,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
/* argument_count = */ 2, ICData::kNSMDispatch);
body += Return(TokenPosition::kNoSource);
return new (Z)
FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_);
PrologueInfo prologue_info(-1, -1);
return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
prologue_info);
}
FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
@ -2426,8 +2429,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
body += Return(TokenPosition::kNoSource);
return new (Z)
FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_);
PrologueInfo prologue_info(-1, -1);
return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
prologue_info);
}
TargetEntryInstr* BaseFlowGraphBuilder::BuildTargetEntry() {

View file

@ -165,6 +165,7 @@ static void EmitCodeFor(FlowGraphCompiler* compiler, FlowGraph* graph) {
bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
FlowGraphCompiler* compiler) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(!parsed_function.function().HasOptionalParameters());
ZoneGrowableArray<const ICData*>* ic_data_array =
new ZoneGrowableArray<const ICData*>();
FlowGraphBuilder builder(parsed_function, *ic_data_array,
@ -177,7 +178,9 @@ bool Intrinsifier::GraphIntrinsify(const ParsedFunction& parsed_function,
Thread::Current()->GetNextDeoptId());
GraphEntryInstr* graph_entry = new GraphEntryInstr(
parsed_function, normal_entry, Compiler::kNoOSRDeoptId);
FlowGraph* graph = new FlowGraph(parsed_function, graph_entry, block_id);
PrologueInfo prologue_info(-1, -1);
FlowGraph* graph =
new FlowGraph(parsed_function, graph_entry, block_id, prologue_info);
const Function& function = parsed_function.function();
switch (function.recognized_kind()) {
#define EMIT_CASE(class_name, function_name, enum_name, type, fp) \

View file

@ -241,9 +241,9 @@ FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph(
if (osr_id != Compiler::kNoOSRDeoptId) {
result.graph_entry->RelinkToOsrEntry(zone, result.num_blocks);
}
return new (zone)
FlowGraph(*parsed_function, result.graph_entry, result.num_blocks);
PrologueInfo prologue_info(-1, -1);
return new (zone) FlowGraph(*parsed_function, result.graph_entry,
result.num_blocks, prologue_info);
}
void IrregexpCompilationPipeline::FinalizeCompilation(FlowGraph* flow_graph) {