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

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

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