Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(408)

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 11953076: Move code around in preparation for better inlining. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/flow_graph_builder.h" 5 #include "vm/flow_graph_builder.h"
6 6
7 #include "vm/ast_printer.h" 7 #include "vm/ast_printer.h"
8 #include "vm/code_descriptors.h" 8 #include "vm/code_descriptors.h"
9 #include "vm/dart_entry.h" 9 #include "vm/dart_entry.h"
10 #include "vm/flags.h" 10 #include "vm/flags.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 last_used_try_index_(CatchClauseNode::kInvalidTryIndex), 53 last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
54 try_index_(CatchClauseNode::kInvalidTryIndex), 54 try_index_(CatchClauseNode::kInvalidTryIndex),
55 graph_entry_(NULL) { } 55 graph_entry_(NULL) { }
56 56
57 57
58 void FlowGraphBuilder::AddCatchEntry(TargetEntryInstr* entry) { 58 void FlowGraphBuilder::AddCatchEntry(TargetEntryInstr* entry) {
59 graph_entry_->AddCatchEntry(entry); 59 graph_entry_->AddCatchEntry(entry);
60 } 60 }
61 61
62 62
63 InliningContext* InliningContext::Create(Definition* call) {
srdjan 2013/01/24 18:09:51 Why the argument call?
64 return new ValueInliningContext();
65 }
66
67
68 void InliningContext::PrepareGraphs(FlowGraph* caller_graph,
69 Definition* call,
70 FlowGraph* callee_graph) {
71 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1);
72 ASSERT(callee_graph->max_block_id() > caller_graph->max_block_id());
73 ASSERT(callee_graph->max_virtual_register_number() >
74 caller_graph->max_virtual_register_number());
75
76 // Adjust the caller's maximum block id and current SSA temp index.
77 caller_graph->set_max_block_id(callee_graph->max_block_id());
78 caller_graph->set_current_ssa_temp_index(
79 callee_graph->max_virtual_register_number());
80
81 // Attach the outer environment on each instruction in the callee graph.
82 for (BlockIterator block_it = callee_graph->postorder_iterator();
83 !block_it.Done();
84 block_it.Advance()) {
85 for (ForwardInstructionIterator it(block_it.Current());
86 !it.Done();
87 it.Advance()) {
88 Instruction* instr = it.Current();
89 // TODO(zerny): Avoid creating unnecessary environments. Note that some
90 // optimizations need deoptimization info for non-deoptable instructions,
91 // eg, LICM on GOTOs.
92 if (instr->env() != NULL) call->env()->DeepCopyToOuter(instr);
93 }
94 }
95 }
96
97
63 void ValueInliningContext::AddExit(ReturnInstr* exit) { 98 void ValueInliningContext::AddExit(ReturnInstr* exit) {
64 Data data = { NULL, exit }; 99 Data data = { NULL, exit };
65 exits_.Add(data); 100 exits_.Add(data);
66 } 101 }
67 102
68 103
69 int ValueInliningContext::LowestBlockIdFirst(const Data* a, const Data* b) { 104 int ValueInliningContext::LowestBlockIdFirst(const Data* a, const Data* b) {
70 return (a->exit_block->block_id() - b->exit_block->block_id()); 105 return (a->exit_block->block_id() - b->exit_block->block_id());
71 } 106 }
72 107
73 108
74 void ValueInliningContext::SortExits() { 109 void ValueInliningContext::SortExits() {
75 // Assign block entries here because we did not necessarily know them when 110 // Assign block entries here because we did not necessarily know them when
76 // the return exit was added to the array. 111 // the return exit was added to the array.
77 for (int i = 0; i < exits_.length(); ++i) { 112 for (int i = 0; i < exits_.length(); ++i) {
78 exits_[i].exit_block = exits_[i].exit_return->GetBlock(); 113 exits_[i].exit_block = exits_[i].exit_return->GetBlock();
79 } 114 }
80 exits_.Sort(LowestBlockIdFirst); 115 exits_.Sort(LowestBlockIdFirst);
81 } 116 }
82 117
83 118
119 void ValueInliningContext::ReplaceCall(FlowGraph* caller_graph,
120 Definition* call,
121 FlowGraph* callee_graph) {
122 ASSERT(call->previous() != NULL);
123 ASSERT(call->next() != NULL);
124 PrepareGraphs(caller_graph, call, callee_graph);
125
126 BlockEntryInstr* caller_entry = call->GetBlock();
127 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry();
128
129 // Insert the callee graph into the caller graph. First sort the list of
130 // exits by block id (recording block entries as a side effect).
131 SortExits();
132 intptr_t num_exits = exits_.length();
133 if (num_exits == 0) {
134 // TODO(zerny): Add support for non-local exits, such as throw.
135 UNREACHABLE();
136 } else if (num_exits == 1) {
137 // For just one exit, replace the uses and remove the call from the graph.
138 call->ReplaceUsesWith(ValueAt(0)->definition());
139 call->previous()->LinkTo(callee_entry->next());
140 LastInstructionAt(0)->LinkTo(call->next());
141 // In case of control flow, locally update the predecessors, phis and
142 // dominator tree.
143 // TODO(zerny): should we leave the dominator tree since we recompute it
144 // after a full inlining pass?
145 if (callee_graph->preorder().length() > 2) {
146 BlockEntryInstr* exit_block = ExitBlockAt(0);
147 // Pictorially, the graph structure is:
148 //
149 // Bc : caller_entry Bi : callee_entry
150 // before_call inlined_head
151 // call ... other blocks ...
152 // after_call Be : exit_block
153 // inlined_foot
154 // And becomes:
155 //
156 // Bc : caller_entry
157 // before_call
158 // inlined_head
159 // ... other blocks ...
160 // Be : exit_block
161 // inlined_foot
162 // after_call
163 //
164 // For 'after_call', caller entry (Bc) is replaced by callee exit (Be).
165 caller_entry->ReplaceAsPredecessorWith(exit_block);
166 // For 'inlined_head', callee entry (Bi) is replaced by caller entry (Bc).
167 callee_entry->ReplaceAsPredecessorWith(caller_entry);
168 // The callee exit is now the immediate dominator of blocks whose
169 // immediate dominator was the caller entry.
170 ASSERT(exit_block->dominated_blocks().is_empty());
171 for (intptr_t i = 0; i < caller_entry->dominated_blocks().length(); ++i) {
172 BlockEntryInstr* block = caller_entry->dominated_blocks()[i];
173 block->set_dominator(exit_block);
174 exit_block->AddDominatedBlock(block);
175 }
176 // The caller entry is now the immediate dominator of blocks whose
177 // immediate dominator was the callee entry.
178 caller_entry->ClearDominatedBlocks();
179 for (intptr_t i = 0; i < callee_entry->dominated_blocks().length(); ++i) {
180 BlockEntryInstr* block = callee_entry->dominated_blocks()[i];
181 block->set_dominator(caller_entry);
182 caller_entry->AddDominatedBlock(block);
183 }
184 }
185 } else {
186 // Create a join of the returns.
187 intptr_t join_id = caller_graph->max_block_id() + 1;
188 caller_graph->set_max_block_id(join_id);
189 JoinEntryInstr* join =
190 new JoinEntryInstr(join_id, CatchClauseNode::kInvalidTryIndex);
191 for (intptr_t i = 0; i < num_exits; ++i) {
192 LastInstructionAt(i)->Goto(join);
193 // Directly add the predecessors of the join in ascending block id order.
194 join->predecessors_.Add(ExitBlockAt(i));
195 }
196 // If the call has uses, create a phi of the returns.
197 if (call->HasUses()) {
198 // Environment count: length before call - argument count (+ return)
199 intptr_t env_count = call->env()->Length() - call->ArgumentCount();
200 // Add a phi of the return values.
201 join->InsertPhi(env_count, env_count + 1);
202 PhiInstr* phi = join->phis()->Last();
203 phi->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index());
204 phi->mark_alive();
205 for (intptr_t i = 0; i < num_exits; ++i) {
206 Value* value = ValueAt(i);
207 phi->SetInputAt(i, value);
208 value->set_instruction(phi);
209 value->set_use_index(i);
210 }
211 // Replace uses of the call with the phi.
212 call->ReplaceUsesWith(phi);
213 }
214 // Remove the call from the graph.
215 call->previous()->LinkTo(callee_entry->next());
216 join->LinkTo(call->next());
217 // Replace the blocks after splitting (see comment in the len=1 case above).
218 caller_entry->ReplaceAsPredecessorWith(join);
219 callee_entry->ReplaceAsPredecessorWith(caller_entry);
220 // Update the last instruction pointers on each exit block to the new goto.
221 for (intptr_t i = 0; i < num_exits; ++i) {
222 ExitBlockAt(i)->set_last_instruction(LastInstructionAt(i)->next());
223 }
224 // Mark that the dominator tree is invalid.
225 // TODO(zerny): Compute the dominator frontier locally.
226 caller_graph->InvalidateDominatorTree();
227 }
228 }
229
230
84 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { 231 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) {
85 ASSERT(is_open()); 232 ASSERT(is_open());
86 if (other_fragment.is_empty()) return; 233 if (other_fragment.is_empty()) return;
87 if (is_empty()) { 234 if (is_empty()) {
88 entry_ = other_fragment.entry(); 235 entry_ = other_fragment.entry();
89 exit_ = other_fragment.exit(); 236 exit_ = other_fragment.exit();
90 } else { 237 } else {
91 exit()->LinkTo(other_fragment.entry()); 238 exit()->LinkTo(other_fragment.entry());
92 exit_ = other_fragment.exit(); 239 exit_ = other_fragment.exit();
93 } 240 }
(...skipping 2956 matching lines...) Expand 10 before | Expand all | Expand 10 after
3050 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; 3197 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
3051 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len); 3198 char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
3052 OS::SNPrint(chars, len, kFormat, function_name, reason); 3199 OS::SNPrint(chars, len, kFormat, function_name, reason);
3053 const Error& error = Error::Handle( 3200 const Error& error = Error::Handle(
3054 LanguageError::New(String::Handle(String::New(chars)))); 3201 LanguageError::New(String::Handle(String::New(chars))));
3055 Isolate::Current()->long_jump_base()->Jump(1, error); 3202 Isolate::Current()->long_jump_base()->Jump(1, error);
3056 } 3203 }
3057 3204
3058 3205
3059 } // namespace dart 3206 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698