Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |