Flutter Engine
The Flutter Engine
Classes | Public Member Functions | List of all members
dart::InlineExitCollector Class Reference

#include <flow_graph_builder.h>

Inheritance diagram for dart::InlineExitCollector:
dart::ZoneAllocated

Public Member Functions

 InlineExitCollector (FlowGraph *caller_graph, Definition *call)
 
void AddExit (DartReturnInstr *exit)
 
void Union (const InlineExitCollector *other)
 
void PrepareGraphs (FlowGraph *callee_graph)
 
void ReplaceCall (BlockEntryInstr *callee_entry)
 
- Public Member Functions inherited from dart::ZoneAllocated
 ZoneAllocated ()
 
void * operator new (size_t size)
 
void * operator new (size_t size, Zone *zone)
 
void operator delete (void *pointer)
 

Detailed Description

Definition at line 24 of file flow_graph_builder.h.

Constructor & Destructor Documentation

◆ InlineExitCollector()

dart::InlineExitCollector::InlineExitCollector ( FlowGraph caller_graph,
Definition call 
)
inline

Definition at line 26 of file flow_graph_builder.h.

27 : caller_graph_(caller_graph), call_(call), exits_(4) {}
def call(args)
Definition: dom.py:159

Member Function Documentation

◆ AddExit()

void dart::InlineExitCollector::AddExit ( DartReturnInstr exit)

Definition at line 94 of file flow_graph_builder.cc.

94 {
95 Data data = {nullptr, exit};
96 exits_.Add(data);
97}
void Add(const T &value)
exit(kErrorExitCode)
static int8_t data[kExtLength]
struct PathData * Data(SkPath *path)
Definition: path_ops.cc:52

◆ PrepareGraphs()

void dart::InlineExitCollector::PrepareGraphs ( FlowGraph callee_graph)

Definition at line 40 of file flow_graph_builder.cc.

40 {
41 COMPILER_TIMINGS_TIMER_SCOPE(callee_graph->thread(), PrepareGraphs);
42 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
43 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id());
44 ASSERT(callee_graph->current_ssa_temp_index() >
45 caller_graph_->current_ssa_temp_index());
46
47 // Adjust the caller's maximum block id and current SSA temp index.
48 caller_graph_->set_max_block_id(callee_graph->max_block_id());
49 caller_graph_->set_current_ssa_temp_index(
50 callee_graph->current_ssa_temp_index());
51
52 // Attach the outer environment on each instruction in the callee graph.
53 ASSERT(call_->env() != nullptr);
54 ASSERT(call_->deopt_id() != DeoptId::kNone);
55
56 auto zone = callee_graph->zone();
57 auto env = call_->env();
58
59 const intptr_t outer_deopt_id = call_->deopt_id();
60 // Scale the edge weights by the call count for the inlined function.
61 double scale_factor = 1.0;
62 if (caller_graph_->graph_entry()->entry_count() != 0) {
63 scale_factor =
64 static_cast<double>(call_->CallCount()) /
65 static_cast<double>(caller_graph_->graph_entry()->entry_count());
66 }
67 for (BlockIterator block_it = callee_graph->postorder_iterator();
68 !block_it.Done(); block_it.Advance()) {
69 BlockEntryInstr* block = block_it.Current();
70 if (block->IsTargetEntry()) {
71 block->AsTargetEntry()->adjust_edge_weight(scale_factor);
72 }
73 Instruction* instr = block;
74 if (block->env() != nullptr) {
75 env->DeepCopyToOuter(zone, block, outer_deopt_id);
76 }
77 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
78 instr = it.Current();
79 // TODO(zerny): Avoid creating unnecessary environments. Note that some
80 // optimizations need deoptimization info for non-deoptable instructions,
81 // eg, LICM on GOTOs.
82 if (instr->env() != nullptr) {
83 env->DeepCopyToOuter(zone, instr, outer_deopt_id);
84 }
85 }
86 if (instr->IsGoto()) {
87 instr->AsGoto()->adjust_edge_weight(scale_factor);
88 }
89 }
90
91 RemoveUnreachableExits(callee_graph);
92}
virtual intptr_t CallCount() const
Definition: il.h:2496
static constexpr intptr_t kNone
Definition: deopt_id.h:27
GraphEntryInstr * graph_entry() const
Definition: flow_graph.h:268
intptr_t current_ssa_temp_index() const
Definition: flow_graph.h:243
void set_current_ssa_temp_index(intptr_t index)
Definition: flow_graph.h:244
intptr_t max_block_id() const
Definition: flow_graph.h:264
void set_max_block_id(intptr_t id)
Definition: flow_graph.h:265
intptr_t entry_count() const
Definition: il.h:1980
void PrepareGraphs(FlowGraph *callee_graph)
Environment * env() const
Definition: il.h:1215
intptr_t deopt_id() const
Definition: il.h:993
#define COMPILER_TIMINGS_TIMER_SCOPE(thread, timer_id)
#define ASSERT(E)
Definition: __init__.py:1

◆ ReplaceCall()

void dart::InlineExitCollector::ReplaceCall ( BlockEntryInstr callee_entry)

Definition at line 242 of file flow_graph_builder.cc.

242 {
243 ASSERT(call_->previous() != nullptr);
244 ASSERT(call_->next() != nullptr);
245 BlockEntryInstr* call_block = call_->GetBlock();
246
247 // Insert the callee graph into the caller graph.
248 BlockEntryInstr* callee_exit = nullptr;
249 Instruction* callee_last_instruction = nullptr;
250
251 if (exits_.length() == 0) {
252 // Handle the case when there are no normal return exits from the callee
253 // (i.e. the callee unconditionally throws) by inserting an artificial
254 // branch (true === true).
255 // The true successor is the inlined body, the false successor
256 // goes to the rest of the caller graph. It is removed as unreachable code
257 // by the constant propagation.
258 TargetEntryInstr* false_block = new (Z) TargetEntryInstr(
259 caller_graph_->allocate_block_id(), call_block->try_index(),
261 false_block->InheritDeoptTargetAfter(caller_graph_, call_, nullptr);
262 false_block->LinkTo(call_->next());
263 call_block->ReplaceAsPredecessorWith(false_block);
264
265 ConstantInstr* true_const = caller_graph_->GetConstant(Bool::True());
266 BranchInstr* branch = new (Z) BranchInstr(
267 new (Z) StrictCompareInstr(InstructionSource(), Token::kEQ_STRICT,
268 new (Z) Value(true_const),
269 new (Z) Value(true_const), false,
270 CompilerState::Current().GetNextDeoptId()),
271 CompilerState::Current().GetNextDeoptId()); // No number check.
272 branch->InheritDeoptTarget(zone(), call_);
273
274 auto true_target = BranchSimplifier::ToTargetEntry(zone(), callee_entry);
275 callee_entry->ReplaceAsPredecessorWith(true_target);
276
277 *branch->true_successor_address() = true_target;
278 *branch->false_successor_address() = false_block;
279
280 call_->previous()->AppendInstruction(branch);
281 call_block->set_last_instruction(branch);
282
283 // Replace uses of the return value with sentinel constant to maintain
284 // valid SSA form - even though the rest of the caller is unreachable.
285 call_->ReplaceUsesWith(caller_graph_->GetConstant(Object::sentinel()));
286
287 // Update dominator tree.
288 for (intptr_t i = 0, n = callee_entry->dominated_blocks().length(); i < n;
289 i++) {
290 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
291 true_target->AddDominatedBlock(block);
292 }
293 for (intptr_t i = 0, n = call_block->dominated_blocks().length(); i < n;
294 i++) {
295 BlockEntryInstr* block = call_block->dominated_blocks()[i];
296 false_block->AddDominatedBlock(block);
297 }
298 call_block->ClearDominatedBlocks();
299 call_block->AddDominatedBlock(true_target);
300 call_block->AddDominatedBlock(false_block);
301
302 } else {
303 Definition* callee_result = JoinReturns(
304 &callee_exit, &callee_last_instruction, call_block->try_index());
305 if (callee_result != nullptr) {
306 call_->ReplaceUsesWith(callee_result);
307 }
308 if (callee_last_instruction == callee_entry) {
309 // There are no instructions in the inlined function (e.g., it might be
310 // a return of a parameter or a return of a constant defined in the
311 // initial definitions).
312 call_->previous()->LinkTo(call_->next());
313 } else {
314 call_->previous()->LinkTo(callee_entry->next());
315 callee_last_instruction->LinkTo(call_->next());
316 }
317 if (callee_exit != callee_entry) {
318 // In case of control flow, locally update the predecessors, phis and
319 // dominator tree.
320 //
321 // Pictorially, the graph structure is:
322 //
323 // Bc : call_block Bi : callee_entry
324 // before_call inlined_head
325 // call ... other blocks ...
326 // after_call Be : callee_exit
327 // inlined_foot
328 // And becomes:
329 //
330 // Bc : call_block
331 // before_call
332 // inlined_head
333 // ... other blocks ...
334 // Be : callee_exit
335 // inlined_foot
336 // after_call
337 //
338 // For successors of 'after_call', the call block (Bc) is replaced as a
339 // predecessor by the callee exit (Be).
340 call_block->ReplaceAsPredecessorWith(callee_exit);
341 // For successors of 'inlined_head', the callee entry (Bi) is replaced
342 // as a predecessor by the call block (Bc).
343 callee_entry->ReplaceAsPredecessorWith(call_block);
344
345 // The callee exit is now the immediate dominator of blocks whose
346 // immediate dominator was the call block.
347 ASSERT(callee_exit->dominated_blocks().is_empty());
348 for (intptr_t i = 0; i < call_block->dominated_blocks().length(); ++i) {
349 BlockEntryInstr* block = call_block->dominated_blocks()[i];
350 callee_exit->AddDominatedBlock(block);
351 }
352 // The call block is now the immediate dominator of blocks whose
353 // immediate dominator was the callee entry.
354 call_block->ClearDominatedBlocks();
355 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
356 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
357 call_block->AddDominatedBlock(block);
358 }
359 }
360
361 // Callee entry in not in the graph anymore. Remove it from use lists.
362 callee_entry->UnuseAllInputs();
363 }
364 // Neither call nor the graph entry (if present) are in the
365 // graph at this point. Remove them from use lists.
366 if (callee_entry->PredecessorCount() > 0) {
367 callee_entry->PredecessorAt(0)->AsGraphEntry()->UnuseAllInputs();
368 }
369 call_->UnuseAllInputs();
370}
intptr_t length() const
static const Bool & True()
Definition: object.h:10797
static TargetEntryInstr * ToTargetEntry(Zone *zone, BlockEntryInstr *target)
intptr_t GetNextDeoptId()
static CompilerState & Current()
void ReplaceUsesWith(Definition *other)
Definition: il.cc:1493
ConstantInstr * GetConstant(const Object &object, Representation representation=kTagged)
Definition: flow_graph.cc:187
intptr_t allocate_block_id()
Definition: flow_graph.h:266
Instruction * next() const
Definition: il.h:1093
void InheritDeoptTargetAfter(FlowGraph *flow_graph, Definition *call, Definition *result)
Definition: il.cc:1558
void LinkTo(Instruction *next)
Definition: il.h:1108
void InheritDeoptTarget(Zone *zone, Instruction *other)
Definition: il.cc:1569
virtual BlockEntryInstr * GetBlock()
Definition: il.cc:1352
Instruction * AppendInstruction(Instruction *tail)
Definition: il.cc:1341
void UnuseAllInputs()
Definition: il.cc:1534
Instruction * previous() const
Definition: il.h:1087
#define Z
size_t length

◆ Union()

void dart::InlineExitCollector::Union ( const InlineExitCollector other)

Definition at line 99 of file flow_graph_builder.cc.

99 {
100 // It doesn't make sense to combine different calls or calls from
101 // different graphs.
102 ASSERT(caller_graph_ == other->caller_graph_);
103 ASSERT(call_ == other->call_);
104 exits_.AddArray(other->exits_);
105}
void AddArray(const BaseGrowableArray< T, B, Allocator > &src)

The documentation for this class was generated from the following files: