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" |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 const Representation to_rep = | 376 const Representation to_rep = |
| 377 use->instruction()->RequiredInputRepresentation(use->use_index()); | 377 use->instruction()->RequiredInputRepresentation(use->use_index()); |
| 378 if (from_rep == to_rep) { | 378 if (from_rep == to_rep) { |
| 379 continue; | 379 continue; |
| 380 } | 380 } |
| 381 | 381 |
| 382 Instruction* insert_before; | 382 Instruction* insert_before; |
| 383 Instruction* deopt_target; | 383 Instruction* deopt_target; |
| 384 PhiInstr* phi = use->instruction()->AsPhi(); | 384 PhiInstr* phi = use->instruction()->AsPhi(); |
| 385 if (phi != NULL) { | 385 if (phi != NULL) { |
| 386 if (!phi->is_alive()) continue; | 386 ASSERT(phi->is_alive()); |
| 387 | |
| 388 // For phis conversions have to be inserted in the predecessor. | 387 // For phis conversions have to be inserted in the predecessor. |
| 389 insert_before = | 388 insert_before = |
| 390 phi->block()->PredecessorAt(use->use_index())->last_instruction(); | 389 phi->block()->PredecessorAt(use->use_index())->last_instruction(); |
| 391 deopt_target = NULL; | 390 deopt_target = NULL; |
| 392 } else { | 391 } else { |
| 393 deopt_target = insert_before = use->instruction(); | 392 deopt_target = insert_before = use->instruction(); |
| 394 } | 393 } |
| 395 | 394 |
| 396 InsertConversion(from_rep, to_rep, use, insert_before, deopt_target); | 395 InsertConversion(from_rep, to_rep, use, insert_before, deopt_target); |
| 397 } | 396 } |
| 398 } | 397 } |
| 399 | 398 |
| 400 | 399 |
| 401 void FlowGraphOptimizer::SelectRepresentations() { | 400 void FlowGraphOptimizer::SelectRepresentations() { |
| 402 // Convervatively unbox all phis that were proven to be of type Double. | 401 // Convervatively unbox all phis that were proven to be of type Double. |
| 403 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 402 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 404 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); | 403 JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry(); |
| 405 if (join_entry == NULL) continue; | 404 if (join_entry != NULL) { |
| 406 | 405 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { |
| 407 if (join_entry->phis() != NULL) { | 406 PhiInstr* phi = it.Current(); |
| 408 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { | 407 ASSERT(phi != NULL); |
| 409 PhiInstr* phi = (*join_entry->phis())[i]; | |
| 410 if (phi == NULL) continue; | |
| 411 if (phi->Type()->ToCid() == kDoubleCid) { | 408 if (phi->Type()->ToCid() == kDoubleCid) { |
| 412 phi->set_representation(kUnboxedDouble); | 409 phi->set_representation(kUnboxedDouble); |
| 413 } | 410 } |
| 414 } | 411 } |
| 415 } | 412 } |
| 416 } | 413 } |
| 417 | 414 |
| 418 // Process all instructions and insert conversions where needed. | 415 // Process all instructions and insert conversions where needed. |
| 419 GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry(); | 416 GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry(); |
| 420 | 417 |
| 421 // Visit incoming parameters and constants. | 418 // Visit incoming parameters and constants. |
| 422 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { | 419 for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) { |
| 423 InsertConversionsFor((*graph_entry->initial_definitions())[i]); | 420 InsertConversionsFor((*graph_entry->initial_definitions())[i]); |
| 424 } | 421 } |
| 425 | 422 |
| 426 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 423 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 427 BlockEntryInstr* entry = block_order_[i]; | 424 BlockEntryInstr* entry = block_order_[i]; |
| 428 | |
| 429 JoinEntryInstr* join_entry = entry->AsJoinEntry(); | 425 JoinEntryInstr* join_entry = entry->AsJoinEntry(); |
| 430 if ((join_entry != NULL) && (join_entry->phis() != NULL)) { | 426 if (join_entry != NULL) { |
| 431 for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) { | 427 for (PhiIterator it(join_entry); !it.Done(); it.Advance()) { |
| 432 PhiInstr* phi = (*join_entry->phis())[i]; | 428 PhiInstr* phi = it.Current(); |
| 433 if ((phi != NULL) && (phi->is_alive())) { | 429 ASSERT(phi != NULL); |
| 434 InsertConversionsFor(phi); | 430 ASSERT(phi->is_alive()); |
| 435 } | 431 InsertConversionsFor(phi); |
| 436 } | 432 } |
| 437 } | 433 } |
| 438 | |
| 439 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 434 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 440 Definition* def = it.Current()->AsDefinition(); | 435 Definition* def = it.Current()->AsDefinition(); |
| 441 if (def != NULL) { | 436 if (def != NULL) { |
| 442 InsertConversionsFor(def); | 437 InsertConversionsFor(def); |
| 443 } | 438 } |
| 444 } | 439 } |
| 445 } | 440 } |
| 446 } | 441 } |
| 447 | 442 |
| 448 | 443 |
| (...skipping 1800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2249 void RangeAnalysis::RenameDominatedUses(Definition* def, | 2244 void RangeAnalysis::RenameDominatedUses(Definition* def, |
| 2250 Instruction* dom, | 2245 Instruction* dom, |
| 2251 Definition* other) { | 2246 Definition* other) { |
| 2252 for (Value::Iterator it(def->input_use_list()); | 2247 for (Value::Iterator it(def->input_use_list()); |
| 2253 !it.Done(); | 2248 !it.Done(); |
| 2254 it.Advance()) { | 2249 it.Advance()) { |
| 2255 Value* use = it.Current(); | 2250 Value* use = it.Current(); |
| 2256 | 2251 |
| 2257 // Skip dead phis. | 2252 // Skip dead phis. |
| 2258 PhiInstr* phi = use->instruction()->AsPhi(); | 2253 PhiInstr* phi = use->instruction()->AsPhi(); |
| 2259 if ((phi != NULL) && !phi->is_alive()) continue; | 2254 ASSERT((phi == NULL) || phi->is_alive()); |
| 2260 | |
| 2261 if (IsDominatedUse(dom, use)) { | 2255 if (IsDominatedUse(dom, use)) { |
| 2262 use->BindTo(other); | 2256 use->BindTo(other); |
| 2263 } | 2257 } |
| 2264 } | 2258 } |
| 2265 } | 2259 } |
| 2266 | 2260 |
| 2267 | 2261 |
| 2268 // For a comparison operation return an operation for the equivalent flipped | 2262 // For a comparison operation return an operation for the equivalent flipped |
| 2269 // comparison: a (op) b === b (op') a. | 2263 // comparison: a (op) b === b (op') a. |
| 2270 static Token::Kind FlipComparison(Token::Kind op) { | 2264 static Token::Kind FlipComparison(Token::Kind op) { |
| (...skipping 1098 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3369 // All phis in the worklist are redundant and have the same computed | 3363 // All phis in the worklist are redundant and have the same computed |
| 3370 // value on all code paths. | 3364 // value on all code paths. |
| 3371 ASSERT(value != NULL); | 3365 ASSERT(value != NULL); |
| 3372 for (intptr_t i = 0; i < worklist_.length(); i++) { | 3366 for (intptr_t i = 0; i < worklist_.length(); i++) { |
| 3373 worklist_[i]->ReplaceUsesWith(value); | 3367 worklist_[i]->ReplaceUsesWith(value); |
| 3374 } | 3368 } |
| 3375 | 3369 |
| 3376 return true; | 3370 return true; |
| 3377 } | 3371 } |
| 3378 | 3372 |
| 3379 // Emit non-redundant phis created during ComputeOutValues and ForwardLoads. | 3373 // Phis have not yet been inserted into the graph but they have uses of |
| 3374 // their inputs. Insert the non-redundant ones and clear the input uses | |
| 3375 // of the redundant ones. | |
| 3380 void EmitPhis() { | 3376 void EmitPhis() { |
| 3381 for (intptr_t i = 0; i < phis_.length(); i++) { | 3377 for (intptr_t i = 0; i < phis_.length(); i++) { |
| 3382 PhiInstr* phi = phis_[i]; | 3378 PhiInstr* phi = phis_[i]; |
| 3383 if ((phi->input_use_list() != NULL) && !EliminateRedundantPhi(phi)) { | 3379 if ((phi->input_use_list() != NULL) && !EliminateRedundantPhi(phi)) { |
| 3384 phi->mark_alive(); | 3380 phi->mark_alive(); |
| 3385 phi->block()->InsertPhi(phi); | 3381 phi->block()->InsertPhi(phi); |
| 3382 } else { | |
| 3383 for (intptr_t j = phi->InputCount() - 1; j >= 0; --j) { | |
| 3384 phi->InputAt(j)->RemoveFromUseList(); | |
| 3385 } | |
| 3386 } | 3386 } |
| 3387 } | 3387 } |
| 3388 } | 3388 } |
| 3389 | 3389 |
| 3390 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { | 3390 ZoneGrowableArray<Definition*>* CreateBlockOutValues() { |
| 3391 ZoneGrowableArray<Definition*>* out = | 3391 ZoneGrowableArray<Definition*>* out = |
| 3392 new ZoneGrowableArray<Definition*>(max_expr_id_); | 3392 new ZoneGrowableArray<Definition*>(max_expr_id_); |
| 3393 for (intptr_t i = 0; i < max_expr_id_; i++) { | 3393 for (intptr_t i = 0; i < max_expr_id_; i++) { |
| 3394 out->Add(NULL); | 3394 out->Add(NULL); |
| 3395 } | 3395 } |
| (...skipping 848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4244 it.Current()->UnuseAllInputs(); | 4244 it.Current()->UnuseAllInputs(); |
| 4245 } | 4245 } |
| 4246 continue; | 4246 continue; |
| 4247 } | 4247 } |
| 4248 | 4248 |
| 4249 if (join != NULL) { | 4249 if (join != NULL) { |
| 4250 // Remove phi inputs corresponding to unreachable predecessor blocks. | 4250 // Remove phi inputs corresponding to unreachable predecessor blocks. |
| 4251 // Predecessors will be recomputed (in block id order) after removing | 4251 // Predecessors will be recomputed (in block id order) after removing |
| 4252 // unreachable code so we merely have to keep the phi inputs in order. | 4252 // unreachable code so we merely have to keep the phi inputs in order. |
| 4253 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 4253 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 4254 if (phis != NULL) { | 4254 if ((phis != NULL) && !phis->is_empty()) { |
| 4255 intptr_t pred_count = join->PredecessorCount(); | 4255 intptr_t pred_count = join->PredecessorCount(); |
| 4256 intptr_t live_count = 0; | 4256 intptr_t live_count = 0; |
| 4257 for (intptr_t pred_idx = 0; pred_idx < pred_count; ++pred_idx) { | 4257 for (intptr_t pred_idx = 0; pred_idx < pred_count; ++pred_idx) { |
| 4258 if (reachable_->Contains( | 4258 if (reachable_->Contains( |
| 4259 join->PredecessorAt(pred_idx)->preorder_number())) { | 4259 join->PredecessorAt(pred_idx)->preorder_number())) { |
| 4260 if (live_count < pred_idx) { | 4260 if (live_count < pred_idx) { |
| 4261 for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) { | 4261 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 4262 PhiInstr* phi = (*phis)[phi_idx]; | 4262 PhiInstr* phi = it.Current(); |
| 4263 if (phi == NULL) continue; | 4263 ASSERT(phi != NULL); |
| 4264 phi->SetInputAt(live_count, phi->InputAt(pred_idx)); | 4264 phi->SetInputAt(live_count, phi->InputAt(pred_idx)); |
| 4265 } | 4265 } |
| 4266 } | 4266 } |
| 4267 ++live_count; | 4267 ++live_count; |
| 4268 } else { | 4268 } else { |
| 4269 for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) { | 4269 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 4270 PhiInstr* phi = (*phis)[phi_idx]; | 4270 PhiInstr* phi = it.Current(); |
| 4271 if (phi == NULL) continue; | 4271 ASSERT(phi != NULL); |
| 4272 phi->InputAt(pred_idx)->RemoveFromUseList(); | 4272 phi->InputAt(pred_idx)->RemoveFromUseList(); |
| 4273 } | 4273 } |
| 4274 } | 4274 } |
| 4275 } | 4275 } |
| 4276 if (live_count < pred_count) { | 4276 if (live_count < pred_count) { |
| 4277 for (intptr_t phi_idx = 0; phi_idx < phis->length(); ++phi_idx) { | 4277 intptr_t to_idx = 0; |
| 4278 PhiInstr* phi = (*phis)[phi_idx]; | 4278 for (intptr_t from_idx = 0; from_idx < phis->length(); ++from_idx) { |
| 4279 if (phi == NULL) continue; | 4279 PhiInstr* phi = (*phis)[from_idx]; |
| 4280 ASSERT(phi != NULL); | |
| 4280 if (FLAG_remove_redundant_phis && (live_count == 1)) { | 4281 if (FLAG_remove_redundant_phis && (live_count == 1)) { |
|
Vyacheslav Egorov (Google)
2013/02/27 21:53:02
Do we have any code that kills truly redundant phi
Kevin Millikin (Google)
2013/02/28 08:12:02
I don't think so. I wonder, do they arise?
| |
| 4281 Value* input = phi->InputAt(0); | 4282 Value* input = phi->InputAt(0); |
| 4282 phi->ReplaceUsesWith(input->definition()); | 4283 phi->ReplaceUsesWith(input->definition()); |
| 4283 input->RemoveFromUseList(); | 4284 input->RemoveFromUseList(); |
| 4284 (*phis)[phi_idx] = NULL; | |
| 4285 } else { | 4285 } else { |
| 4286 phi->inputs_.TruncateTo(live_count); | 4286 phi->inputs_.TruncateTo(live_count); |
| 4287 (*phis)[to_idx++] = phi; | |
| 4287 } | 4288 } |
| 4288 } | 4289 } |
| 4290 if (to_idx == 0) { | |
| 4291 join->phis_ = NULL; | |
| 4292 } else { | |
| 4293 phis->TruncateTo(to_idx); | |
| 4294 } | |
| 4289 } | 4295 } |
| 4290 } | 4296 } |
| 4291 } | 4297 } |
| 4292 | 4298 |
| 4293 for (ForwardInstructionIterator i(block); !i.Done(); i.Advance()) { | 4299 for (ForwardInstructionIterator i(block); !i.Done(); i.Advance()) { |
| 4294 Definition* defn = i.Current()->AsDefinition(); | 4300 Definition* defn = i.Current()->AsDefinition(); |
| 4295 // Replace constant-valued instructions without observable side | 4301 // Replace constant-valued instructions without observable side |
| 4296 // effects. Do this for smis only to avoid having to copy other | 4302 // effects. Do this for smis only to avoid having to copy other |
| 4297 // objects into the heap's old generation. | 4303 // objects into the heap's old generation. |
| 4298 if ((defn != NULL) && | 4304 if ((defn != NULL) && |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4357 | 4363 |
| 4358 if (FLAG_trace_constant_propagation) { | 4364 if (FLAG_trace_constant_propagation) { |
| 4359 OS::Print("\n==== After constant propagation ====\n"); | 4365 OS::Print("\n==== After constant propagation ====\n"); |
| 4360 FlowGraphPrinter printer(*graph_); | 4366 FlowGraphPrinter printer(*graph_); |
| 4361 printer.PrintBlocks(); | 4367 printer.PrintBlocks(); |
| 4362 } | 4368 } |
| 4363 } | 4369 } |
| 4364 | 4370 |
| 4365 | 4371 |
| 4366 } // namespace dart | 4372 } // namespace dart |
| OLD | NEW |