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

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

Issue 22839003: Polymorphic inlining for some recognized methods in the optimizing compiler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: fixed modulo performance regression Created 7 years, 4 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_compiler.cc ('k') | runtime/vm/flow_graph_optimizer.h » ('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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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"
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 void Collect(const FlowGraph& graph) { 158 void Collect(const FlowGraph& graph) {
159 call_site_count_ = 0; 159 call_site_count_ = 0;
160 instruction_count_ = 0; 160 instruction_count_ = 0;
161 for (BlockIterator block_it = graph.postorder_iterator(); 161 for (BlockIterator block_it = graph.postorder_iterator();
162 !block_it.Done(); 162 !block_it.Done();
163 block_it.Advance()) { 163 block_it.Advance()) {
164 for (ForwardInstructionIterator it(block_it.Current()); 164 for (ForwardInstructionIterator it(block_it.Current());
165 !it.Done(); 165 !it.Done();
166 it.Advance()) { 166 it.Advance()) {
167 ++instruction_count_; 167 ++instruction_count_;
168 if (it.Current()->IsStaticCall() || 168 Instruction* current = it.Current();
169 it.Current()->IsClosureCall() || 169 if (current->IsStaticCall() ||
170 it.Current()->IsPolymorphicInstanceCall()) { 170 current->IsClosureCall() ||
171 (current->IsPolymorphicInstanceCall() &&
172 !current->AsPolymorphicInstanceCall()->HasRecognizedTarget())) {
171 ++call_site_count_; 173 ++call_site_count_;
172 } 174 }
173 } 175 }
174 } 176 }
175 } 177 }
176 178
177 intptr_t call_site_count() const { return call_site_count_; } 179 intptr_t call_site_count() const { return call_site_count_; }
178 intptr_t instruction_count() const { return instruction_count_; } 180 intptr_t instruction_count() const { return instruction_count_; }
179 181
180 private: 182 private:
181 intptr_t call_site_count_; 183 intptr_t call_site_count_;
182 intptr_t instruction_count_; 184 intptr_t instruction_count_;
183 }; 185 };
184 186
185 187
186 // A collection of call sites to consider for inlining. 188 // A collection of call sites to consider for inlining.
187 class CallSites : public FlowGraphVisitor { 189 class CallSites : public ValueObject {
188 public: 190 public:
189 explicit CallSites(FlowGraph* flow_graph) 191 explicit CallSites(FlowGraph* flow_graph)
190 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. 192 : static_calls_(),
191 static_calls_(),
192 closure_calls_(), 193 closure_calls_(),
193 instance_calls_() { } 194 instance_calls_() { }
194 195
195 const GrowableArray<ClosureCallInstr*>& closure_calls() const { 196 const GrowableArray<ClosureCallInstr*>& closure_calls() const {
196 return closure_calls_; 197 return closure_calls_;
197 } 198 }
198 199
199 struct InstanceCallInfo { 200 struct InstanceCallInfo {
200 PolymorphicInstanceCallInstr* call; 201 PolymorphicInstanceCallInstr* call;
201 double ratio; 202 double ratio;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 0.0 : static_cast<double>(instance_call_counts[i]) / max_count; 263 0.0 : static_cast<double>(instance_call_counts[i]) / max_count;
263 instance_calls_[i + instance_call_start_ix].ratio = ratio; 264 instance_calls_[i + instance_call_start_ix].ratio = ratio;
264 } 265 }
265 for (intptr_t i = 0; i < num_static_calls; ++i) { 266 for (intptr_t i = 0; i < num_static_calls; ++i) {
266 const double ratio = (max_count == 0) ? 267 const double ratio = (max_count == 0) ?
267 0.0 : static_cast<double>(static_call_counts[i]) / max_count; 268 0.0 : static_cast<double>(static_call_counts[i]) / max_count;
268 static_calls_[i + static_call_start_ix].ratio = ratio; 269 static_calls_[i + static_call_start_ix].ratio = ratio;
269 } 270 }
270 } 271 }
271 272
272 void FindCallSites(FlowGraph* graph) { 273 void FindCallSites(FlowGraph* graph, intptr_t depth) {
273 ASSERT(graph != NULL); 274 ASSERT(graph != NULL);
275 // If depth is less than the threshold recursively add call sites.
276 if (depth > FLAG_inlining_depth_threshold) return;
277
278 // Recognized methods are not treated as normal calls. They don't have
279 // calls in themselves, so we keep adding those even when at the threshold.
280 const bool only_recognized_methods =
281 (depth == FLAG_inlining_depth_threshold);
274 282
275 const intptr_t instance_call_start_ix = instance_calls_.length(); 283 const intptr_t instance_call_start_ix = instance_calls_.length();
276 const intptr_t static_call_start_ix = static_calls_.length(); 284 const intptr_t static_call_start_ix = static_calls_.length();
277 for (BlockIterator block_it = graph->postorder_iterator(); 285 for (BlockIterator block_it = graph->postorder_iterator();
278 !block_it.Done(); 286 !block_it.Done();
279 block_it.Advance()) { 287 block_it.Advance()) {
280 for (ForwardInstructionIterator it(block_it.Current()); 288 for (ForwardInstructionIterator it(block_it.Current());
281 !it.Done(); 289 !it.Done();
282 it.Advance()) { 290 it.Advance()) {
283 it.Current()->Accept(this); 291 Instruction* current = it.Current();
292 if (only_recognized_methods) {
293 PolymorphicInstanceCallInstr* instance_call =
294 current->AsPolymorphicInstanceCall();
295 if ((instance_call != NULL) && instance_call->HasRecognizedTarget()) {
296 instance_calls_.Add(InstanceCallInfo(instance_call));
297 }
298 continue;
299 }
300 // Collect all call sites (!only_recognized_methods).
301 ClosureCallInstr* closure_call = current->AsClosureCall();
302 if (closure_call != NULL) {
303 closure_calls_.Add(closure_call);
304 continue;
305 }
306 StaticCallInstr* static_call = current->AsStaticCall();
307 if (static_call != NULL) {
308 if (static_call->function().IsInlineable()) {
309 static_calls_.Add(StaticCallInfo(static_call));
310 }
311 continue;
312 }
313 PolymorphicInstanceCallInstr* instance_call =
314 current->AsPolymorphicInstanceCall();
315 if (instance_call != NULL) {
316 instance_calls_.Add(InstanceCallInfo(instance_call));
317 continue;
318 }
284 } 319 }
285 } 320 }
286 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix); 321 ComputeCallSiteRatio(static_call_start_ix, instance_call_start_ix);
287 } 322 }
288 323
289 void VisitClosureCall(ClosureCallInstr* call) {
290 closure_calls_.Add(call);
291 }
292
293 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
294 instance_calls_.Add(InstanceCallInfo(call));
295 }
296
297 void VisitStaticCall(StaticCallInstr* call) {
298 if (!call->function().IsInlineable()) return;
299 static_calls_.Add(StaticCallInfo(call));
300 }
301
302 private: 324 private:
303 GrowableArray<StaticCallInfo> static_calls_; 325 GrowableArray<StaticCallInfo> static_calls_;
304 GrowableArray<ClosureCallInstr*> closure_calls_; 326 GrowableArray<ClosureCallInstr*> closure_calls_;
305 GrowableArray<InstanceCallInfo> instance_calls_; 327 GrowableArray<InstanceCallInfo> instance_calls_;
306 328
307 DISALLOW_COPY_AND_ASSIGN(CallSites); 329 DISALLOW_COPY_AND_ASSIGN(CallSites);
308 }; 330 };
309 331
310 332
311 struct InlinedCallData { 333 struct InlinedCallData {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && 409 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) &&
388 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { 410 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) {
389 return true; 411 return true;
390 } 412 }
391 if (MethodRecognizer::AlwaysInline(callee)) { 413 if (MethodRecognizer::AlwaysInline(callee)) {
392 return true; 414 return true;
393 } 415 }
394 return false; 416 return false;
395 } 417 }
396 418
397 // TODO(srdjan): Handle large 'skip_static_call_deopt_ids'. Currently
398 // max. size observed is 11 (dart2js).
399 void InlineCalls() { 419 void InlineCalls() {
400 // If inlining depth is less then one abort. 420 // If inlining depth is less then one abort.
401 if (FLAG_inlining_depth_threshold < 1) return; 421 if (FLAG_inlining_depth_threshold < 1) return;
402 if (caller_graph_->parsed_function().function().deoptimization_counter() >= 422 if (caller_graph_->parsed_function().function().deoptimization_counter() >=
403 FLAG_deoptimization_counter_inlining_threshold) { 423 FLAG_deoptimization_counter_inlining_threshold) {
404 return; 424 return;
405 } 425 }
406 // Create two call site collections to swap between. 426 // Create two call site collections to swap between.
407 CallSites sites1(caller_graph_); 427 CallSites sites1(caller_graph_);
408 CallSites sites2(caller_graph_); 428 CallSites sites2(caller_graph_);
409 CallSites* call_sites_temp = NULL; 429 CallSites* call_sites_temp = NULL;
410 collected_call_sites_ = &sites1; 430 collected_call_sites_ = &sites1;
411 inlining_call_sites_ = &sites2; 431 inlining_call_sites_ = &sites2;
412 // Collect initial call sites. 432 // Collect initial call sites.
413 collected_call_sites_->FindCallSites(caller_graph_); 433 collected_call_sites_->FindCallSites(caller_graph_, inlining_depth_);
414 while (collected_call_sites_->HasCalls()) { 434 while (collected_call_sites_->HasCalls()) {
415 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n", 435 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n",
416 inlining_depth_)); 436 inlining_depth_));
417 // Swap collected and inlining arrays and clear the new collecting array. 437 // Swap collected and inlining arrays and clear the new collecting array.
418 call_sites_temp = collected_call_sites_; 438 call_sites_temp = collected_call_sites_;
419 collected_call_sites_ = inlining_call_sites_; 439 collected_call_sites_ = inlining_call_sites_;
420 inlining_call_sites_ = call_sites_temp; 440 inlining_call_sites_ = call_sites_temp;
421 collected_call_sites_->Clear(); 441 collected_call_sites_->Clear();
422 // Inline call sites at the current depth. 442 // Inline call sites at the current depth.
423 InlineStaticCalls(); 443 InlineStaticCalls();
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 503
484 // Abort if this is a recursive occurrence. 504 // Abort if this is a recursive occurrence.
485 Definition* call = call_data->call; 505 Definition* call = call_data->call;
486 if (!FLAG_inline_recursive && IsCallRecursive(function, call)) { 506 if (!FLAG_inline_recursive && IsCallRecursive(function, call)) {
487 function.set_is_inlinable(false); 507 function.set_is_inlinable(false);
488 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); 508 TRACE_INLINING(OS::Print(" Bailout: recursive function\n"));
489 return false; 509 return false;
490 } 510 }
491 511
492 // Abort if the callee has an intrinsic translation. 512 // Abort if the callee has an intrinsic translation.
493 if (Intrinsifier::CanIntrinsify(function)) { 513 if (Intrinsifier::CanIntrinsify(function) &&
514 !function.is_optimizable()) {
494 function.set_is_inlinable(false); 515 function.set_is_inlinable(false);
495 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n")); 516 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n"));
496 return false; 517 return false;
497 } 518 }
498 519
499 Isolate* isolate = Isolate::Current(); 520 Isolate* isolate = Isolate::Current();
500 // Save and clear deopt id. 521 // Save and clear deopt id.
501 const intptr_t prev_deopt_id = isolate->deopt_id(); 522 const intptr_t prev_deopt_id = isolate->deopt_id();
502 isolate->set_deopt_id(0); 523 isolate->set_deopt_id(0);
503 // Install bailout jump. 524 // Install bailout jump.
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 TRACE_INLINING(OS::Print(" Bailout: heuristics with " 647 TRACE_INLINING(OS::Print(" Bailout: heuristics with "
627 "code size: %" Pd ", " 648 "code size: %" Pd ", "
628 "call sites: %" Pd ", " 649 "call sites: %" Pd ", "
629 "const args: %" Pd "\n", 650 "const args: %" Pd "\n",
630 size, 651 size,
631 call_site_count, 652 call_site_count,
632 constants_count)); 653 constants_count));
633 return false; 654 return false;
634 } 655 }
635 656
636 // If depth is less or equal to threshold recursively add call sites. 657 collected_call_sites_->FindCallSites(callee_graph, inlining_depth_);
637 if (inlining_depth_ < FLAG_inlining_depth_threshold) {
638 collected_call_sites_->FindCallSites(callee_graph);
639 }
640 658
641 // Add the function to the cache. 659 // Add the function to the cache.
642 if (!in_cache) function_cache_.Add(parsed_function); 660 if (!in_cache) function_cache_.Add(parsed_function);
643 661
644 // Build succeeded so we restore the bailout jump. 662 // Build succeeded so we restore the bailout jump.
645 inlined_ = true; 663 inlined_ = true;
646 inlined_size_ += size; 664 inlined_size_ += size;
647 isolate->set_long_jump_base(base); 665 isolate->set_long_jump_base(base);
648 isolate->set_deopt_id(prev_deopt_id); 666 isolate->set_deopt_id(prev_deopt_id);
649 667
(...skipping 775 matching lines...) Expand 10 before | Expand all | Expand 10 after
1425 OS::Print("After Inlining of %s\n", flow_graph_-> 1443 OS::Print("After Inlining of %s\n", flow_graph_->
1426 parsed_function().function().ToFullyQualifiedCString()); 1444 parsed_function().function().ToFullyQualifiedCString());
1427 FlowGraphPrinter printer(*flow_graph_); 1445 FlowGraphPrinter printer(*flow_graph_);
1428 printer.PrintBlocks(); 1446 printer.PrintBlocks();
1429 } 1447 }
1430 } 1448 }
1431 } 1449 }
1432 } 1450 }
1433 1451
1434 } // namespace dart 1452 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler.cc ('k') | runtime/vm/flow_graph_optimizer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698