Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 12457034: Ensure that all goto instructions have deoptimization target. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698