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 4347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4358 if (!reachable_->Contains(block->preorder_number())) { | 4358 if (!reachable_->Contains(block->preorder_number())) { |
4359 if (FLAG_trace_constant_propagation) { | 4359 if (FLAG_trace_constant_propagation) { |
4360 OS::Print("Unreachable B%"Pd"\n", block->block_id()); | 4360 OS::Print("Unreachable B%"Pd"\n", block->block_id()); |
4361 } | 4361 } |
4362 // Remove all uses in unreachable blocks. | 4362 // Remove all uses in unreachable blocks. |
4363 if (join != NULL) { | 4363 if (join != NULL) { |
4364 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 4364 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
4365 it.Current()->UnuseAllInputs(); | 4365 it.Current()->UnuseAllInputs(); |
4366 } | 4366 } |
4367 } | 4367 } |
| 4368 block->UnuseAllInputs(); |
4368 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 4369 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
4369 it.Current()->UnuseAllInputs(); | 4370 it.Current()->UnuseAllInputs(); |
4370 } | 4371 } |
4371 continue; | 4372 continue; |
4372 } | 4373 } |
4373 | 4374 |
4374 if (join != NULL) { | 4375 if (join != NULL) { |
4375 // Remove phi inputs corresponding to unreachable predecessor blocks. | 4376 // Remove phi inputs corresponding to unreachable predecessor blocks. |
4376 // Predecessors will be recomputed (in block id order) after removing | 4377 // Predecessors will be recomputed (in block id order) after removing |
4377 // unreachable code so we merely have to keep the phi inputs in order. | 4378 // unreachable code so we merely have to keep the phi inputs in order. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4450 TargetEntryInstr* if_true = branch->true_successor(); | 4451 TargetEntryInstr* if_true = branch->true_successor(); |
4451 TargetEntryInstr* if_false = branch->false_successor(); | 4452 TargetEntryInstr* if_false = branch->false_successor(); |
4452 JoinEntryInstr* join = NULL; | 4453 JoinEntryInstr* join = NULL; |
4453 Instruction* next = NULL; | 4454 Instruction* next = NULL; |
4454 | 4455 |
4455 if (!reachable_->Contains(if_true->preorder_number())) { | 4456 if (!reachable_->Contains(if_true->preorder_number())) { |
4456 ASSERT(reachable_->Contains(if_false->preorder_number())); | 4457 ASSERT(reachable_->Contains(if_false->preorder_number())); |
4457 ASSERT(if_false->parallel_move() == NULL); | 4458 ASSERT(if_false->parallel_move() == NULL); |
4458 ASSERT(if_false->loop_info() == NULL); | 4459 ASSERT(if_false->loop_info() == NULL); |
4459 join = new JoinEntryInstr(if_false->block_id(), if_false->try_index()); | 4460 join = new JoinEntryInstr(if_false->block_id(), if_false->try_index()); |
| 4461 join->InheritDeoptTarget(if_false); |
| 4462 if_false->UnuseAllInputs(); |
4460 next = if_false->next(); | 4463 next = if_false->next(); |
4461 } else if (!reachable_->Contains(if_false->preorder_number())) { | 4464 } else if (!reachable_->Contains(if_false->preorder_number())) { |
4462 ASSERT(if_true->parallel_move() == NULL); | 4465 ASSERT(if_true->parallel_move() == NULL); |
4463 ASSERT(if_true->loop_info() == NULL); | 4466 ASSERT(if_true->loop_info() == NULL); |
4464 join = new JoinEntryInstr(if_true->block_id(), if_true->try_index()); | 4467 join = new JoinEntryInstr(if_true->block_id(), if_true->try_index()); |
| 4468 join->InheritDeoptTarget(if_true); |
| 4469 if_true->UnuseAllInputs(); |
4465 next = if_true->next(); | 4470 next = if_true->next(); |
4466 } | 4471 } |
4467 | 4472 |
4468 if (join != NULL) { | 4473 if (join != NULL) { |
4469 // Replace the branch with a jump to the reachable successor. | 4474 // Replace the branch with a jump to the reachable successor. |
4470 // Drop the comparison, which does not have side effects as long | 4475 // Drop the comparison, which does not have side effects as long |
4471 // as it is a strict compare (the only one we can determine is | 4476 // as it is a strict compare (the only one we can determine is |
4472 // constant with the current analysis). | 4477 // constant with the current analysis). |
4473 GotoInstr* jump = new GotoInstr(join); | 4478 GotoInstr* jump = new GotoInstr(join); |
| 4479 jump->InheritDeoptTarget(branch); |
| 4480 |
4474 Instruction* previous = branch->previous(); | 4481 Instruction* previous = branch->previous(); |
4475 branch->set_previous(NULL); | 4482 branch->set_previous(NULL); |
4476 previous->LinkTo(jump); | 4483 previous->LinkTo(jump); |
| 4484 |
4477 // Replace the false target entry with the new join entry. We will | 4485 // Replace the false target entry with the new join entry. We will |
4478 // recompute the dominators after this pass. | 4486 // recompute the dominators after this pass. |
4479 join->LinkTo(next); | 4487 join->LinkTo(next); |
4480 branch->UnuseAllInputs(); | 4488 branch->UnuseAllInputs(); |
4481 } | 4489 } |
4482 } | 4490 } |
4483 } | 4491 } |
4484 | 4492 |
4485 graph_->DiscoverBlocks(); | 4493 graph_->DiscoverBlocks(); |
4486 GrowableArray<BitVector*> dominance_frontier; | 4494 GrowableArray<BitVector*> dominance_frontier; |
4487 graph_->ComputeDominators(&dominance_frontier); | 4495 graph_->ComputeDominators(&dominance_frontier); |
4488 | 4496 |
4489 if (FLAG_trace_constant_propagation) { | 4497 if (FLAG_trace_constant_propagation) { |
4490 OS::Print("\n==== After constant propagation ====\n"); | 4498 OS::Print("\n==== After constant propagation ====\n"); |
4491 FlowGraphPrinter printer(*graph_); | 4499 FlowGraphPrinter printer(*graph_); |
4492 printer.PrintBlocks(); | 4500 printer.PrintBlocks(); |
4493 } | 4501 } |
4494 } | 4502 } |
4495 | 4503 |
4496 | 4504 |
| 4505 // Returns true if the given phi has a single input use and |
| 4506 // is used in the environments either at the corresponding block entry or |
| 4507 // at the same instruction where input use is. |
| 4508 static bool PhiHasSingleUse(PhiInstr* phi, Value* use) { |
| 4509 if ((use->next_use() != NULL) || (phi->input_use_list() != use)) { |
| 4510 return false; |
| 4511 } |
| 4512 |
| 4513 BlockEntryInstr* block = phi->block(); |
| 4514 for (Value* env_use = phi->env_use_list(); |
| 4515 env_use != NULL; |
| 4516 env_use = env_use->next_use()) { |
| 4517 if ((env_use->instruction() != block) && |
| 4518 (env_use->instruction() != use->instruction())) { |
| 4519 return false; |
| 4520 } |
| 4521 } |
| 4522 |
| 4523 return true; |
| 4524 } |
| 4525 |
| 4526 |
4497 bool BranchSimplifier::Match(JoinEntryInstr* block) { | 4527 bool BranchSimplifier::Match(JoinEntryInstr* block) { |
4498 // Match the pattern of a branch on a comparison whose left operand is a | 4528 // Match the pattern of a branch on a comparison whose left operand is a |
4499 // phi from the same block, and whose right operand is a constant. | 4529 // phi from the same block, and whose right operand is a constant. |
4500 // | 4530 // |
4501 // Branch(Comparison(kind, Phi, Constant)) | 4531 // Branch(Comparison(kind, Phi, Constant)) |
4502 // | 4532 // |
4503 // These are the branches produced by inlining in a test context. Also, | 4533 // These are the branches produced by inlining in a test context. Also, |
4504 // the phi and the constant have no other uses so they can simply be | 4534 // the phi and the constant have no other uses so they can simply be |
4505 // eliminated. The block has no other phis and no instructions | 4535 // eliminated. The block has no other phis and no instructions |
4506 // intervening between the phi, constant, and branch so the block can | 4536 // intervening between the phi, constant, and branch so the block can |
4507 // simply be eliminated. | 4537 // simply be eliminated. |
4508 BranchInstr* branch = block->last_instruction()->AsBranch(); | 4538 BranchInstr* branch = block->last_instruction()->AsBranch(); |
4509 ASSERT(branch != NULL); | 4539 ASSERT(branch != NULL); |
4510 ComparisonInstr* comparison = branch->comparison(); | 4540 ComparisonInstr* comparison = branch->comparison(); |
4511 Value* left = comparison->left(); | 4541 Value* left = comparison->left(); |
4512 PhiInstr* phi = left->definition()->AsPhi(); | 4542 PhiInstr* phi = left->definition()->AsPhi(); |
4513 Value* right = comparison->right(); | 4543 Value* right = comparison->right(); |
4514 ConstantInstr* constant = right->definition()->AsConstant(); | 4544 ConstantInstr* constant = right->definition()->AsConstant(); |
4515 return (phi != NULL) && | 4545 return (phi != NULL) && |
4516 (constant != NULL) && | 4546 (constant != NULL) && |
4517 (phi->GetBlock() == block) && | 4547 (phi->GetBlock() == block) && |
4518 phi->HasOnlyUse(left) && | 4548 PhiHasSingleUse(phi, left) && |
4519 constant->HasOnlyUse(right) && | 4549 constant->HasOnlyUse(right) && |
4520 (block->next() == constant) && | 4550 (block->next() == constant) && |
4521 (constant->next() == branch) && | 4551 (constant->next() == branch) && |
4522 (block->phis()->length() == 1); | 4552 (block->phis()->length() == 1); |
4523 } | 4553 } |
4524 | 4554 |
4525 | 4555 |
4526 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { | 4556 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { |
4527 // Convert a target block into a join block. Branches will be duplicated | 4557 // Convert a target block into a join block. Branches will be duplicated |
4528 // so the former true and false targets become joins of the control flows | 4558 // so the former true and false targets become joins of the control flows |
4529 // from all the duplicated branches. | 4559 // from all the duplicated branches. |
4530 JoinEntryInstr* join = | 4560 JoinEntryInstr* join = |
4531 new JoinEntryInstr(target->block_id(), target->try_index()); | 4561 new JoinEntryInstr(target->block_id(), target->try_index()); |
| 4562 join->InheritDeoptTarget(target); |
4532 join->LinkTo(target->next()); | 4563 join->LinkTo(target->next()); |
4533 join->set_last_instruction(target->last_instruction()); | 4564 join->set_last_instruction(target->last_instruction()); |
| 4565 target->UnuseAllInputs(); |
4534 return join; | 4566 return join; |
4535 } | 4567 } |
4536 | 4568 |
4537 | 4569 |
4538 ConstantInstr* BranchSimplifier::CloneConstant(FlowGraph* flow_graph, | 4570 ConstantInstr* BranchSimplifier::CloneConstant(FlowGraph* flow_graph, |
4539 ConstantInstr* constant) { | 4571 ConstantInstr* constant) { |
4540 ConstantInstr* new_constant = new ConstantInstr(constant->value()); | 4572 ConstantInstr* new_constant = new ConstantInstr(constant->value()); |
4541 new_constant->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); | 4573 new_constant->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); |
4542 return new_constant; | 4574 return new_constant; |
4543 } | 4575 } |
4544 | 4576 |
4545 | 4577 |
4546 BranchInstr* BranchSimplifier::CloneBranch(BranchInstr* branch, | 4578 BranchInstr* BranchSimplifier::CloneBranch(BranchInstr* branch, |
4547 Value* left, | 4579 Value* left, |
4548 Value* right) { | 4580 Value* right) { |
4549 ComparisonInstr* comparison = branch->comparison(); | 4581 ComparisonInstr* comparison = branch->comparison(); |
4550 ComparisonInstr* new_comparison = NULL; | 4582 ComparisonInstr* new_comparison = NULL; |
4551 if (comparison->IsStrictCompare()) { | 4583 if (comparison->IsStrictCompare()) { |
4552 new_comparison = new StrictCompareInstr(comparison->kind(), left, right); | 4584 new_comparison = new StrictCompareInstr(comparison->kind(), left, right); |
4553 } else if (comparison->IsEqualityCompare()) { | 4585 } else if (comparison->IsEqualityCompare()) { |
4554 new_comparison = | 4586 EqualityCompareInstr* equality_compare = comparison->AsEqualityCompare(); |
4555 new EqualityCompareInstr(comparison->AsEqualityCompare()->token_pos(), | 4587 EqualityCompareInstr* new_equality_compare = |
| 4588 new EqualityCompareInstr(equality_compare->token_pos(), |
4556 comparison->kind(), | 4589 comparison->kind(), |
4557 left, | 4590 left, |
4558 right); | 4591 right); |
| 4592 new_equality_compare->set_ic_data(equality_compare->ic_data()); |
| 4593 new_comparison = new_equality_compare; |
4559 } else { | 4594 } else { |
4560 ASSERT(comparison->IsRelationalOp()); | 4595 ASSERT(comparison->IsRelationalOp()); |
4561 new_comparison = | 4596 RelationalOpInstr* relational_op = comparison->AsRelationalOp(); |
4562 new RelationalOpInstr(comparison->AsRelationalOp()->token_pos(), | 4597 RelationalOpInstr* new_relational_op = |
| 4598 new RelationalOpInstr(relational_op->token_pos(), |
4563 comparison->kind(), | 4599 comparison->kind(), |
4564 left, | 4600 left, |
4565 right); | 4601 right); |
| 4602 new_relational_op->set_ic_data(relational_op->ic_data()); |
| 4603 new_comparison = new_relational_op; |
4566 } | 4604 } |
4567 return new BranchInstr(new_comparison, branch->is_checked()); | 4605 return new BranchInstr(new_comparison, branch->is_checked()); |
4568 } | 4606 } |
4569 | 4607 |
4570 | 4608 |
4571 void BranchSimplifier::Simplify(FlowGraph* flow_graph) { | 4609 void BranchSimplifier::Simplify(FlowGraph* flow_graph) { |
4572 // Optimize some branches that test the value of a phi. When it is safe | 4610 // Optimize some branches that test the value of a phi. When it is safe |
4573 // to do so, push the branch to each of the predecessor blocks. This is | 4611 // to do so, push the branch to each of the predecessor blocks. This is |
4574 // an optimization when (a) it can avoid materializing a boolean object at | 4612 // an optimization when (a) it can avoid materializing a boolean object at |
4575 // the phi only to test its value, and (b) it can expose opportunities for | 4613 // the phi only to test its value, and (b) it can expose opportunities for |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4624 | 4662 |
4625 // Insert a copy of the constant in all the predecessors. | 4663 // Insert a copy of the constant in all the predecessors. |
4626 ConstantInstr* new_constant = CloneConstant(flow_graph, constant); | 4664 ConstantInstr* new_constant = CloneConstant(flow_graph, constant); |
4627 new_constant->InsertBefore(old_goto); | 4665 new_constant->InsertBefore(old_goto); |
4628 | 4666 |
4629 // Replace the goto in each predecessor with a rewritten branch, | 4667 // Replace the goto in each predecessor with a rewritten branch, |
4630 // rewritten to use the corresponding phi input instead of the phi. | 4668 // rewritten to use the corresponding phi input instead of the phi. |
4631 Value* new_left = phi->InputAt(i)->Copy(); | 4669 Value* new_left = phi->InputAt(i)->Copy(); |
4632 Value* new_right = new Value(new_constant); | 4670 Value* new_right = new Value(new_constant); |
4633 BranchInstr* new_branch = CloneBranch(branch, new_left, new_right); | 4671 BranchInstr* new_branch = CloneBranch(branch, new_left, new_right); |
| 4672 new_branch->InheritDeoptTarget(old_goto); |
4634 new_branch->InsertBefore(old_goto); | 4673 new_branch->InsertBefore(old_goto); |
4635 new_branch->set_next(NULL); // Detaching the goto from the graph. | 4674 new_branch->set_next(NULL); // Detaching the goto from the graph. |
4636 old_goto->UnuseAllInputs(); | 4675 old_goto->UnuseAllInputs(); |
4637 | 4676 |
4638 // Update the predecessor block. We may have created another | 4677 // Update the predecessor block. We may have created another |
4639 // instance of the pattern so add it to the worklist if necessary. | 4678 // instance of the pattern so add it to the worklist if necessary. |
4640 BlockEntryInstr* branch_block = new_branch->GetBlock(); | 4679 BlockEntryInstr* branch_block = new_branch->GetBlock(); |
4641 branch_block->set_last_instruction(new_branch); | 4680 branch_block->set_last_instruction(new_branch); |
4642 if (branch_block->IsJoinEntry()) worklist.Add(branch_block); | 4681 if (branch_block->IsJoinEntry()) worklist.Add(branch_block); |
4643 | 4682 |
4644 // Connect the branch to the true and false joins, via empty target | 4683 // Connect the branch to the true and false joins, via empty target |
4645 // blocks. | 4684 // blocks. |
4646 TargetEntryInstr* true_target = | 4685 TargetEntryInstr* true_target = |
4647 new TargetEntryInstr(flow_graph->max_block_id() + 1, | 4686 new TargetEntryInstr(flow_graph->max_block_id() + 1, |
4648 block->try_index()); | 4687 block->try_index()); |
| 4688 true_target->InheritDeoptTarget(join_true); |
4649 TargetEntryInstr* false_target = | 4689 TargetEntryInstr* false_target = |
4650 new TargetEntryInstr(flow_graph->max_block_id() + 2, | 4690 new TargetEntryInstr(flow_graph->max_block_id() + 2, |
4651 block->try_index()); | 4691 block->try_index()); |
| 4692 false_target->InheritDeoptTarget(join_false); |
4652 flow_graph->set_max_block_id(flow_graph->max_block_id() + 2); | 4693 flow_graph->set_max_block_id(flow_graph->max_block_id() + 2); |
4653 *new_branch->true_successor_address() = true_target; | 4694 *new_branch->true_successor_address() = true_target; |
4654 *new_branch->false_successor_address() = false_target; | 4695 *new_branch->false_successor_address() = false_target; |
4655 GotoInstr* goto_true = new GotoInstr(join_true); | 4696 GotoInstr* goto_true = new GotoInstr(join_true); |
| 4697 goto_true->InheritDeoptTarget(join_true); |
4656 true_target->LinkTo(goto_true); | 4698 true_target->LinkTo(goto_true); |
4657 true_target->set_last_instruction(goto_true); | 4699 true_target->set_last_instruction(goto_true); |
4658 GotoInstr* goto_false = new GotoInstr(join_false); | 4700 GotoInstr* goto_false = new GotoInstr(join_false); |
| 4701 goto_false->InheritDeoptTarget(join_false); |
4659 false_target->LinkTo(goto_false); | 4702 false_target->LinkTo(goto_false); |
4660 false_target->set_last_instruction(goto_false); | 4703 false_target->set_last_instruction(goto_false); |
4661 } | 4704 } |
4662 // When all predecessors have been rewritten, the original block is | 4705 // When all predecessors have been rewritten, the original block is |
4663 // unreachable from the graph. | 4706 // unreachable from the graph. |
4664 phi->UnuseAllInputs(); | 4707 phi->UnuseAllInputs(); |
4665 branch->UnuseAllInputs(); | 4708 branch->UnuseAllInputs(); |
| 4709 block->UnuseAllInputs(); |
4666 } | 4710 } |
4667 } | 4711 } |
4668 | 4712 |
4669 if (changed) { | 4713 if (changed) { |
4670 // We may have changed the block order and the dominator tree. | 4714 // We may have changed the block order and the dominator tree. |
4671 flow_graph->DiscoverBlocks(); | 4715 flow_graph->DiscoverBlocks(); |
4672 GrowableArray<BitVector*> dominance_frontier; | 4716 GrowableArray<BitVector*> dominance_frontier; |
4673 flow_graph->ComputeDominators(&dominance_frontier); | 4717 flow_graph->ComputeDominators(&dominance_frontier); |
4674 } | 4718 } |
4675 } | 4719 } |
4676 | 4720 |
4677 | 4721 |
4678 } // namespace dart | 4722 } // namespace dart |
OLD | NEW |