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

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: fixed checked mode tests failure 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 #include "vm/il_printer.h"
srdjan 2013/05/07 17:34:05 Remove.
Florian Schneider 2013/05/08 08:57:47 Done.
12 13
13 namespace dart { 14 namespace dart {
14 15
15 DECLARE_FLAG(bool, trace_optimization); 16 DECLARE_FLAG(bool, trace_optimization);
16 DECLARE_FLAG(bool, verify_compiler); 17 DECLARE_FLAG(bool, verify_compiler);
17 18
18 FlowGraph::FlowGraph(const FlowGraphBuilder& builder, 19 FlowGraph::FlowGraph(const FlowGraphBuilder& builder,
19 GraphEntryInstr* graph_entry, 20 GraphEntryInstr* graph_entry,
20 intptr_t max_block_id) 21 intptr_t max_block_id)
21 : parent_(), 22 : parent_(),
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 // have new assigned values flowing out of that block. 321 // have new assigned values flowing out of that block.
321 const GrowableArray<BitVector*>& ComputeAssignedVars() { 322 const GrowableArray<BitVector*>& ComputeAssignedVars() {
322 // We can't directly return kill_ because it uses postorder numbering while 323 // We can't directly return kill_ because it uses postorder numbering while
323 // SSA construction uses preorder numbering internally. 324 // SSA construction uses preorder numbering internally.
324 // We have to permute postorder into preorder. 325 // We have to permute postorder into preorder.
325 assigned_vars_.Clear(); 326 assigned_vars_.Clear();
326 327
327 const intptr_t block_count = flow_graph_->preorder().length(); 328 const intptr_t block_count = flow_graph_->preorder().length();
328 for (intptr_t i = 0; i < block_count; i++) { 329 for (intptr_t i = 0; i < block_count; i++) {
329 BlockEntryInstr* block = flow_graph_->preorder()[i]; 330 BlockEntryInstr* block = flow_graph_->preorder()[i];
331 // All locals are assigned inside try-catch.
330 BitVector* kill = GetKillSet(block); 332 BitVector* kill = GetKillSet(block);
331 kill->Intersect(GetLiveOutSet(block)); 333 if (block->try_index() != CatchClauseNode::kInvalidTryIndex) {
334 kill->SetAll();
335 } else {
336 kill->Intersect(GetLiveOutSet(block));
337 }
332 assigned_vars_.Add(kill); 338 assigned_vars_.Add(kill);
333 } 339 }
334 340
335 return assigned_vars_; 341 return assigned_vars_;
336 } 342 }
337 343
338 // Returns true if the value set by the given store reaches any load from the 344 // Returns true if the value set by the given store reaches any load from the
339 // same local variable. 345 // same local variable.
340 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { 346 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) {
341 if (store->is_dead()) { 347 if (store->is_dead()) {
(...skipping 24 matching lines...) Expand all
366 }; 372 };
367 373
368 374
369 void VariableLivenessAnalysis::ComputeInitialSets() { 375 void VariableLivenessAnalysis::ComputeInitialSets() {
370 const intptr_t block_count = postorder_.length(); 376 const intptr_t block_count = postorder_.length();
371 377
372 BitVector* last_loads = new BitVector(variable_count_); 378 BitVector* last_loads = new BitVector(variable_count_);
373 for (intptr_t i = 0; i < block_count; i++) { 379 for (intptr_t i = 0; i < block_count; i++) {
374 BlockEntryInstr* block = postorder_[i]; 380 BlockEntryInstr* block = postorder_[i];
375 381
382
srdjan 2013/05/07 17:34:05 Two lines space seems too match within a function
Florian Schneider 2013/05/08 08:57:47 Done.
376 BitVector* kill = kill_[i]; 383 BitVector* kill = kill_[i];
377 BitVector* live_in = live_in_[i]; 384 BitVector* live_in = live_in_[i];
378 last_loads->Clear(); 385 last_loads->Clear();
379 386
387 // Inside try-catch all locals are live.
388 if (block->try_index() != CatchClauseNode::kInvalidTryIndex) {
389 live_in->SetAll();
390 continue;
391 }
392
380 // Iterate backwards starting at the last instruction. 393 // Iterate backwards starting at the last instruction.
381 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { 394 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) {
382 Instruction* current = it.Current(); 395 Instruction* current = it.Current();
383 396
384 LoadLocalInstr* load = current->AsLoadLocal(); 397 LoadLocalInstr* load = current->AsLoadLocal();
385 if (load != NULL) { 398 if (load != NULL) {
386 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); 399 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_);
387 live_in->Add(index); 400 live_in->Add(index);
388 if (!last_loads->Contains(index)) { 401 if (!last_loads->Contains(index) && !load->local().always_live()) {
389 last_loads->Add(index); 402 last_loads->Add(index);
390 load->mark_last(); 403 load->mark_last();
391 } 404 }
392 continue; 405 continue;
393 } 406 }
394 407
395 StoreLocalInstr* store = current->AsStoreLocal(); 408 StoreLocalInstr* store = current->AsStoreLocal();
396 if (store != NULL) { 409 if (store != NULL && !store->local().always_live()) {
397 const intptr_t index = 410 const intptr_t index =
398 store->local().BitIndexIn(num_non_copied_params_); 411 store->local().BitIndexIn(num_non_copied_params_);
399 if (kill->Contains(index)) { 412 if (kill->Contains(index)) {
400 if (!live_in->Contains(index)) { 413 if (!live_in->Contains(index)) {
401 store->mark_dead(); 414 store->mark_dead();
402 } 415 }
403 } else { 416 } else {
404 if (!live_in->Contains(index)) { 417 if (!live_in->Contains(index)) {
405 store->mark_last(); 418 store->mark_last();
406 } 419 }
407 kill->Add(index); 420 kill->Add(index);
408 } 421 }
409 live_in->Remove(index); 422 if (block->try_index() == CatchClauseNode::kInvalidTryIndex) {
423 live_in->Remove(index);
424 }
410 continue; 425 continue;
411 } 426 }
412 } 427 }
413 } 428 }
414 } 429 }
415 430
416 431
417 void FlowGraph::ComputeSSA( 432 void FlowGraph::ComputeSSA(
418 intptr_t next_virtual_register_number, 433 intptr_t next_virtual_register_number,
419 ZoneGrowableArray<Definition*>* inlining_parameters) { 434 ZoneGrowableArray<Definition*>* inlining_parameters) {
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 } 624 }
610 } 625 }
611 } 626 }
612 } 627 }
613 } 628 }
614 629
615 630
616 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, 631 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis,
617 VariableLivenessAnalysis* variable_liveness, 632 VariableLivenessAnalysis* variable_liveness,
618 ZoneGrowableArray<Definition*>* inlining_parameters) { 633 ZoneGrowableArray<Definition*>* inlining_parameters) {
619 // TODO(fschneider): Support catch-entry.
620 if (graph_entry_->SuccessorCount() > 1) {
621 Bailout("Catch-entry support in SSA.");
622 }
623
624 // Initial renaming environment. 634 // Initial renaming environment.
625 GrowableArray<Definition*> env(variable_count()); 635 GrowableArray<Definition*> env(variable_count());
626 636
627 // Add global constants to the initial definitions. 637 // Add global constants to the initial definitions.
628 constant_null_ = 638 constant_null_ =
629 AddConstantToInitialDefinitions(Object::ZoneHandle()); 639 AddConstantToInitialDefinitions(Object::ZoneHandle());
630 640
631 // Add parameters to the initial definitions and renaming environment. 641 // Add parameters to the initial definitions and renaming environment.
632 if (inlining_parameters != NULL) { 642 if (inlining_parameters != NULL) {
633 // Use known parameters. 643 // Use known parameters.
(...skipping 12 matching lines...) Expand all
646 AddToInitialDefinitions(param); 656 AddToInitialDefinitions(param);
647 env.Add(param); 657 env.Add(param);
648 } 658 }
649 } 659 }
650 660
651 // Initialize all locals with #null in the renaming environment. 661 // Initialize all locals with #null in the renaming environment.
652 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { 662 for (intptr_t i = parameter_count(); i < variable_count(); ++i) {
653 env.Add(constant_null()); 663 env.Add(constant_null());
654 } 664 }
655 665
656 BlockEntryInstr* normal_entry = graph_entry_->SuccessorAt(0); 666 if (graph_entry_->SuccessorCount() > 1) {
657 ASSERT(normal_entry != NULL); // Must have entry. 667 // Functions with try-catch have a fixed area of stack slots reserved
658 RenameRecursive(normal_entry, &env, live_phis, variable_liveness); 668 // so that all local variables are stored at a known location when
669 // on entry to the catch.
670 graph_entry_->set_fixed_slot_count(
671 num_stack_locals() + num_copied_params());
672 }
673 RenameRecursive(graph_entry_, &env, live_phis, variable_liveness);
659 } 674 }
660 675
661 676
662 void FlowGraph::AttachEnvironment(Instruction* instr, 677 void FlowGraph::AttachEnvironment(Instruction* instr,
663 GrowableArray<Definition*>* env) { 678 GrowableArray<Definition*>* env) {
664 Environment* deopt_env = 679 Environment* deopt_env =
665 Environment::From(*env, 680 Environment::From(*env,
666 num_non_copied_params_, 681 num_non_copied_params_,
667 parsed_function_.function()); 682 parsed_function_.function());
668 instr->SetEnvironment(deopt_env); 683 instr->SetEnvironment(deopt_env);
(...skipping 13 matching lines...) Expand all
682 VariableLivenessAnalysis* variable_liveness) { 697 VariableLivenessAnalysis* variable_liveness) {
683 // 1. Process phis first. 698 // 1. Process phis first.
684 if (block_entry->IsJoinEntry()) { 699 if (block_entry->IsJoinEntry()) {
685 JoinEntryInstr* join = block_entry->AsJoinEntry(); 700 JoinEntryInstr* join = block_entry->AsJoinEntry();
686 if (join->phis() != NULL) { 701 if (join->phis() != NULL) {
687 for (intptr_t i = 0; i < join->phis()->length(); ++i) { 702 for (intptr_t i = 0; i < join->phis()->length(); ++i) {
688 PhiInstr* phi = (*join->phis())[i]; 703 PhiInstr* phi = (*join->phis())[i];
689 if (phi != NULL) { 704 if (phi != NULL) {
690 (*env)[i] = phi; 705 (*env)[i] = phi;
691 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. 706 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
707 if (block_entry->try_index() != CatchClauseNode::kInvalidTryIndex) {
708 phi->mark_alive();
709 live_phis->Add(phi);
710 }
692 } 711 }
693 } 712 }
694 } 713 }
714 } else if (block_entry->IsCatchBlockEntry()) {
715 // Add real definitions for all locals and parameters. The location of the
716 // parameters and locals is the same as at function entry.
717 for (intptr_t i = 0; i < env->length(); ++i) {
718 ParameterInstr* param = new ParameterInstr(i, block_entry);
719 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp.
720 (*env)[i] = param;
721 block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param);
722 }
695 } 723 }
696 724
697 // Attach environment to the block entry. 725 // Attach environment to the block entry.
698 AttachEnvironment(block_entry, env); 726 AttachEnvironment(block_entry, env);
699 727
700 // 2. Process normal instructions. 728 // 2. Process normal instructions.
701 729
702 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { 730 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) {
703 Instruction* current = it.Current(); 731 Instruction* current = it.Current();
704 732
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 LoadLocalInstr* load = definition->AsLoadLocal(); 771 LoadLocalInstr* load = definition->AsLoadLocal();
744 StoreLocalInstr* store = definition->AsStoreLocal(); 772 StoreLocalInstr* store = definition->AsStoreLocal();
745 if ((load != NULL) || (store != NULL)) { 773 if ((load != NULL) || (store != NULL)) {
746 intptr_t index; 774 intptr_t index;
747 Definition* result; 775 Definition* result;
748 if (store != NULL) { 776 if (store != NULL) {
749 // Update renaming environment. 777 // Update renaming environment.
750 index = store->local().BitIndexIn(num_non_copied_params_); 778 index = store->local().BitIndexIn(num_non_copied_params_);
751 result = store->value()->definition(); 779 result = store->value()->definition();
752 780
753 if (variable_liveness->IsStoreAlive(block_entry, store)) { 781 if (variable_liveness->IsStoreAlive(block_entry, store) ||
782 store->local().always_live()) {
754 (*env)[index] = result; 783 (*env)[index] = result;
755 } else { 784 } else {
756 (*env)[index] = constant_null(); 785 (*env)[index] = constant_null();
757 } 786 }
758 } else { 787 } else {
759 // The graph construction ensures we do not have an unused LoadLocal 788 // The graph construction ensures we do not have an unused LoadLocal
760 // computation. 789 // computation.
761 ASSERT(definition->is_used()); 790 ASSERT(definition->is_used());
762 index = load->local().BitIndexIn(num_non_copied_params_); 791 index = load->local().BitIndexIn(num_non_copied_params_);
763 result = (*env)[index]; 792 result = (*env)[index];
764 793
765 PhiInstr* phi = result->AsPhi(); 794 PhiInstr* phi = result->AsPhi();
766 if ((phi != NULL) && !phi->is_alive()) { 795 if ((phi != NULL) && !phi->is_alive()) {
767 phi->mark_alive(); 796 phi->mark_alive();
768 live_phis->Add(phi); 797 live_phis->Add(phi);
769 } 798 }
770 799
771 if (variable_liveness->IsLastLoad(block_entry, load)) { 800 if (variable_liveness->IsLastLoad(block_entry, load) &&
801 !load->local().always_live()) {
772 (*env)[index] = constant_null(); 802 (*env)[index] = constant_null();
773 } 803 }
774 } 804 }
775 // Update expression stack or remove from graph. 805 // Update expression stack or remove from graph.
776 if (definition->is_used()) { 806 if (definition->is_used()) {
777 env->Add(result); 807 env->Add(result);
778 // We remove load/store instructions when we find their use in 2a. 808 // We remove load/store instructions when we find their use in 2a.
779 } else { 809 } else {
780 it.RemoveCurrentFromGraph(); 810 it.RemoveCurrentFromGraph();
781 } 811 }
782 } else { 812 } else {
783 // Not a load or store. 813 // Not a load or store.
784 if (definition->is_used()) { 814 if (definition->is_used()) {
785 // Assign fresh SSA temporary and update expression stack. 815 // Assign fresh SSA temporary and update expression stack.
786 definition->set_ssa_temp_index(alloc_ssa_temp_index()); 816 definition->set_ssa_temp_index(alloc_ssa_temp_index());
787 env->Add(definition); 817 env->Add(definition);
788 } 818 }
789 } 819 }
790 } 820 }
791 821
792 // 2c. Handle pushed argument. 822 // 2c. Handle pushed argument.
793 PushArgumentInstr* push = current->AsPushArgument(); 823 PushArgumentInstr* push = current->AsPushArgument();
794 if (push != NULL) { 824 if (push != NULL) {
795 env->Add(push); 825 env->Add(push);
796 } 826 }
797 } 827 }
798 828
829
799 // 3. Process dominated blocks. 830 // 3. Process dominated blocks.
800 for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) { 831 for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) {
801 BlockEntryInstr* block = block_entry->dominated_blocks()[i]; 832 BlockEntryInstr* block = block_entry->dominated_blocks()[i];
802 GrowableArray<Definition*> new_env(env->length()); 833 GrowableArray<Definition*> new_env(env->length());
803 new_env.AddArray(*env); 834 new_env.AddArray(*env);
804 RenameRecursive(block, &new_env, live_phis, variable_liveness); 835 RenameRecursive(block, &new_env, live_phis, variable_liveness);
805 } 836 }
806 837
807 // 4. Process successor block. We have edge-split form, so that only blocks 838 // 4. Process successor block. We have edge-split form, so that only blocks
808 // with one successor can have a join block as successor. 839 // with one successor can have a join block as successor.
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1052 } 1083 }
1053 1084
1054 1085
1055 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, 1086 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from,
1056 BlockEntryInstr* to) const { 1087 BlockEntryInstr* to) const {
1057 return available_at_[to->postorder_number()]->Contains( 1088 return available_at_[to->postorder_number()]->Contains(
1058 from->postorder_number()); 1089 from->postorder_number());
1059 } 1090 }
1060 1091
1061 } // namespace dart 1092 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698