| OLD | NEW |
| 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_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| 11 #include "vm/hash_map.h" | 11 #include "vm/hash_map.h" |
| 12 #include "vm/il_printer.h" | 12 #include "vm/il_printer.h" |
| 13 #include "vm/intermediate_language.h" | 13 #include "vm/intermediate_language.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/parser.h" | 15 #include "vm/parser.h" |
| 16 #include "vm/resolver.h" | 16 #include "vm/resolver.h" |
| 17 #include "vm/scopes.h" | 17 #include "vm/scopes.h" |
| 18 #include "vm/stack_frame.h" |
| 18 #include "vm/symbols.h" | 19 #include "vm/symbols.h" |
| 19 | 20 |
| 20 namespace dart { | 21 namespace dart { |
| 21 | 22 |
| 22 DEFINE_FLAG(bool, array_bounds_check_elimination, true, | 23 DEFINE_FLAG(bool, array_bounds_check_elimination, true, |
| 23 "Eliminate redundant bounds checks."); | 24 "Eliminate redundant bounds checks."); |
| 24 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 25 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 25 DEFINE_FLAG(int, max_polymorphic_checks, 4, | 26 DEFINE_FLAG(int, max_polymorphic_checks, 4, |
| 26 "Maximum number of polymorphic check, otherwise it is megamorphic."); | 27 "Maximum number of polymorphic check, otherwise it is megamorphic."); |
| 27 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 28 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 BlockEntryInstr* entry = block_order_[i]; | 449 BlockEntryInstr* entry = block_order_[i]; |
| 449 JoinEntryInstr* join_entry = entry->AsJoinEntry(); | 450 JoinEntryInstr* join_entry = entry->AsJoinEntry(); |
| 450 if (join_entry != NULL) { | 451 if (join_entry != NULL) { |
| 451 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { | 452 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { |
| 452 PhiInstr* phi = it.Current(); | 453 PhiInstr* phi = it.Current(); |
| 453 ASSERT(phi != NULL); | 454 ASSERT(phi != NULL); |
| 454 ASSERT(phi->is_alive()); | 455 ASSERT(phi->is_alive()); |
| 455 InsertConversionsFor(phi); | 456 InsertConversionsFor(phi); |
| 456 } | 457 } |
| 457 } | 458 } |
| 459 CatchBlockEntryInstr* catch_entry = entry->AsCatchBlockEntry(); |
| 460 if (catch_entry != NULL) { |
| 461 for (intptr_t i = 0; |
| 462 i < catch_entry->initial_definitions()->length(); |
| 463 i++) { |
| 464 InsertConversionsFor((*catch_entry->initial_definitions())[i]); |
| 465 } |
| 466 } |
| 458 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 467 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 459 Definition* def = it.Current()->AsDefinition(); | 468 Definition* def = it.Current()->AsDefinition(); |
| 460 if (def != NULL) { | 469 if (def != NULL) { |
| 461 InsertConversionsFor(def); | 470 InsertConversionsFor(def); |
| 462 } | 471 } |
| 463 } | 472 } |
| 464 } | 473 } |
| 465 } | 474 } |
| 466 | 475 |
| 467 | 476 |
| (...skipping 2235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2703 Definition* current = initial[i]; | 2712 Definition* current = initial[i]; |
| 2704 if (current->Type()->ToCid() == kSmiCid) { | 2713 if (current->Type()->ToCid() == kSmiCid) { |
| 2705 smi_values_.Add(current); | 2714 smi_values_.Add(current); |
| 2706 } | 2715 } |
| 2707 } | 2716 } |
| 2708 | 2717 |
| 2709 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 2718 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 2710 !block_it.Done(); | 2719 !block_it.Done(); |
| 2711 block_it.Advance()) { | 2720 block_it.Advance()) { |
| 2712 BlockEntryInstr* block = block_it.Current(); | 2721 BlockEntryInstr* block = block_it.Current(); |
| 2722 |
| 2723 |
| 2724 if (block->IsGraphEntry() || block->IsCatchBlockEntry()) { |
| 2725 const GrowableArray<Definition*>& initial = block->IsGraphEntry() |
| 2726 ? *block->AsGraphEntry()->initial_definitions() |
| 2727 : *block->AsCatchBlockEntry()->initial_definitions(); |
| 2728 for (intptr_t i = 0; i < initial.length(); ++i) { |
| 2729 Definition* current = initial[i]; |
| 2730 if (current->Type()->ToCid() == kSmiCid) { |
| 2731 smi_values_.Add(current); |
| 2732 } |
| 2733 } |
| 2734 } |
| 2735 |
| 2736 JoinEntryInstr* join = block->AsJoinEntry(); |
| 2737 if (join != NULL) { |
| 2738 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
| 2739 PhiInstr* current = phi_it.Current(); |
| 2740 if (current->Type()->ToCid() == kSmiCid) { |
| 2741 smi_values_.Add(current); |
| 2742 } |
| 2743 } |
| 2744 } |
| 2745 |
| 2713 for (ForwardInstructionIterator instr_it(block); | 2746 for (ForwardInstructionIterator instr_it(block); |
| 2714 !instr_it.Done(); | 2747 !instr_it.Done(); |
| 2715 instr_it.Advance()) { | 2748 instr_it.Advance()) { |
| 2716 Instruction* current = instr_it.Current(); | 2749 Instruction* current = instr_it.Current(); |
| 2717 Definition* defn = current->AsDefinition(); | 2750 Definition* defn = current->AsDefinition(); |
| 2718 if (defn != NULL) { | 2751 if (defn != NULL) { |
| 2719 if ((defn->Type()->ToCid() == kSmiCid) && | 2752 if ((defn->Type()->ToCid() == kSmiCid) && |
| 2720 (defn->ssa_temp_index() != -1)) { | 2753 (defn->ssa_temp_index() != -1)) { |
| 2721 smi_values_.Add(defn); | 2754 smi_values_.Add(defn); |
| 2722 } | 2755 } |
| 2723 } else if (current->IsCheckSmi()) { | 2756 } else if (current->IsCheckSmi()) { |
| 2724 smi_checks_.Add(current->AsCheckSmi()); | 2757 smi_checks_.Add(current->AsCheckSmi()); |
| 2725 } | 2758 } |
| 2726 } | 2759 } |
| 2727 | |
| 2728 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 2729 if (join != NULL) { | |
| 2730 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | |
| 2731 PhiInstr* current = phi_it.Current(); | |
| 2732 if (current->Type()->ToCid() == kSmiCid) { | |
| 2733 smi_values_.Add(current); | |
| 2734 } | |
| 2735 } | |
| 2736 } | |
| 2737 } | 2760 } |
| 2738 } | 2761 } |
| 2739 | 2762 |
| 2740 | 2763 |
| 2741 // Returns true if use is dominated by the given instruction. | 2764 // Returns true if use is dominated by the given instruction. |
| 2742 // Note: uses that occur at instruction itself are not dominated by it. | 2765 // Note: uses that occur at instruction itself are not dominated by it. |
| 2743 static bool IsDominatedUse(Instruction* dom, Value* use) { | 2766 static bool IsDominatedUse(Instruction* dom, Value* use) { |
| 2744 BlockEntryInstr* dom_block = dom->GetBlock(); | 2767 BlockEntryInstr* dom_block = dom->GetBlock(); |
| 2745 | 2768 |
| 2746 Instruction* instr = use->instruction(); | 2769 Instruction* instr = use->instruction(); |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3164 } | 3187 } |
| 3165 } | 3188 } |
| 3166 | 3189 |
| 3167 | 3190 |
| 3168 void FlowGraphOptimizer::InferSmiRanges() { | 3191 void FlowGraphOptimizer::InferSmiRanges() { |
| 3169 RangeAnalysis range_analysis(flow_graph_); | 3192 RangeAnalysis range_analysis(flow_graph_); |
| 3170 range_analysis.Analyze(); | 3193 range_analysis.Analyze(); |
| 3171 } | 3194 } |
| 3172 | 3195 |
| 3173 | 3196 |
| 3197 void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) { |
| 3198 // For every catch-block: Iterate over all call instructions inside the |
| 3199 // corresponding try-block and figure out for each environment value if it |
| 3200 // is the same constant at all calls. If yes, replace the initial definition |
| 3201 // at the catch-entry with this constant. |
| 3202 const GrowableArray<CatchBlockEntryInstr*>& catch_entries = |
| 3203 flow_graph->graph_entry()->catch_entries(); |
| 3204 intptr_t base = kFirstLocalSlotFromFp + flow_graph->num_non_copied_params(); |
| 3205 for (intptr_t catch_idx = 0; |
| 3206 catch_idx < catch_entries.length(); |
| 3207 ++catch_idx) { |
| 3208 CatchBlockEntryInstr* cb = catch_entries[catch_idx]; |
| 3209 CatchEntryInstr* catch_entry = cb->next()->AsCatchEntry(); |
| 3210 |
| 3211 // Initialize cdefs with the original initial definitions (ParameterInstr). |
| 3212 // The following representation is used: |
| 3213 // ParameterInstr => unknown |
| 3214 // ConstantInstr => known constant |
| 3215 // NULL => non-constant |
| 3216 GrowableArray<Definition*>* idefs = cb->initial_definitions(); |
| 3217 GrowableArray<Definition*> cdefs(idefs->length()); |
| 3218 cdefs.AddArray(*idefs); |
| 3219 |
| 3220 // exception_var and stacktrace_var are never constant. |
| 3221 intptr_t ex_idx = base - catch_entry->exception_var().index(); |
| 3222 intptr_t st_idx = base - catch_entry->stacktrace_var().index(); |
| 3223 cdefs[ex_idx] = cdefs[st_idx] = NULL; |
| 3224 |
| 3225 for (BlockIterator block_it = flow_graph->reverse_postorder_iterator(); |
| 3226 !block_it.Done(); |
| 3227 block_it.Advance()) { |
| 3228 BlockEntryInstr* block = block_it.Current(); |
| 3229 if (block->try_index() == cb->catch_try_index()) { |
| 3230 for (ForwardInstructionIterator instr_it(block); |
| 3231 !instr_it.Done(); |
| 3232 instr_it.Advance()) { |
| 3233 Instruction* current = instr_it.Current(); |
| 3234 if (current->MayThrow()) { |
| 3235 Environment* env = current->env(); |
| 3236 for (intptr_t env_idx = 0; env_idx < cdefs.length(); ++env_idx) { |
| 3237 if (cdefs[env_idx] != NULL && |
| 3238 env->ValueAt(env_idx)->BindsToConstant()) { |
| 3239 cdefs[env_idx] = env->ValueAt(env_idx)->definition(); |
| 3240 } |
| 3241 if (cdefs[env_idx] != env->ValueAt(env_idx)->definition()) { |
| 3242 cdefs[env_idx] = NULL; |
| 3243 } |
| 3244 } |
| 3245 } |
| 3246 } |
| 3247 } |
| 3248 } |
| 3249 for (intptr_t j = 0; j < idefs->length(); ++j) { |
| 3250 if (cdefs[j] != NULL && cdefs[j]->IsConstant()) { |
| 3251 // TODO(fschneider): Use constants from the constant pool. |
| 3252 Definition* old = (*idefs)[j]; |
| 3253 ConstantInstr* orig = cdefs[j]->AsConstant(); |
| 3254 ConstantInstr* copy = new ConstantInstr(orig->value()); |
| 3255 copy->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); |
| 3256 old->ReplaceUsesWith(copy); |
| 3257 (*idefs)[j] = copy; |
| 3258 } |
| 3259 } |
| 3260 } |
| 3261 } |
| 3262 |
| 3263 |
| 3174 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) { | 3264 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) { |
| 3175 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { | 3265 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { |
| 3176 BlockEntryInstr* candidate = header->PredecessorAt(j); | 3266 BlockEntryInstr* candidate = header->PredecessorAt(j); |
| 3177 if (header->dominator() == candidate) { | 3267 if (header->dominator() == candidate) { |
| 3178 return candidate; | 3268 return candidate; |
| 3179 } | 3269 } |
| 3180 } | 3270 } |
| 3181 return NULL; | 3271 return NULL; |
| 3182 } | 3272 } |
| 3183 | 3273 |
| (...skipping 1339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4523 // -------------------------------------------------------------------------- | 4613 // -------------------------------------------------------------------------- |
| 4524 // Analysis of blocks. Called at most once per block. The block is already | 4614 // Analysis of blocks. Called at most once per block. The block is already |
| 4525 // marked as reachable. All instructions in the block are analyzed. | 4615 // marked as reachable. All instructions in the block are analyzed. |
| 4526 void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) { | 4616 void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) { |
| 4527 const GrowableArray<Definition*>& defs = *block->initial_definitions(); | 4617 const GrowableArray<Definition*>& defs = *block->initial_definitions(); |
| 4528 for (intptr_t i = 0; i < defs.length(); ++i) { | 4618 for (intptr_t i = 0; i < defs.length(); ++i) { |
| 4529 defs[i]->Accept(this); | 4619 defs[i]->Accept(this); |
| 4530 } | 4620 } |
| 4531 ASSERT(ForwardInstructionIterator(block).Done()); | 4621 ASSERT(ForwardInstructionIterator(block).Done()); |
| 4532 | 4622 |
| 4533 SetReachable(block->normal_entry()); | 4623 // TODO(fschneider): Improve this approximation. The catch entry is only |
| 4624 // reachable if a call in the try-block is reachable. |
| 4625 for (intptr_t i = 0; i < block->SuccessorCount(); ++i) { |
| 4626 SetReachable(block->SuccessorAt(i)); |
| 4627 } |
| 4534 } | 4628 } |
| 4535 | 4629 |
| 4536 | 4630 |
| 4537 void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) { | 4631 void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) { |
| 4538 // Phis are visited when visiting Goto at a predecessor. See VisitGoto. | 4632 // Phis are visited when visiting Goto at a predecessor. See VisitGoto. |
| 4539 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4633 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 4540 it.Current()->Accept(this); | 4634 it.Current()->Accept(this); |
| 4541 } | 4635 } |
| 4542 } | 4636 } |
| 4543 | 4637 |
| 4544 | 4638 |
| 4545 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { | 4639 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { |
| 4546 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4640 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 4547 it.Current()->Accept(this); | 4641 it.Current()->Accept(this); |
| 4548 } | 4642 } |
| 4549 } | 4643 } |
| 4550 | 4644 |
| 4551 | 4645 |
| 4552 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { | 4646 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { |
| 4647 const GrowableArray<Definition*>& defs = *block->initial_definitions(); |
| 4648 for (intptr_t i = 0; i < defs.length(); ++i) { |
| 4649 defs[i]->Accept(this); |
| 4650 } |
| 4553 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4651 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 4554 it.Current()->Accept(this); | 4652 it.Current()->Accept(this); |
| 4555 } | 4653 } |
| 4556 } | 4654 } |
| 4557 | 4655 |
| 4558 | 4656 |
| 4559 void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) { | 4657 void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) { |
| 4560 // Parallel moves have not yet been inserted in the graph. | 4658 // Parallel moves have not yet been inserted in the graph. |
| 4561 UNREACHABLE(); | 4659 UNREACHABLE(); |
| 4562 } | 4660 } |
| (...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5364 BlockEntryInstr* block = block_worklist_.RemoveLast(); | 5462 BlockEntryInstr* block = block_worklist_.RemoveLast(); |
| 5365 block->Accept(this); | 5463 block->Accept(this); |
| 5366 } | 5464 } |
| 5367 } | 5465 } |
| 5368 } | 5466 } |
| 5369 | 5467 |
| 5370 | 5468 |
| 5371 void ConstantPropagator::VisitBranches() { | 5469 void ConstantPropagator::VisitBranches() { |
| 5372 GraphEntryInstr* entry = graph_->graph_entry(); | 5470 GraphEntryInstr* entry = graph_->graph_entry(); |
| 5373 reachable_->Add(entry->preorder_number()); | 5471 reachable_->Add(entry->preorder_number()); |
| 5374 // TODO(fschneider): Handle CatchEntry. | 5472 block_worklist_.Add(entry); |
| 5375 reachable_->Add(entry->normal_entry()->preorder_number()); | |
| 5376 block_worklist_.Add(entry->normal_entry()); | |
| 5377 | 5473 |
| 5378 while (!block_worklist_.is_empty()) { | 5474 while (!block_worklist_.is_empty()) { |
| 5379 BlockEntryInstr* block = block_worklist_.RemoveLast(); | 5475 BlockEntryInstr* block = block_worklist_.RemoveLast(); |
| 5476 if (block->IsGraphEntry()) { |
| 5477 // TODO(fschneider): Improve this approximation. Catch entries are only |
| 5478 // reachable if a call in the corresponding try-block is reachable. |
| 5479 for (intptr_t i = 0; i < block->SuccessorCount(); ++i) { |
| 5480 SetReachable(block->SuccessorAt(i)); |
| 5481 } |
| 5482 continue; |
| 5483 } |
| 5380 Instruction* last = block->last_instruction(); | 5484 Instruction* last = block->last_instruction(); |
| 5381 if (last->IsGoto()) { | 5485 if (last->IsGoto()) { |
| 5382 SetReachable(last->AsGoto()->successor()); | 5486 SetReachable(last->AsGoto()->successor()); |
| 5383 } else if (last->IsBranch()) { | 5487 } else if (last->IsBranch()) { |
| 5384 BranchInstr* branch = last->AsBranch(); | 5488 BranchInstr* branch = last->AsBranch(); |
| 5385 // The current block must be reachable. | 5489 // The current block must be reachable. |
| 5386 ASSERT(reachable_->Contains(branch->GetBlock()->preorder_number())); | 5490 ASSERT(reachable_->Contains(branch->GetBlock()->preorder_number())); |
| 5387 if (branch->constant_target() != NULL) { | 5491 if (branch->constant_target() != NULL) { |
| 5388 // Found constant target computed by range analysis. | 5492 // Found constant target computed by range analysis. |
| 5389 if (branch->constant_target() == branch->true_successor()) { | 5493 if (branch->constant_target() == branch->true_successor()) { |
| (...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6154 | 6258 |
| 6155 // Insert materializations at environment uses. | 6259 // Insert materializations at environment uses. |
| 6156 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 6260 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 6157 for (intptr_t i = 0; i < exits.length(); i++) { | 6261 for (intptr_t i = 0; i < exits.length(); i++) { |
| 6158 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 6262 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 6159 } | 6263 } |
| 6160 } | 6264 } |
| 6161 | 6265 |
| 6162 | 6266 |
| 6163 } // namespace dart | 6267 } // namespace dart |
| OLD | NEW |