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

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

Issue 10979078: Revert several inlining related changes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 2 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.cc ('k') | runtime/vm/il_printer.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_inliner.h" 5 #include "vm/flow_graph_inliner.h"
6 6
7 #include "vm/compiler.h" 7 #include "vm/compiler.h"
8 #include "vm/flags.h" 8 #include "vm/flags.h"
9 #include "vm/flow_graph.h" 9 #include "vm/flow_graph.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
11 #include "vm/flow_graph_optimizer.h" 11 #include "vm/flow_graph_optimizer.h"
12 #include "vm/il_printer.h" 12 #include "vm/il_printer.h"
13 #include "vm/intrinsifier.h" 13 #include "vm/intrinsifier.h"
14 #include "vm/longjump.h" 14 #include "vm/longjump.h"
15 #include "vm/object.h" 15 #include "vm/object.h"
16 #include "vm/object_store.h" 16 #include "vm/object_store.h"
17 17
18 namespace dart { 18 namespace dart {
19 19
20 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); 20 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining");
21 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); 21 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
22 DEFINE_FLAG(int, inlining_size_threshold, 250,
23 "Inline only functions with up to threshold instructions");
24 DEFINE_FLAG(int, inlining_growth_factor, 3,
25 "Stop inlining when a function grows by the factor");
26 DECLARE_FLAG(bool, print_flow_graph); 22 DECLARE_FLAG(bool, print_flow_graph);
27 DECLARE_FLAG(int, deoptimization_counter_threshold); 23 DECLARE_FLAG(int, deoptimization_counter_threshold);
28 24
29 #define TRACE_INLINING(statement) \ 25 #define TRACE_INLINING(statement) \
30 do { \ 26 do { \
31 if (FLAG_trace_inlining) statement; \ 27 if (FLAG_trace_inlining) statement; \
32 } while (false) 28 } while (false)
33 29
34 30
35 // Test if a call is recursive by looking in the deoptimization environment. 31 // Test if a call is recursive by looking in the deoptimization environment.
36 static bool IsCallRecursive(const Function& function, Definition* call) { 32 static bool IsCallRecursive(const Function& function, Definition* call) {
37 Environment* env = call->env(); 33 Environment* env = call->env();
38 while (env != NULL) { 34 while (env != NULL) {
39 if (function.raw() == env->function().raw()) return true; 35 if (function.raw() == env->function().raw()) return true;
40 env = env->outer(); 36 env = env->outer();
41 } 37 }
42 return false; 38 return false;
43 } 39 }
44 40
45 41
46 class CallSiteInliner : public FlowGraphVisitor { 42 class CallSiteInliner : public FlowGraphVisitor {
47 public: 43 public:
48 explicit CallSiteInliner(FlowGraph* flow_graph) 44 explicit CallSiteInliner(FlowGraph* flow_graph)
49 : FlowGraphVisitor(flow_graph->postorder()), 45 : FlowGraphVisitor(flow_graph->postorder()),
50 caller_graph_(flow_graph), 46 caller_graph_(flow_graph),
51 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), 47 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
52 inlined_(false), 48 inlined_(false) { }
53 initial_size_(flow_graph->InstructionCount()),
54 inlined_size_(0),
55 static_calls_(),
56 closure_calls_(),
57 instance_calls_() { }
58 49
59 void VisitClosureCall(ClosureCallInstr* call) {
60 closure_calls_.Add(call);
61 }
62
63 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
64 instance_calls_.Add(call);
65 }
66
67 void VisitStaticCall(StaticCallInstr* call) {
68 if (call->function().is_inlinable()) static_calls_.Add(call);
69 }
70
71 void FindCallSites() {
72 VisitBlocks();
73 }
74
75 void InlineCalls() {
76 InlineStaticCalls();
77 InlineClosureCalls();
78 InlineInstanceCalls();
79 }
80
81 bool inlined() const { return inlined_; }
82
83 double GrowthFactor() const {
84 return static_cast<double>(inlined_size_) /
85 static_cast<double>(initial_size_);
86 }
87
88 private:
89 bool TryInlining(const Function& function, 50 bool TryInlining(const Function& function,
90 GrowableArray<Value*>* arguments, 51 GrowableArray<Value*>* arguments,
91 Definition* call) { 52 Definition* call) {
92 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); 53 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString()));
93 54
94 // Abort if the inlinable bit on the function is low. 55 // Abort if the inlinable bit on the function is low.
95 if (!function.is_inlinable()) { 56 if (!function.is_inlinable()) {
96 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 57 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
97 return false; 58 return false;
98 } 59 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 if ((function.deoptimization_counter() < 102 if ((function.deoptimization_counter() <
142 FLAG_deoptimization_counter_threshold) && 103 FLAG_deoptimization_counter_threshold) &&
143 function.HasCode()) { 104 function.HasCode()) {
144 const Code& unoptimized_code = 105 const Code& unoptimized_code =
145 Code::Handle(function.unoptimized_code()); 106 Code::Handle(function.unoptimized_code());
146 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); 107 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
147 } 108 }
148 109
149 // Build the callee graph. 110 // Build the callee graph.
150 FlowGraphBuilder builder(parsed_function); 111 FlowGraphBuilder builder(parsed_function);
151 builder.SetInitialBlockId(caller_graph_->max_block_id());
152 FlowGraph* callee_graph = 112 FlowGraph* callee_graph =
153 builder.BuildGraph(FlowGraphBuilder::kValueContext); 113 builder.BuildGraph(FlowGraphBuilder::kValueContext);
154 114
115 // Abort if the callee graph contains control flow.
116 if (callee_graph->preorder().length() != 2) {
117 function.set_is_inlinable(false);
118 isolate->set_long_jump_base(base);
119 isolate->set_ic_data_array(prev_ic_data.raw());
120 TRACE_INLINING(OS::Print(" Bailout: control flow\n"));
121 return false;
122 }
123
155 // Compute SSA on the callee graph, catching bailouts. 124 // Compute SSA on the callee graph, catching bailouts.
156 callee_graph->ComputeSSA(next_ssa_temp_index_); 125 callee_graph->ComputeSSA(next_ssa_temp_index_);
157 callee_graph->ComputeUseLists(); 126 callee_graph->ComputeUseLists();
158 127
159 // TODO(zerny): Do more optimization passes on the callee graph. 128 // TODO(zerny): Do more optimization passes on the callee graph.
160 FlowGraphOptimizer optimizer(callee_graph); 129 FlowGraphOptimizer optimizer(callee_graph);
161 optimizer.ApplyICData(); 130 optimizer.ApplyICData();
162 callee_graph->ComputeUseLists(); 131 callee_graph->ComputeUseLists();
163 132
164 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 133 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
165 OS::Print("Callee graph for inlining %s\n", 134 OS::Print("Callee graph for inlining %s\n",
166 parsed_function.function().ToFullyQualifiedCString()); 135 parsed_function.function().ToFullyQualifiedCString());
167 FlowGraphPrinter printer(*callee_graph); 136 FlowGraphPrinter printer(*callee_graph);
168 printer.PrintBlocks(); 137 printer.PrintBlocks();
169 } 138 }
170 139
171 // If result is more than size threshold then abort. 140 // TODO(zerny): If result is more than size threshold then abort.
172 // TODO(zerny): Do this after CP and dead code elimination.
173 intptr_t size = callee_graph->InstructionCount();
174 if (size > FLAG_inlining_size_threshold) {
175 function.set_is_inlinable(false);
176 isolate->set_long_jump_base(base);
177 isolate->set_deopt_id(prev_deopt_id);
178 isolate->set_ic_data_array(prev_ic_data.raw());
179 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size));
180 return false;
181 }
182
183 // If the growth factor is more than threshold abort.
184 double growth =
185 static_cast<double>(inlined_size_ + size) /
186 static_cast<double>(initial_size_);
187 if (growth > static_cast<double>(FLAG_inlining_growth_factor)) {
188 function.set_is_inlinable(false);
189 isolate->set_long_jump_base(base);
190 isolate->set_deopt_id(prev_deopt_id);
191 isolate->set_ic_data_array(prev_ic_data.raw());
192 TRACE_INLINING(OS::Print(" Bailout: growth factor %f\n",
193 growth));
194 return false;
195 }
196 141
197 // TODO(zerny): If effort is less than threshold then inline recursively. 142 // TODO(zerny): If effort is less than threshold then inline recursively.
198 143
199 // Plug result in the caller graph. 144 // Plug result in the caller graph.
200 caller_graph_->InlineCall(call, callee_graph); 145 caller_graph_->InlineCall(call, callee_graph);
201 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 146 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
202 147
148 // Check that inlining maintains use lists.
149 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
150
203 // Remove push arguments of the call. 151 // Remove push arguments of the call.
204 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 152 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
205 PushArgumentInstr* push = call->ArgumentAt(i); 153 PushArgumentInstr* push = call->ArgumentAt(i);
206 push->ReplaceUsesWith(push->value()->definition()); 154 push->ReplaceUsesWith(push->value()->definition());
207 push->RemoveFromGraph(); 155 push->RemoveFromGraph();
208 } 156 }
209 157
210 // Replace formal parameters with actuals. 158 // Replace formal parameters with actuals.
211 intptr_t arg_index = 0; 159 intptr_t arg_index = 0;
212 GrowableArray<Definition*>* defns = 160 GrowableArray<Definition*>* defns =
213 callee_graph->graph_entry()->initial_definitions(); 161 callee_graph->graph_entry()->initial_definitions();
214 for (intptr_t i = 0; i < defns->length(); ++i) { 162 for (intptr_t i = 0; i < defns->length(); ++i) {
215 ParameterInstr* param = (*defns)[i]->AsParameter(); 163 ParameterInstr* param = (*defns)[i]->AsParameter();
216 if (param != NULL) { 164 if (param != NULL) {
217 param->ReplaceUsesWith((*arguments)[arg_index++]->definition()); 165 param->ReplaceUsesWith((*arguments)[arg_index++]->definition());
218 } 166 }
219 } 167 }
220 ASSERT(arg_index == arguments->length()); 168 ASSERT(arg_index == arguments->length());
221 169
222 // Replace callee's null constant with caller's null constant. 170 // Replace callee's null constant with caller's null constant.
223 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( 171 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
224 caller_graph_->graph_entry()->constant_null()); 172 caller_graph_->graph_entry()->constant_null());
225 173
226 TRACE_INLINING(OS::Print(" Success\n")); 174 TRACE_INLINING(OS::Print(" Success\n"));
227 175
228 // Check that inlining maintains use lists.
229 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
230
231 // Build succeeded so we restore the bailout jump. 176 // Build succeeded so we restore the bailout jump.
232 inlined_ = true; 177 inlined_ = true;
233 inlined_size_ += size;
234 isolate->set_long_jump_base(base); 178 isolate->set_long_jump_base(base);
235 isolate->set_deopt_id(prev_deopt_id); 179 isolate->set_deopt_id(prev_deopt_id);
236 isolate->set_ic_data_array(prev_ic_data.raw()); 180 isolate->set_ic_data_array(prev_ic_data.raw());
237 return true; 181 return true;
238 } else { 182 } else {
239 Error& error = Error::Handle(); 183 Error& error = Error::Handle();
240 error = isolate->object_store()->sticky_error(); 184 error = isolate->object_store()->sticky_error();
241 isolate->object_store()->clear_sticky_error(); 185 isolate->object_store()->clear_sticky_error();
242 isolate->set_long_jump_base(base); 186 isolate->set_long_jump_base(base);
243 isolate->set_deopt_id(prev_deopt_id); 187 isolate->set_deopt_id(prev_deopt_id);
244 isolate->set_ic_data_array(prev_ic_data.raw()); 188 isolate->set_ic_data_array(prev_ic_data.raw());
245 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 189 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
246 return false; 190 return false;
247 } 191 }
248 } 192 }
249 193
250 void InlineStaticCalls() { 194 void VisitClosureCall(ClosureCallInstr* call) {
251 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", 195 TRACE_INLINING(OS::Print(" ClosureCall\n"));
252 static_calls_.length())); 196 // Find the closure of the callee.
253 for (intptr_t i = 0; i < static_calls_.length(); ++i) { 197 ASSERT(call->ArgumentCount() > 0);
254 StaticCallInstr* call = static_calls_[i]; 198 const CreateClosureInstr* closure =
255 GrowableArray<Value*> arguments(call->ArgumentCount()); 199 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
256 for (int i = 0; i < call->ArgumentCount(); ++i) { 200 if (closure == NULL) {
257 arguments.Add(call->ArgumentAt(i)->value()); 201 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
258 } 202 return;
259 TryInlining(call->function(), &arguments, call);
260 } 203 }
204 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
205 for (int i = 1; i < call->ArgumentCount(); ++i) {
206 arguments.Add(call->ArgumentAt(i)->value());
207 }
208 TryInlining(closure->function(), &arguments, call);
261 } 209 }
262 210
263 void InlineClosureCalls() { 211 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* instr) {
264 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", 212 TRACE_INLINING(OS::Print(" PolymorphicInstanceCall\n"));
265 closure_calls_.length())); 213 const ICData& ic_data = instr->ic_data();
266 for (intptr_t i = 0; i < closure_calls_.length(); ++i) { 214 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
267 ClosureCallInstr* call = closure_calls_[i]; 215 if (instr->with_checks()) {
268 // Find the closure of the callee. 216 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n",
269 ASSERT(call->ArgumentCount() > 0); 217 ic_data.NumberOfChecks(),
270 const CreateClosureInstr* closure = 218 target.ToCString()));
271 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); 219 return;
272 if (closure == NULL) {
273 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
274 continue;
275 }
276 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
277 for (int i = 1; i < call->ArgumentCount(); ++i) {
278 arguments.Add(call->ArgumentAt(i)->value());
279 }
280 TryInlining(closure->function(), &arguments, call);
281 } 220 }
221
222 GrowableArray<Value*> arguments(instr->ArgumentCount());
223 for (int i = 0; i < instr->ArgumentCount(); ++i) {
224 arguments.Add(instr->ArgumentAt(i)->value());
225 }
226
227 TryInlining(target, &arguments, instr);
282 } 228 }
283 229
284 void InlineInstanceCalls() { 230 void VisitStaticCall(StaticCallInstr* call) {
285 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", 231 TRACE_INLINING(OS::Print(" StaticCall\n"));
286 instance_calls_.length())); 232 GrowableArray<Value*> arguments(call->ArgumentCount());
287 for (intptr_t i = 0; i < instance_calls_.length(); ++i) { 233 for (int i = 0; i < call->ArgumentCount(); ++i) {
288 PolymorphicInstanceCallInstr* instr = instance_calls_[i]; 234 arguments.Add(call->ArgumentAt(i)->value());
289 const ICData& ic_data = instr->ic_data();
290 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
291 if (instr->with_checks()) {
292 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n",
293 ic_data.NumberOfChecks(),
294 target.ToCString()));
295 continue;
296 }
297 GrowableArray<Value*> arguments(instr->ArgumentCount());
298 for (int i = 0; i < instr->ArgumentCount(); ++i) {
299 arguments.Add(instr->ArgumentAt(i)->value());
300 }
301 TryInlining(target, &arguments, instr);
302 } 235 }
236 TryInlining(call->function(), &arguments, call);
303 } 237 }
304 238
239 bool inlined() const { return inlined_; }
240
241 private:
305 FlowGraph* caller_graph_; 242 FlowGraph* caller_graph_;
306 intptr_t next_ssa_temp_index_; 243 intptr_t next_ssa_temp_index_;
307 bool inlined_; 244 bool inlined_;
308 intptr_t initial_size_;
309 intptr_t inlined_size_;
310
311 GrowableArray<StaticCallInstr*> static_calls_;
312 GrowableArray<ClosureCallInstr*> closure_calls_;
313 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_;
314 }; 245 };
315 246
316 247
317 void FlowGraphInliner::Inline() { 248 void FlowGraphInliner::Inline() {
318 if ((FLAG_inlining_filter != NULL) && 249 if ((FLAG_inlining_filter != NULL) &&
319 (strstr(flow_graph_-> 250 (strstr(flow_graph_->
320 parsed_function().function().ToFullyQualifiedCString(), 251 parsed_function().function().ToFullyQualifiedCString(),
321 FLAG_inlining_filter) == NULL)) { 252 FLAG_inlining_filter) == NULL)) {
322 return; 253 return;
323 } 254 }
324 255
325 TRACE_INLINING(OS::Print( 256 TRACE_INLINING(OS::Print(
326 "Inlining calls in %s\n", 257 "Inlining calls in %s\n",
327 flow_graph_->parsed_function().function().ToCString())); 258 flow_graph_->parsed_function().function().ToCString()));
328 259
329 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 260 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
330 OS::Print("Before Inlining of %s\n", flow_graph_-> 261 OS::Print("Before Inlining of %s\n", flow_graph_->
331 parsed_function().function().ToFullyQualifiedCString()); 262 parsed_function().function().ToFullyQualifiedCString());
332 FlowGraphPrinter printer(*flow_graph_); 263 FlowGraphPrinter printer(*flow_graph_);
333 printer.PrintBlocks(); 264 printer.PrintBlocks();
334 } 265 }
335 266
336 CallSiteInliner inliner(flow_graph_); 267 CallSiteInliner inliner(flow_graph_);
337 inliner.FindCallSites(); 268 inliner.VisitBlocks();
338 inliner.InlineCalls();
339 269
340 if (inliner.inlined()) { 270 if (inliner.inlined()) {
341 if (FLAG_trace_inlining) { 271 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
342 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); 272 OS::Print("After Inlining of %s\n", flow_graph_->
343 if (FLAG_print_flow_graph) { 273 parsed_function().function().ToFullyQualifiedCString());
344 OS::Print("After Inlining of %s\n", flow_graph_-> 274 FlowGraphPrinter printer(*flow_graph_);
345 parsed_function().function().ToFullyQualifiedCString()); 275 printer.PrintBlocks();
346 FlowGraphPrinter printer(*flow_graph_);
347 printer.PrintBlocks();
348 }
349 } 276 }
350 } 277 }
351 } 278 }
352 279
353 } // namespace dart 280 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698