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

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

Issue 14682020: Optimize functions containing try-catch. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: addressed Srdjan's comments Created 7 years, 7 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
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.h" 5 #include "vm/flow_graph.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/flow_graph_builder.h" 8 #include "vm/flow_graph_builder.h"
9 #include "vm/intermediate_language.h" 9 #include "vm/intermediate_language.h"
10 #include "vm/longjump.h" 10 #include "vm/longjump.h"
11 #include "vm/growable_array.h" 11 #include "vm/growable_array.h"
12 12
13 namespace dart { 13 namespace dart {
14 14
15 DECLARE_FLAG(bool, trace_optimization); 15 DECLARE_FLAG(bool, trace_optimization);
16 DECLARE_FLAG(bool, verify_compiler); 16 DECLARE_FLAG(bool, verify_compiler);
17 17
18 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
19 DEFINE_FLAG(bool, optimize_try_catch, false, "Optimization of try-catch");
20 #else
21 DEFINE_FLAG(bool, optimize_try_catch, true, "Optimization of try-catch");
22 #endif
23
18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, 24 FlowGraph::FlowGraph(const FlowGraphBuilder& builder,
19 GraphEntryInstr* graph_entry, 25 GraphEntryInstr* graph_entry,
20 intptr_t max_block_id) 26 intptr_t max_block_id)
21 : parent_(), 27 : parent_(),
22 current_ssa_temp_index_(0), 28 current_ssa_temp_index_(0),
23 max_block_id_(max_block_id), 29 max_block_id_(max_block_id),
24 parsed_function_(builder.parsed_function()), 30 parsed_function_(builder.parsed_function()),
25 num_copied_params_(builder.num_copied_params()), 31 num_copied_params_(builder.num_copied_params()),
26 num_non_copied_params_(builder.num_non_copied_params()), 32 num_non_copied_params_(builder.num_non_copied_params()),
27 num_stack_locals_(builder.num_stack_locals()), 33 num_stack_locals_(builder.num_stack_locals()),
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 // have new assigned values flowing out of that block. 326 // have new assigned values flowing out of that block.
321 const GrowableArray<BitVector*>& ComputeAssignedVars() { 327 const GrowableArray<BitVector*>& ComputeAssignedVars() {
322 // We can't directly return kill_ because it uses postorder numbering while 328 // We can't directly return kill_ because it uses postorder numbering while
323 // SSA construction uses preorder numbering internally. 329 // SSA construction uses preorder numbering internally.
324 // We have to permute postorder into preorder. 330 // We have to permute postorder into preorder.
325 assigned_vars_.Clear(); 331 assigned_vars_.Clear();
326 332
327 const intptr_t block_count = flow_graph_->preorder().length(); 333 const intptr_t block_count = flow_graph_->preorder().length();
328 for (intptr_t i = 0; i < block_count; i++) { 334 for (intptr_t i = 0; i < block_count; i++) {
329 BlockEntryInstr* block = flow_graph_->preorder()[i]; 335 BlockEntryInstr* block = flow_graph_->preorder()[i];
336 // All locals are assigned inside try-catch.
Kevin Millikin (Google) 2013/05/08 11:42:00 Comment needs to say why. I don't understand why
Florian Schneider 2013/05/08 17:10:55 Done.
330 BitVector* kill = GetKillSet(block); 337 BitVector* kill = GetKillSet(block);
331 kill->Intersect(GetLiveOutSet(block)); 338 if (block->try_index() != CatchClauseNode::kInvalidTryIndex) {
339 kill->SetAll();
340 } else {
341 kill->Intersect(GetLiveOutSet(block));
342 }
332 assigned_vars_.Add(kill); 343 assigned_vars_.Add(kill);
333 } 344 }
334 345
335 return assigned_vars_; 346 return assigned_vars_;
336 } 347 }
337 348
338 // Returns true if the value set by the given store reaches any load from the 349 // Returns true if the value set by the given store reaches any load from the
339 // same local variable. 350 // same local variable.
340 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { 351 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) {
341 if (store->is_dead()) { 352 if (store->is_dead()) {
(...skipping 28 matching lines...) Expand all
370 const intptr_t block_count = postorder_.length(); 381 const intptr_t block_count = postorder_.length();
371 382
372 BitVector* last_loads = new BitVector(variable_count_); 383 BitVector* last_loads = new BitVector(variable_count_);
373 for (intptr_t i = 0; i < block_count; i++) { 384 for (intptr_t i = 0; i < block_count; i++) {
374 BlockEntryInstr* block = postorder_[i]; 385 BlockEntryInstr* block = postorder_[i];
375 386
376 BitVector* kill = kill_[i]; 387 BitVector* kill = kill_[i];
377 BitVector* live_in = live_in_[i]; 388 BitVector* live_in = live_in_[i];
378 last_loads->Clear(); 389 last_loads->Clear();
379 390
391 // Inside try-catch all locals are live.
Kevin Millikin (Google) 2013/05/08 11:42:00 Again, I don't understand why. This is just for a
Florian Schneider 2013/05/08 17:10:55 Done.
392 if (block->try_index() != CatchClauseNode::kInvalidTryIndex) {
393 live_in->SetAll();
394 continue;
395 }
396
380 // Iterate backwards starting at the last instruction. 397 // Iterate backwards starting at the last instruction.
381 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { 398 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) {
382 Instruction* current = it.Current(); 399 Instruction* current = it.Current();
383 400
384 LoadLocalInstr* load = current->AsLoadLocal(); 401 LoadLocalInstr* load = current->AsLoadLocal();
385 if (load != NULL) { 402 if (load != NULL) {
386 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); 403 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_);
387 live_in->Add(index); 404 live_in->Add(index);
388 if (!last_loads->Contains(index)) { 405 if (!last_loads->Contains(index) && !load->local().always_live()) {
389 last_loads->Add(index); 406 last_loads->Add(index);
390 load->mark_last(); 407 load->mark_last();
391 } 408 }
392 continue; 409 continue;
393 } 410 }
394 411
395 StoreLocalInstr* store = current->AsStoreLocal(); 412 StoreLocalInstr* store = current->AsStoreLocal();
396 if (store != NULL) { 413 if (store != NULL && !store->local().always_live()) {
397 const intptr_t index = 414 const intptr_t index =
398 store->local().BitIndexIn(num_non_copied_params_); 415 store->local().BitIndexIn(num_non_copied_params_);
399 if (kill->Contains(index)) { 416 if (kill->Contains(index)) {
400 if (!live_in->Contains(index)) { 417 if (!live_in->Contains(index)) {
401 store->mark_dead(); 418 store->mark_dead();
402 } 419 }
403 } else { 420 } else {
404 if (!live_in->Contains(index)) { 421 if (!live_in->Contains(index)) {
405 store->mark_last(); 422 store->mark_last();
406 } 423 }
407 kill->Add(index); 424 kill->Add(index);
408 } 425 }
409 live_in->Remove(index); 426 if (block->try_index() == CatchClauseNode::kInvalidTryIndex) {
Kevin Millikin (Google) 2013/05/08 11:42:00 This comparison is always true. The loop is not e
Florian Schneider 2013/05/08 17:10:55 Done.
427 live_in->Remove(index);
428 }
410 continue; 429 continue;
411 } 430 }
412 } 431 }
413 } 432 }
414 } 433 }
415 434
416 435
417 void FlowGraph::ComputeSSA( 436 void FlowGraph::ComputeSSA(
418 intptr_t next_virtual_register_number, 437 intptr_t next_virtual_register_number,
419 ZoneGrowableArray<Definition*>* inlining_parameters) { 438 ZoneGrowableArray<Definition*>* inlining_parameters) {
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 } 628 }
610 } 629 }
611 } 630 }
612 } 631 }
613 } 632 }
614 633
615 634
616 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, 635 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis,
617 VariableLivenessAnalysis* variable_liveness, 636 VariableLivenessAnalysis* variable_liveness,
618 ZoneGrowableArray<Definition*>* inlining_parameters) { 637 ZoneGrowableArray<Definition*>* inlining_parameters) {
619 // TODO(fschneider): Support catch-entry. 638 if (!FLAG_optimize_try_catch && (graph_entry_->SuccessorCount() > 1)) {
620 if (graph_entry_->SuccessorCount() > 1) {
621 Bailout("Catch-entry support in SSA."); 639 Bailout("Catch-entry support in SSA.");
622 } 640 }
623 641
624 // Initial renaming environment. 642 // Initial renaming environment.
625 GrowableArray<Definition*> env(variable_count()); 643 GrowableArray<Definition*> env(variable_count());
626 644
627 // Add global constants to the initial definitions. 645 // Add global constants to the initial definitions.
628 constant_null_ = 646 constant_null_ =
629 AddConstantToInitialDefinitions(Object::ZoneHandle()); 647 AddConstantToInitialDefinitions(Object::ZoneHandle());
630 648
(...skipping 15 matching lines...) Expand all
646 AddToInitialDefinitions(param); 664 AddToInitialDefinitions(param);
647 env.Add(param); 665 env.Add(param);
648 } 666 }
649 } 667 }
650 668
651 // Initialize all locals with #null in the renaming environment. 669 // Initialize all locals with #null in the renaming environment.
652 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { 670 for (intptr_t i = parameter_count(); i < variable_count(); ++i) {
653 env.Add(constant_null()); 671 env.Add(constant_null());
654 } 672 }
655 673
656 BlockEntryInstr* normal_entry = graph_entry_->SuccessorAt(0); 674 if (graph_entry_->SuccessorCount() > 1) {
657 ASSERT(normal_entry != NULL); // Must have entry. 675 // Functions with try-catch have a fixed area of stack slots reserved
658 RenameRecursive(normal_entry, &env, live_phis, variable_liveness); 676 // so that all local variables are stored at a known location when
677 // on entry to the catch.
678 graph_entry_->set_fixed_slot_count(
679 num_stack_locals() + num_copied_params());
680 }
681 RenameRecursive(graph_entry_, &env, live_phis, variable_liveness);
659 } 682 }
660 683
661 684
662 void FlowGraph::AttachEnvironment(Instruction* instr, 685 void FlowGraph::AttachEnvironment(Instruction* instr,
663 GrowableArray<Definition*>* env) { 686 GrowableArray<Definition*>* env) {
664 Environment* deopt_env = 687 Environment* deopt_env =
665 Environment::From(*env, 688 Environment::From(*env,
666 num_non_copied_params_, 689 num_non_copied_params_,
667 parsed_function_.function()); 690 parsed_function_.function());
668 instr->SetEnvironment(deopt_env); 691 instr->SetEnvironment(deopt_env);
(...skipping 13 matching lines...) Expand all
682 VariableLivenessAnalysis* variable_liveness) { 705 VariableLivenessAnalysis* variable_liveness) {
683 // 1. Process phis first. 706 // 1. Process phis first.
684 if (block_entry->IsJoinEntry()) { 707 if (block_entry->IsJoinEntry()) {
685 JoinEntryInstr* join = block_entry->AsJoinEntry(); 708 JoinEntryInstr* join = block_entry->AsJoinEntry();
686 if (join->phis() != NULL) { 709 if (join->phis() != NULL) {
687 for (intptr_t i = 0; i < join->phis()->length(); ++i) { 710 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
688 PhiInstr* phi = (*join->phis())[i]; 711 PhiInstr* phi = (*join->phis())[i];
689 if (phi != NULL) { 712 if (phi != NULL) {
690 (*env)[i] = phi; 713 (*env)[i] = phi;
691 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. 714 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
715 if (block_entry->try_index() != CatchClauseNode::kInvalidTryIndex) {
Kevin Millikin (Google) 2013/05/08 11:42:00 This comparison is repeated a lot in this change.
Florian Schneider 2013/05/08 17:10:55 Done.
716 phi->mark_alive();
717 live_phis->Add(phi);
718 }
692 } 719 }
693 } 720 }
694 } 721 }
722 } else if (block_entry->IsCatchBlockEntry()) {
723 // Add real definitions for all locals and parameters. The location of the
724 // parameters and locals is the same as at function entry.
Kevin Millikin (Google) 2013/05/08 11:42:00 I don't think this comment is quite correct. The
Florian Schneider 2013/05/08 17:10:55 Done.
725 for (intptr_t i = 0; i < env->length(); ++i) {
726 ParameterInstr* param = new ParameterInstr(i, block_entry);
727 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
728 (*env)[i] = param;
729 block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param);
730 }
695 } 731 }
696 732
697 // Attach environment to the block entry. 733 // Attach environment to the block entry.
698 AttachEnvironment(block_entry, env); 734 AttachEnvironment(block_entry, env);
699 735
700 // 2. Process normal instructions. 736 // 2. Process normal instructions.
701 737
702 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { 738 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
703 Instruction* current = it.Current(); 739 Instruction* current = it.Current();
704 740
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 LoadLocalInstr* load = definition->AsLoadLocal(); 779 LoadLocalInstr* load = definition->AsLoadLocal();
744 StoreLocalInstr* store = definition->AsStoreLocal(); 780 StoreLocalInstr* store = definition->AsStoreLocal();
745 if ((load != NULL) || (store != NULL)) { 781 if ((load != NULL) || (store != NULL)) {
746 intptr_t index; 782 intptr_t index;
747 Definition* result; 783 Definition* result;
748 if (store != NULL) { 784 if (store != NULL) {
749 // Update renaming environment. 785 // Update renaming environment.
750 index = store->local().BitIndexIn(num_non_copied_params_); 786 index = store->local().BitIndexIn(num_non_copied_params_);
751 result = store->value()->definition(); 787 result = store->value()->definition();
752 788
753 if (variable_liveness->IsStoreAlive(block_entry, store)) { 789 if (variable_liveness->IsStoreAlive(block_entry, store) ||
790 store->local().always_live()) {
Kevin Millikin (Google) 2013/05/08 11:42:00 Need to know why, also below. These are for the t
Florian Schneider 2013/05/08 17:10:55 Done. Not needed anymore.
754 (*env)[index] = result; 791 (*env)[index] = result;
755 } else { 792 } else {
756 (*env)[index] = constant_null(); 793 (*env)[index] = constant_null();
757 } 794 }
758 } else { 795 } else {
759 // The graph construction ensures we do not have an unused LoadLocal 796 // The graph construction ensures we do not have an unused LoadLocal
760 // computation. 797 // computation.
761 ASSERT(definition->is_used()); 798 ASSERT(definition->is_used());
762 index = load->local().BitIndexIn(num_non_copied_params_); 799 index = load->local().BitIndexIn(num_non_copied_params_);
763 result = (*env)[index]; 800 result = (*env)[index];
764 801
765 PhiInstr* phi = result->AsPhi(); 802 PhiInstr* phi = result->AsPhi();
766 if ((phi != NULL) && !phi->is_alive()) { 803 if ((phi != NULL) && !phi->is_alive()) {
767 phi->mark_alive(); 804 phi->mark_alive();
768 live_phis->Add(phi); 805 live_phis->Add(phi);
769 } 806 }
770 807
771 if (variable_liveness->IsLastLoad(block_entry, load)) { 808 if (variable_liveness->IsLastLoad(block_entry, load) &&
809 !load->local().always_live()) {
Kevin Millikin (Google) 2013/05/08 11:42:00 Is this because there are implicit loads from the
Florian Schneider 2013/05/08 17:10:55 Done. Not needed anymore.
772 (*env)[index] = constant_null(); 810 (*env)[index] = constant_null();
773 } 811 }
774 } 812 }
775 // Update expression stack or remove from graph. 813 // Update expression stack or remove from graph.
776 if (definition->is_used()) { 814 if (definition->is_used()) {
777 env->Add(result); 815 env->Add(result);
778 // We remove load/store instructions when we find their use in 2a. 816 // We remove load/store instructions when we find their use in 2a.
779 } else { 817 } else {
780 it.RemoveCurrentFromGraph(); 818 it.RemoveCurrentFromGraph();
781 } 819 }
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
1052 } 1090 }
1053 1091
1054 1092
1055 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, 1093 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from,
1056 BlockEntryInstr* to) const { 1094 BlockEntryInstr* to) const {
1057 return available_at_[to->postorder_number()]->Contains( 1095 return available_at_[to->postorder_number()]->Contains(
1058 from->postorder_number()); 1096 from->postorder_number());
1059 } 1097 }
1060 1098
1061 } // namespace dart 1099 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698