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