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

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

Issue 10996057: Instruction size and growth threshold for inlining. (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.cc ('k') | no next file » | 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");
22 DECLARE_FLAG(bool, print_flow_graph); 26 DECLARE_FLAG(bool, print_flow_graph);
23 DECLARE_FLAG(int, deoptimization_counter_threshold); 27 DECLARE_FLAG(int, deoptimization_counter_threshold);
24 28
25 #define TRACE_INLINING(statement) \ 29 #define TRACE_INLINING(statement) \
26 do { \ 30 do { \
27 if (FLAG_trace_inlining) statement; \ 31 if (FLAG_trace_inlining) statement; \
28 } while (false) 32 } while (false)
29 33
30 34
31 // Test if a call is recursive by looking in the deoptimization environment. 35 // Test if a call is recursive by looking in the deoptimization environment.
32 static bool IsCallRecursive(const Function& function, Definition* call) { 36 static bool IsCallRecursive(const Function& function, Definition* call) {
33 Environment* env = call->env(); 37 Environment* env = call->env();
34 while (env != NULL) { 38 while (env != NULL) {
35 if (function.raw() == env->function().raw()) return true; 39 if (function.raw() == env->function().raw()) return true;
36 env = env->outer(); 40 env = env->outer();
37 } 41 }
38 return false; 42 return false;
39 } 43 }
40 44
41 45
42 class CallSiteInliner : public FlowGraphVisitor { 46 class CallSiteInliner : public FlowGraphVisitor {
43 public: 47 public:
44 explicit CallSiteInliner(FlowGraph* flow_graph) 48 explicit CallSiteInliner(FlowGraph* flow_graph)
45 : FlowGraphVisitor(flow_graph->postorder()), 49 : FlowGraphVisitor(flow_graph->postorder()),
46 caller_graph_(flow_graph), 50 caller_graph_(flow_graph),
47 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), 51 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
48 inlined_(false), 52 inlined_(false),
53 initial_size_(flow_graph->InstructionCount()),
54 inlined_size_(0),
49 static_calls_(), 55 static_calls_(),
50 closure_calls_(), 56 closure_calls_(),
51 instance_calls_() { } 57 instance_calls_() { }
52 58
53 void VisitClosureCall(ClosureCallInstr* call) { 59 void VisitClosureCall(ClosureCallInstr* call) {
54 closure_calls_.Add(call); 60 closure_calls_.Add(call);
55 } 61 }
56 62
57 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { 63 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
58 instance_calls_.Add(call); 64 instance_calls_.Add(call);
59 } 65 }
60 66
61 void VisitStaticCall(StaticCallInstr* call) { 67 void VisitStaticCall(StaticCallInstr* call) {
62 if (call->function().is_inlinable()) static_calls_.Add(call); 68 if (call->function().is_inlinable()) static_calls_.Add(call);
63 } 69 }
64 70
65 void FindCallSites() { 71 void FindCallSites() {
66 VisitBlocks(); 72 VisitBlocks();
67 } 73 }
68 74
69 void InlineCalls() { 75 void InlineCalls() {
70 InlineStaticCalls(); 76 InlineStaticCalls();
71 InlineClosureCalls(); 77 InlineClosureCalls();
72 InlineInstanceCalls(); 78 InlineInstanceCalls();
73 } 79 }
74 80
75 bool inlined() const { return inlined_; } 81 bool inlined() const { return inlined_; }
76 82
83 double GrowthFactor() const {
84 return static_cast<double>(inlined_size_) /
85 static_cast<double>(initial_size_);
86 }
87
77 private: 88 private:
78 bool TryInlining(const Function& function, 89 bool TryInlining(const Function& function,
79 GrowableArray<Value*>* arguments, 90 GrowableArray<Value*>* arguments,
80 Definition* call) { 91 Definition* call) {
81 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); 92 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString()));
82 93
83 // Abort if the inlinable bit on the function is low. 94 // Abort if the inlinable bit on the function is low.
84 if (!function.is_inlinable()) { 95 if (!function.is_inlinable()) {
85 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 96 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
86 return false; 97 return false;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 optimizer.ApplyICData(); 161 optimizer.ApplyICData();
151 callee_graph->ComputeUseLists(); 162 callee_graph->ComputeUseLists();
152 163
153 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 164 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
154 OS::Print("Callee graph for inlining %s\n", 165 OS::Print("Callee graph for inlining %s\n",
155 parsed_function.function().ToFullyQualifiedCString()); 166 parsed_function.function().ToFullyQualifiedCString());
156 FlowGraphPrinter printer(*callee_graph); 167 FlowGraphPrinter printer(*callee_graph);
157 printer.PrintBlocks(); 168 printer.PrintBlocks();
158 } 169 }
159 170
160 // TODO(zerny): If result is more than size threshold then abort. 171 // 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 }
161 196
162 // TODO(zerny): If effort is less than threshold then inline recursively. 197 // TODO(zerny): If effort is less than threshold then inline recursively.
163 198
164 // Plug result in the caller graph. 199 // Plug result in the caller graph.
165 caller_graph_->InlineCall(call, callee_graph); 200 caller_graph_->InlineCall(call, callee_graph);
166 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 201 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
167 202
168 // Remove push arguments of the call. 203 // Remove push arguments of the call.
169 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 204 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
170 PushArgumentInstr* push = call->ArgumentAt(i); 205 PushArgumentInstr* push = call->ArgumentAt(i);
(...skipping 17 matching lines...) Expand all
188 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( 223 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
189 caller_graph_->graph_entry()->constant_null()); 224 caller_graph_->graph_entry()->constant_null());
190 225
191 TRACE_INLINING(OS::Print(" Success\n")); 226 TRACE_INLINING(OS::Print(" Success\n"));
192 227
193 // Check that inlining maintains use lists. 228 // Check that inlining maintains use lists.
194 DEBUG_ASSERT(caller_graph_->ValidateUseLists()); 229 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
195 230
196 // Build succeeded so we restore the bailout jump. 231 // Build succeeded so we restore the bailout jump.
197 inlined_ = true; 232 inlined_ = true;
233 inlined_size_ += size;
198 isolate->set_long_jump_base(base); 234 isolate->set_long_jump_base(base);
199 isolate->set_deopt_id(prev_deopt_id); 235 isolate->set_deopt_id(prev_deopt_id);
200 isolate->set_ic_data_array(prev_ic_data.raw()); 236 isolate->set_ic_data_array(prev_ic_data.raw());
201 return true; 237 return true;
202 } else { 238 } else {
203 Error& error = Error::Handle(); 239 Error& error = Error::Handle();
204 error = isolate->object_store()->sticky_error(); 240 error = isolate->object_store()->sticky_error();
205 isolate->object_store()->clear_sticky_error(); 241 isolate->object_store()->clear_sticky_error();
206 isolate->set_long_jump_base(base); 242 isolate->set_long_jump_base(base);
207 isolate->set_deopt_id(prev_deopt_id); 243 isolate->set_deopt_id(prev_deopt_id);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 } 282 }
247 283
248 void InlineInstanceCalls() { 284 void InlineInstanceCalls() {
249 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", 285 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n",
250 instance_calls_.length())); 286 instance_calls_.length()));
251 for (intptr_t i = 0; i < instance_calls_.length(); ++i) { 287 for (intptr_t i = 0; i < instance_calls_.length(); ++i) {
252 PolymorphicInstanceCallInstr* instr = instance_calls_[i]; 288 PolymorphicInstanceCallInstr* instr = instance_calls_[i];
253 const ICData& ic_data = instr->ic_data(); 289 const ICData& ic_data = instr->ic_data();
254 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 290 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
255 if (instr->with_checks()) { 291 if (instr->with_checks()) {
256 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n", 292 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n",
257 ic_data.NumberOfChecks(), 293 ic_data.NumberOfChecks(),
258 target.ToCString())); 294 target.ToCString()));
259 continue; 295 continue;
260 } 296 }
261 GrowableArray<Value*> arguments(instr->ArgumentCount()); 297 GrowableArray<Value*> arguments(instr->ArgumentCount());
262 for (int i = 0; i < instr->ArgumentCount(); ++i) { 298 for (int i = 0; i < instr->ArgumentCount(); ++i) {
263 arguments.Add(instr->ArgumentAt(i)->value()); 299 arguments.Add(instr->ArgumentAt(i)->value());
264 } 300 }
265 TryInlining(target, &arguments, instr); 301 TryInlining(target, &arguments, instr);
266 } 302 }
267 } 303 }
268 304
269 FlowGraph* caller_graph_; 305 FlowGraph* caller_graph_;
270 intptr_t next_ssa_temp_index_; 306 intptr_t next_ssa_temp_index_;
271 bool inlined_; 307 bool inlined_;
308 intptr_t initial_size_;
309 intptr_t inlined_size_;
272 310
273 GrowableArray<StaticCallInstr*> static_calls_; 311 GrowableArray<StaticCallInstr*> static_calls_;
274 GrowableArray<ClosureCallInstr*> closure_calls_; 312 GrowableArray<ClosureCallInstr*> closure_calls_;
275 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_; 313 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_;
276 }; 314 };
277 315
278 316
279 void FlowGraphInliner::Inline() { 317 void FlowGraphInliner::Inline() {
280 if ((FLAG_inlining_filter != NULL) && 318 if ((FLAG_inlining_filter != NULL) &&
281 (strstr(flow_graph_-> 319 (strstr(flow_graph_->
(...skipping 11 matching lines...) Expand all
293 parsed_function().function().ToFullyQualifiedCString()); 331 parsed_function().function().ToFullyQualifiedCString());
294 FlowGraphPrinter printer(*flow_graph_); 332 FlowGraphPrinter printer(*flow_graph_);
295 printer.PrintBlocks(); 333 printer.PrintBlocks();
296 } 334 }
297 335
298 CallSiteInliner inliner(flow_graph_); 336 CallSiteInliner inliner(flow_graph_);
299 inliner.FindCallSites(); 337 inliner.FindCallSites();
300 inliner.InlineCalls(); 338 inliner.InlineCalls();
301 339
302 if (inliner.inlined()) { 340 if (inliner.inlined()) {
303 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 341 if (FLAG_trace_inlining) {
304 OS::Print("After Inlining of %s\n", flow_graph_-> 342 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
305 parsed_function().function().ToFullyQualifiedCString()); 343 if (FLAG_print_flow_graph) {
306 FlowGraphPrinter printer(*flow_graph_); 344 OS::Print("After Inlining of %s\n", flow_graph_->
307 printer.PrintBlocks(); 345 parsed_function().function().ToFullyQualifiedCString());
346 FlowGraphPrinter printer(*flow_graph_);
347 printer.PrintBlocks();
348 }
308 } 349 }
309 } 350 }
310 } 351 }
311 352
312 } // namespace dart 353 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698