| 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 | 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 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 // have new assigned values flowing out of that block. | 327 // have new assigned values flowing out of that block. |
| 322 const GrowableArray<BitVector*>& ComputeAssignedVars() { | 328 const GrowableArray<BitVector*>& ComputeAssignedVars() { |
| 323 // We can't directly return kill_ because it uses postorder numbering while | 329 // We can't directly return kill_ because it uses postorder numbering while |
| 324 // SSA construction uses preorder numbering internally. | 330 // SSA construction uses preorder numbering internally. |
| 325 // We have to permute postorder into preorder. | 331 // We have to permute postorder into preorder. |
| 326 assigned_vars_.Clear(); | 332 assigned_vars_.Clear(); |
| 327 | 333 |
| 328 const intptr_t block_count = flow_graph_->preorder().length(); | 334 const intptr_t block_count = flow_graph_->preorder().length(); |
| 329 for (intptr_t i = 0; i < block_count; i++) { | 335 for (intptr_t i = 0; i < block_count; i++) { |
| 330 BlockEntryInstr* block = flow_graph_->preorder()[i]; | 336 BlockEntryInstr* block = flow_graph_->preorder()[i]; |
| 337 // All locals are assigned inside a try{} block. |
| 338 // This is a safe approximation and workaround to force insertion of |
| 339 // phis for stores that appear non-live because of the way catch-blocks |
| 340 // are connected to the graph: They normally are dominated by the |
| 341 // try-entry, but are direct successors of the graph entry in our flow |
| 342 // graph. |
| 343 // TODO(fschneider): Improve this approximation by better modeling the |
| 344 // actual data flow to reduce the number of redundant phis. |
| 331 BitVector* kill = GetKillSet(block); | 345 BitVector* kill = GetKillSet(block); |
| 332 kill->Intersect(GetLiveOutSet(block)); | 346 if (block->InsideTryBlock()) { |
| 347 kill->SetAll(); |
| 348 } else { |
| 349 kill->Intersect(GetLiveOutSet(block)); |
| 350 } |
| 333 assigned_vars_.Add(kill); | 351 assigned_vars_.Add(kill); |
| 334 } | 352 } |
| 335 | 353 |
| 336 return assigned_vars_; | 354 return assigned_vars_; |
| 337 } | 355 } |
| 338 | 356 |
| 339 // Returns true if the value set by the given store reaches any load from the | 357 // Returns true if the value set by the given store reaches any load from the |
| 340 // same local variable. | 358 // same local variable. |
| 341 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { | 359 bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { |
| 342 if (store->is_dead()) { | 360 if (store->is_dead()) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 371 const intptr_t block_count = postorder_.length(); | 389 const intptr_t block_count = postorder_.length(); |
| 372 | 390 |
| 373 BitVector* last_loads = new BitVector(variable_count_); | 391 BitVector* last_loads = new BitVector(variable_count_); |
| 374 for (intptr_t i = 0; i < block_count; i++) { | 392 for (intptr_t i = 0; i < block_count; i++) { |
| 375 BlockEntryInstr* block = postorder_[i]; | 393 BlockEntryInstr* block = postorder_[i]; |
| 376 | 394 |
| 377 BitVector* kill = kill_[i]; | 395 BitVector* kill = kill_[i]; |
| 378 BitVector* live_in = live_in_[i]; | 396 BitVector* live_in = live_in_[i]; |
| 379 last_loads->Clear(); | 397 last_loads->Clear(); |
| 380 | 398 |
| 399 // There is an implicit use (load-local) of every local variable at each |
| 400 // call inside a try{} block and every call has an implicit control-flow |
| 401 // to the catch entry. As an approximation we mark all locals as live |
| 402 // inside try{}. |
| 403 // TODO(fschneider): Improve this approximation, since not all local |
| 404 // variable stores actually reach a call. |
| 405 if (block->InsideTryBlock()) { |
| 406 live_in->SetAll(); |
| 407 continue; |
| 408 } |
| 409 |
| 381 // Iterate backwards starting at the last instruction. | 410 // Iterate backwards starting at the last instruction. |
| 382 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 411 for (BackwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 383 Instruction* current = it.Current(); | 412 Instruction* current = it.Current(); |
| 384 | 413 |
| 385 LoadLocalInstr* load = current->AsLoadLocal(); | 414 LoadLocalInstr* load = current->AsLoadLocal(); |
| 386 if (load != NULL) { | 415 if (load != NULL) { |
| 387 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); | 416 const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); |
| 388 live_in->Add(index); | 417 live_in->Add(index); |
| 389 if (!last_loads->Contains(index)) { | 418 if (!last_loads->Contains(index)) { |
| 390 last_loads->Add(index); | 419 last_loads->Add(index); |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 } | 639 } |
| 611 } | 640 } |
| 612 } | 641 } |
| 613 } | 642 } |
| 614 } | 643 } |
| 615 | 644 |
| 616 | 645 |
| 617 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, | 646 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis, |
| 618 VariableLivenessAnalysis* variable_liveness, | 647 VariableLivenessAnalysis* variable_liveness, |
| 619 ZoneGrowableArray<Definition*>* inlining_parameters) { | 648 ZoneGrowableArray<Definition*>* inlining_parameters) { |
| 620 // TODO(fschneider): Support catch-entry. | 649 if (!FLAG_optimize_try_catch && (graph_entry_->SuccessorCount() > 1)) { |
| 621 if (graph_entry_->SuccessorCount() > 1) { | |
| 622 Bailout("Catch-entry support in SSA."); | 650 Bailout("Catch-entry support in SSA."); |
| 623 } | 651 } |
| 624 | 652 |
| 625 // Initial renaming environment. | 653 // Initial renaming environment. |
| 626 GrowableArray<Definition*> env(variable_count()); | 654 GrowableArray<Definition*> env(variable_count()); |
| 627 | 655 |
| 628 // Add global constants to the initial definitions. | 656 // Add global constants to the initial definitions. |
| 629 constant_null_ = GetConstant(Object::ZoneHandle()); | 657 constant_null_ = GetConstant(Object::ZoneHandle()); |
| 630 | 658 |
| 631 // Add parameters to the initial definitions and renaming environment. | 659 // Add parameters to the initial definitions and renaming environment. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 646 AddToInitialDefinitions(param); | 674 AddToInitialDefinitions(param); |
| 647 env.Add(param); | 675 env.Add(param); |
| 648 } | 676 } |
| 649 } | 677 } |
| 650 | 678 |
| 651 // Initialize all locals with #null in the renaming environment. | 679 // Initialize all locals with #null in the renaming environment. |
| 652 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { | 680 for (intptr_t i = parameter_count(); i < variable_count(); ++i) { |
| 653 env.Add(constant_null()); | 681 env.Add(constant_null()); |
| 654 } | 682 } |
| 655 | 683 |
| 656 BlockEntryInstr* normal_entry = graph_entry_->SuccessorAt(0); | 684 if (graph_entry_->SuccessorCount() > 1) { |
| 657 ASSERT(normal_entry != NULL); // Must have entry. | 685 // Functions with try-catch have a fixed area of stack slots reserved |
| 658 RenameRecursive(normal_entry, &env, live_phis, variable_liveness); | 686 // so that all local variables are stored at a known location when |
| 687 // on entry to the catch. |
| 688 graph_entry_->set_fixed_slot_count( |
| 689 num_stack_locals() + num_copied_params()); |
| 690 } |
| 691 RenameRecursive(graph_entry_, &env, live_phis, variable_liveness); |
| 659 } | 692 } |
| 660 | 693 |
| 661 | 694 |
| 662 void FlowGraph::AttachEnvironment(Instruction* instr, | 695 void FlowGraph::AttachEnvironment(Instruction* instr, |
| 663 GrowableArray<Definition*>* env) { | 696 GrowableArray<Definition*>* env) { |
| 664 Environment* deopt_env = | 697 Environment* deopt_env = |
| 665 Environment::From(*env, | 698 Environment::From(*env, |
| 666 num_non_copied_params_, | 699 num_non_copied_params_, |
| 667 parsed_function_.function()); | 700 parsed_function_.function()); |
| 668 instr->SetEnvironment(deopt_env); | 701 instr->SetEnvironment(deopt_env); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 682 VariableLivenessAnalysis* variable_liveness) { | 715 VariableLivenessAnalysis* variable_liveness) { |
| 683 // 1. Process phis first. | 716 // 1. Process phis first. |
| 684 if (block_entry->IsJoinEntry()) { | 717 if (block_entry->IsJoinEntry()) { |
| 685 JoinEntryInstr* join = block_entry->AsJoinEntry(); | 718 JoinEntryInstr* join = block_entry->AsJoinEntry(); |
| 686 if (join->phis() != NULL) { | 719 if (join->phis() != NULL) { |
| 687 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | 720 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
| 688 PhiInstr* phi = (*join->phis())[i]; | 721 PhiInstr* phi = (*join->phis())[i]; |
| 689 if (phi != NULL) { | 722 if (phi != NULL) { |
| 690 (*env)[i] = phi; | 723 (*env)[i] = phi; |
| 691 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. | 724 phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. |
| 725 if (block_entry->InsideTryBlock()) { |
| 726 // This is a safe approximation. Inside try{} all locals are |
| 727 // used at every call implicitly, so we mark all phis as live |
| 728 // from the start. |
| 729 // TODO(fschneider): Improve this approximation to eliminate |
| 730 // more redundant phis. |
| 731 phi->mark_alive(); |
| 732 live_phis->Add(phi); |
| 733 } |
| 692 } | 734 } |
| 693 } | 735 } |
| 694 } | 736 } |
| 737 } else if (block_entry->IsCatchBlockEntry()) { |
| 738 // Add real definitions for all locals and parameters. |
| 739 for (intptr_t i = 0; i < env->length(); ++i) { |
| 740 ParameterInstr* param = new ParameterInstr(i, block_entry); |
| 741 param->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. |
| 742 (*env)[i] = param; |
| 743 block_entry->AsCatchBlockEntry()->initial_definitions()->Add(param); |
| 744 } |
| 695 } | 745 } |
| 696 | 746 |
| 697 // Attach environment to the block entry. | 747 // Attach environment to the block entry. |
| 698 AttachEnvironment(block_entry, env); | 748 AttachEnvironment(block_entry, env); |
| 699 | 749 |
| 700 // 2. Process normal instructions. | 750 // 2. Process normal instructions. |
| 701 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { | 751 for (ForwardInstructionIterator it(block_entry); !it.Done(); it.Advance()) { |
| 702 Instruction* current = it.Current(); | 752 Instruction* current = it.Current(); |
| 703 | 753 |
| 704 // Attach current environment to the instructions that need it. | 754 // Attach current environment to the instructions that need it. |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 } | 1107 } |
| 1058 | 1108 |
| 1059 | 1109 |
| 1060 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, | 1110 bool BlockEffects::IsSideEffectFreePath(BlockEntryInstr* from, |
| 1061 BlockEntryInstr* to) const { | 1111 BlockEntryInstr* to) const { |
| 1062 return available_at_[to->postorder_number()]->Contains( | 1112 return available_at_[to->postorder_number()]->Contains( |
| 1063 from->postorder_number()); | 1113 from->postorder_number()); |
| 1064 } | 1114 } |
| 1065 | 1115 |
| 1066 } // namespace dart | 1116 } // namespace dart |
| OLD | NEW |