Chromium Code Reviews| 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 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 450 BlockEntryInstr* entry = block_order_[i]; | 451 BlockEntryInstr* entry = block_order_[i]; |
| 451 JoinEntryInstr* join_entry = entry->AsJoinEntry(); | 452 JoinEntryInstr* join_entry = entry->AsJoinEntry(); |
| 452 if (join_entry != NULL) { | 453 if (join_entry != NULL) { |
| 453 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { | 454 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { |
| 454 PhiInstr* phi = it.Current(); | 455 PhiInstr* phi = it.Current(); |
| 455 ASSERT(phi != NULL); | 456 ASSERT(phi != NULL); |
| 456 ASSERT(phi->is_alive()); | 457 ASSERT(phi->is_alive()); |
| 457 InsertConversionsFor(phi); | 458 InsertConversionsFor(phi); |
| 458 } | 459 } |
| 459 } | 460 } |
| 461 CatchBlockEntryInstr* catch_entry = entry->AsCatchBlockEntry(); | |
| 462 if (catch_entry != NULL) { | |
| 463 for (intptr_t i = 0; | |
| 464 i < catch_entry->initial_definitions()->length(); | |
| 465 i++) { | |
| 466 InsertConversionsFor((*catch_entry->initial_definitions())[i]); | |
| 467 } | |
| 468 } | |
| 460 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 469 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 461 Definition* def = it.Current()->AsDefinition(); | 470 Definition* def = it.Current()->AsDefinition(); |
| 462 if (def != NULL) { | 471 if (def != NULL) { |
| 463 InsertConversionsFor(def); | 472 InsertConversionsFor(def); |
| 464 } | 473 } |
| 465 } | 474 } |
| 466 } | 475 } |
| 467 } | 476 } |
| 468 | 477 |
| 469 | 478 |
| (...skipping 2201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2671 | 2680 |
| 2672 | 2681 |
| 2673 void RangeAnalysis::Analyze() { | 2682 void RangeAnalysis::Analyze() { |
| 2674 CollectSmiValues(); | 2683 CollectSmiValues(); |
| 2675 InsertConstraints(); | 2684 InsertConstraints(); |
| 2676 InferRanges(); | 2685 InferRanges(); |
| 2677 RemoveConstraints(); | 2686 RemoveConstraints(); |
| 2678 } | 2687 } |
| 2679 | 2688 |
| 2680 | 2689 |
| 2681 void RangeAnalysis::CollectSmiValues() { | 2690 void RangeAnalysis::CollectSmiValues() { |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
Note that this function does not handle smi consta
Florian Schneider
2013/05/08 17:10:55
Good catch. Done.
| |
| 2682 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 2691 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 2683 !block_it.Done(); | 2692 !block_it.Done(); |
| 2684 block_it.Advance()) { | 2693 block_it.Advance()) { |
| 2685 BlockEntryInstr* block = block_it.Current(); | 2694 BlockEntryInstr* block = block_it.Current(); |
| 2686 for (ForwardInstructionIterator instr_it(block); | 2695 for (ForwardInstructionIterator instr_it(block); |
| 2687 !instr_it.Done(); | 2696 !instr_it.Done(); |
| 2688 instr_it.Advance()) { | 2697 instr_it.Advance()) { |
| 2689 Instruction* current = instr_it.Current(); | 2698 Instruction* current = instr_it.Current(); |
| 2690 Definition* defn = current->AsDefinition(); | 2699 Definition* defn = current->AsDefinition(); |
| 2691 if (defn != NULL) { | 2700 if (defn != NULL) { |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3042 case kUnknown: | 3051 case kUnknown: |
| 3043 case kBoth: | 3052 case kBoth: |
| 3044 return Range::Unknown(); | 3053 return Range::Unknown(); |
| 3045 } | 3054 } |
| 3046 | 3055 |
| 3047 UNREACHABLE(); | 3056 UNREACHABLE(); |
| 3048 return NULL; | 3057 return NULL; |
| 3049 } | 3058 } |
| 3050 | 3059 |
| 3051 | 3060 |
| 3052 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) { | 3061 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) { |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
Note that this function does not infer ranges for
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3053 JoinEntryInstr* join = block->AsJoinEntry(); | 3062 JoinEntryInstr* join = block->AsJoinEntry(); |
| 3054 if (join != NULL) { | 3063 if (join != NULL) { |
| 3055 const bool is_loop_header = (join->loop_info() != NULL); | 3064 const bool is_loop_header = (join->loop_info() != NULL); |
| 3056 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 3065 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 3057 PhiInstr* phi = it.Current(); | 3066 PhiInstr* phi = it.Current(); |
| 3058 if (smi_definitions_->Contains(phi->ssa_temp_index())) { | 3067 if (smi_definitions_->Contains(phi->ssa_temp_index())) { |
| 3059 if (is_loop_header) { | 3068 if (is_loop_header) { |
| 3060 // Try recognizing simple induction variables. | 3069 // Try recognizing simple induction variables. |
| 3061 Range* range = InferInductionVariableRange(join, phi); | 3070 Range* range = InferInductionVariableRange(join, phi); |
| 3062 if (range != NULL) { | 3071 if (range != NULL) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3129 } | 3138 } |
| 3130 } | 3139 } |
| 3131 | 3140 |
| 3132 | 3141 |
| 3133 void FlowGraphOptimizer::InferSmiRanges() { | 3142 void FlowGraphOptimizer::InferSmiRanges() { |
| 3134 RangeAnalysis range_analysis(flow_graph_); | 3143 RangeAnalysis range_analysis(flow_graph_); |
| 3135 range_analysis.Analyze(); | 3144 range_analysis.Analyze(); |
| 3136 } | 3145 } |
| 3137 | 3146 |
| 3138 | 3147 |
| 3148 void FlowGraphOptimizer::AnalyzeTryCatch() { | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
Doesn't need to be in the FlowGraphOptimizer, whic
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3149 // For every catch-block: Iterate over all call instructions inside the | |
| 3150 // corresponding try-block and figure out for each environment value if it | |
| 3151 // is the same constant at all calls. If yes, replace the initial definition | |
| 3152 // at the catch-entry with this constant. | |
| 3153 const GrowableArray<CatchBlockEntryInstr*>& catch_entries = | |
| 3154 flow_graph_->graph_entry()->catch_entries(); | |
| 3155 intptr_t nncp = flow_graph_->num_non_copied_params(); | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
intptr_t base = kFirstLocalSlotIndex + flow_graph_
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3156 for (intptr_t catch_idx = 0; | |
| 3157 catch_idx < catch_entries.length(); | |
| 3158 ++catch_idx) { | |
| 3159 CatchBlockEntryInstr* cb = catch_entries[catch_idx]; | |
| 3160 CatchEntryInstr* catch_entry = cb->next()->AsCatchEntry(); | |
| 3161 intptr_t ex_idx = | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
intptr_t ex_idx = base - catch_entry->exception_va
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3162 kFirstLocalSlotIndex - catch_entry->exception_var().index() + nncp; | |
| 3163 intptr_t st_idx = | |
| 3164 kFirstLocalSlotIndex - catch_entry->stacktrace_var().index() + nncp; | |
| 3165 GrowableArray<Definition*>* idefs = cb->initial_definitions(); | |
| 3166 GrowableArray<Definition*> cdefs(idefs->length()); | |
| 3167 cdefs.AddArray(*idefs); | |
| 3168 | |
| 3169 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
This is doing constant analysis with the lattice:
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3170 !block_it.Done(); | |
| 3171 block_it.Advance()) { | |
| 3172 BlockEntryInstr* block = block_it.Current(); | |
| 3173 if (block->try_index() == cb->catch_try_index()) { | |
| 3174 for (ForwardInstructionIterator instr_it(block); | |
| 3175 !instr_it.Done(); | |
| 3176 instr_it.Advance()) { | |
| 3177 Instruction* current = instr_it.Current(); | |
| 3178 if (current->MayThrow()) { | |
| 3179 Environment* env = current->env(); | |
| 3180 for (intptr_t env_idx = 0; env_idx < cdefs.length(); ++env_idx) { | |
| 3181 if (cdefs[env_idx] != NULL && | |
| 3182 cdefs[env_idx]->IsParameter() && | |
| 3183 cdefs[env_idx]->AsParameter()->index() != ex_idx && | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
The intent is that ex_idx and st_idx are not const
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3184 cdefs[env_idx]->AsParameter()->index() != st_idx && | |
| 3185 env->ValueAt(env_idx)->definition()->IsConstant()) { | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
I guess you can write this as env->ValueAt(env_idx
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 3186 cdefs[env_idx] = env->ValueAt(env_idx)->definition(); | |
| 3187 } | |
| 3188 if (cdefs[env_idx] != env->ValueAt(env_idx)->definition()) { | |
| 3189 cdefs[env_idx] = NULL; | |
| 3190 } | |
| 3191 } | |
| 3192 } | |
| 3193 } | |
| 3194 } | |
| 3195 } | |
| 3196 for (intptr_t j = 0; j < idefs->length(); ++j) { | |
| 3197 if (cdefs[j] != NULL && cdefs[j]->IsConstant()) { | |
| 3198 Definition* old = (*idefs)[j]; | |
| 3199 ConstantInstr* orig = cdefs[j]->AsConstant(); | |
| 3200 ConstantInstr* copy = new ConstantInstr(orig->value()); | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
Note that all constants are pooled now. I think y
Florian Schneider
2013/05/08 17:10:55
Yes. It should and make the code much simpler here
| |
| 3201 copy->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | |
| 3202 old->ReplaceUsesWith(copy); | |
| 3203 (*idefs)[j] = copy; | |
| 3204 } | |
| 3205 } | |
| 3206 } | |
| 3207 } | |
| 3208 | |
| 3209 | |
| 3139 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) { | 3210 static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) { |
| 3140 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { | 3211 for (intptr_t j = 0; j < header->PredecessorCount(); ++j) { |
| 3141 BlockEntryInstr* candidate = header->PredecessorAt(j); | 3212 BlockEntryInstr* candidate = header->PredecessorAt(j); |
| 3142 if (header->dominator() == candidate) { | 3213 if (header->dominator() == candidate) { |
| 3143 return candidate; | 3214 return candidate; |
| 3144 } | 3215 } |
| 3145 } | 3216 } |
| 3146 return NULL; | 3217 return NULL; |
| 3147 } | 3218 } |
| 3148 | 3219 |
| (...skipping 1242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4391 // -------------------------------------------------------------------------- | 4462 // -------------------------------------------------------------------------- |
| 4392 // Analysis of blocks. Called at most once per block. The block is already | 4463 // Analysis of blocks. Called at most once per block. The block is already |
| 4393 // marked as reachable. All instructions in the block are analyzed. | 4464 // marked as reachable. All instructions in the block are analyzed. |
| 4394 void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) { | 4465 void ConstantPropagator::VisitGraphEntry(GraphEntryInstr* block) { |
| 4395 const GrowableArray<Definition*>& defs = *block->initial_definitions(); | 4466 const GrowableArray<Definition*>& defs = *block->initial_definitions(); |
| 4396 for (intptr_t i = 0; i < defs.length(); ++i) { | 4467 for (intptr_t i = 0; i < defs.length(); ++i) { |
| 4397 defs[i]->Accept(this); | 4468 defs[i]->Accept(this); |
| 4398 } | 4469 } |
| 4399 ASSERT(ForwardInstructionIterator(block).Done()); | 4470 ASSERT(ForwardInstructionIterator(block).Done()); |
| 4400 | 4471 |
| 4401 SetReachable(block->normal_entry()); | 4472 for (intptr_t i = 0; i < block->SuccessorCount(); ++i) { |
| 4473 SetReachable(block->SuccessorAt(i)); | |
|
Kevin Millikin (Google)
2013/05/08 11:42:00
Hmm, this is a poor approximation. Can you add a
Florian Schneider
2013/05/08 17:10:55
Done.
| |
| 4474 } | |
| 4402 } | 4475 } |
| 4403 | 4476 |
| 4404 | 4477 |
| 4405 void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) { | 4478 void ConstantPropagator::VisitJoinEntry(JoinEntryInstr* block) { |
| 4406 // Phis are visited when visiting Goto at a predecessor. See VisitGoto. | 4479 // Phis are visited when visiting Goto at a predecessor. See VisitGoto. |
| 4407 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4480 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 4408 it.Current()->Accept(this); | 4481 it.Current()->Accept(this); |
| 4409 } | 4482 } |
| 4410 } | 4483 } |
| 4411 | 4484 |
| 4412 | 4485 |
| 4413 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { | 4486 void ConstantPropagator::VisitTargetEntry(TargetEntryInstr* block) { |
| 4414 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4487 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 4415 it.Current()->Accept(this); | 4488 it.Current()->Accept(this); |
| 4416 } | 4489 } |
| 4417 } | 4490 } |
| 4418 | 4491 |
| 4419 | 4492 |
| 4420 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { | 4493 void ConstantPropagator::VisitCatchBlockEntry(CatchBlockEntryInstr* block) { |
| 4494 const GrowableArray<Definition*>& defs = *block->initial_definitions(); | |
| 4495 for (intptr_t i = 0; i < defs.length(); ++i) { | |
| 4496 defs[i]->Accept(this); | |
| 4497 } | |
| 4421 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4498 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 4422 it.Current()->Accept(this); | 4499 it.Current()->Accept(this); |
| 4423 } | 4500 } |
| 4424 } | 4501 } |
| 4425 | 4502 |
| 4426 | 4503 |
| 4427 void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) { | 4504 void ConstantPropagator::VisitParallelMove(ParallelMoveInstr* instr) { |
| 4428 // Parallel moves have not yet been inserted in the graph. | 4505 // Parallel moves have not yet been inserted in the graph. |
| 4429 UNREACHABLE(); | 4506 UNREACHABLE(); |
| 4430 } | 4507 } |
| (...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5217 BlockEntryInstr* block = block_worklist_.RemoveLast(); | 5294 BlockEntryInstr* block = block_worklist_.RemoveLast(); |
| 5218 block->Accept(this); | 5295 block->Accept(this); |
| 5219 } | 5296 } |
| 5220 } | 5297 } |
| 5221 } | 5298 } |
| 5222 | 5299 |
| 5223 | 5300 |
| 5224 void ConstantPropagator::VisitBranches() { | 5301 void ConstantPropagator::VisitBranches() { |
| 5225 GraphEntryInstr* entry = graph_->graph_entry(); | 5302 GraphEntryInstr* entry = graph_->graph_entry(); |
| 5226 reachable_->Add(entry->preorder_number()); | 5303 reachable_->Add(entry->preorder_number()); |
| 5227 // TODO(fschneider): Handle CatchEntry. | 5304 block_worklist_.Add(entry); |
| 5228 reachable_->Add(entry->normal_entry()->preorder_number()); | |
| 5229 block_worklist_.Add(entry->normal_entry()); | |
| 5230 | 5305 |
| 5231 while (!block_worklist_.is_empty()) { | 5306 while (!block_worklist_.is_empty()) { |
| 5232 BlockEntryInstr* block = block_worklist_.RemoveLast(); | 5307 BlockEntryInstr* block = block_worklist_.RemoveLast(); |
| 5308 if (block->IsGraphEntry()) { | |
| 5309 for (intptr_t i = 0; i < block->SuccessorCount(); ++i) { | |
| 5310 SetReachable(block->SuccessorAt(i)); | |
| 5311 } | |
| 5312 continue; | |
| 5313 } | |
| 5233 Instruction* last = block->last_instruction(); | 5314 Instruction* last = block->last_instruction(); |
| 5234 if (last->IsGoto()) { | 5315 if (last->IsGoto()) { |
| 5235 SetReachable(last->AsGoto()->successor()); | 5316 SetReachable(last->AsGoto()->successor()); |
| 5236 } else if (last->IsBranch()) { | 5317 } else if (last->IsBranch()) { |
| 5237 BranchInstr* branch = last->AsBranch(); | 5318 BranchInstr* branch = last->AsBranch(); |
| 5238 // The current block must be reachable. | 5319 // The current block must be reachable. |
| 5239 ASSERT(reachable_->Contains(branch->GetBlock()->preorder_number())); | 5320 ASSERT(reachable_->Contains(branch->GetBlock()->preorder_number())); |
| 5240 if (branch->constant_target() != NULL) { | 5321 if (branch->constant_target() != NULL) { |
| 5241 // Found constant target computed by range analysis. | 5322 // Found constant target computed by range analysis. |
| 5242 if (branch->constant_target() == branch->true_successor()) { | 5323 if (branch->constant_target() == branch->true_successor()) { |
| (...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5790 if (changed) { | 5871 if (changed) { |
| 5791 // We may have changed the block order and the dominator tree. | 5872 // We may have changed the block order and the dominator tree. |
| 5792 flow_graph->DiscoverBlocks(); | 5873 flow_graph->DiscoverBlocks(); |
| 5793 GrowableArray<BitVector*> dominance_frontier; | 5874 GrowableArray<BitVector*> dominance_frontier; |
| 5794 flow_graph->ComputeDominators(&dominance_frontier); | 5875 flow_graph->ComputeDominators(&dominance_frontier); |
| 5795 } | 5876 } |
| 5796 } | 5877 } |
| 5797 | 5878 |
| 5798 | 5879 |
| 5799 } // namespace dart | 5880 } // namespace dart |
| OLD | NEW |