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 4356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4367 graph_->ComputeDominators(&dominance_frontier); | 4367 graph_->ComputeDominators(&dominance_frontier); |
| 4368 | 4368 |
| 4369 if (FLAG_trace_constant_propagation) { | 4369 if (FLAG_trace_constant_propagation) { |
| 4370 OS::Print("\n==== After constant propagation ====\n"); | 4370 OS::Print("\n==== After constant propagation ====\n"); |
| 4371 FlowGraphPrinter printer(*graph_); | 4371 FlowGraphPrinter printer(*graph_); |
| 4372 printer.PrintBlocks(); | 4372 printer.PrintBlocks(); |
| 4373 } | 4373 } |
| 4374 } | 4374 } |
| 4375 | 4375 |
| 4376 | 4376 |
| 4377 bool BranchSimplifier::Match(JoinEntryInstr* block) { | |
| 4378 // Match the pattern of a branch on a comparison whose left operand is a | |
| 4379 // phi from the same block, and whose right operand is a constant. | |
| 4380 // | |
| 4381 // Branch(Comparison(kind, Phi, Constant)) | |
| 4382 // | |
| 4383 // These are the branches produced by inlining in a test context. Also, | |
| 4384 // the phi and the constant have no other uses so they can simply be | |
| 4385 // eliminated. The block has no other phis and no instructions | |
| 4386 // intervening between the phi, constant, and branch so the block can | |
| 4387 // simply be eliminated. | |
| 4388 BranchInstr* branch = block->last_instruction()->AsBranch(); | |
| 4389 ASSERT(branch != NULL); | |
| 4390 ComparisonInstr* comparison = branch->comparison(); | |
| 4391 Value* left = comparison->left(); | |
| 4392 PhiInstr* phi = left->definition()->AsPhi(); | |
| 4393 Value* right = comparison->right(); | |
| 4394 ConstantInstr* constant = right->definition()->AsConstant(); | |
| 4395 return (phi != NULL) && | |
| 4396 (constant != NULL) && | |
| 4397 (phi->GetBlock() == block) && | |
| 4398 phi->HasOnlyUse(left) && | |
| 4399 constant->HasOnlyUse(right) && | |
| 4400 (block->next() == constant) && | |
| 4401 (constant->next() == branch) && | |
| 4402 (block->phis()->length() == 1); | |
| 4403 } | |
| 4404 | |
| 4405 | |
| 4406 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { | |
| 4407 // Convert a target block into a join block. Branches will be duplicated | |
| 4408 // so the former true and false targets become joins of the control flows | |
| 4409 // from all the duplicated branches. | |
| 4410 JoinEntryInstr* join = | |
| 4411 new JoinEntryInstr(target->block_id(), target->try_index()); | |
| 4412 join->LinkTo(target->next()); | |
| 4413 join->set_last_instruction(target->last_instruction()); | |
| 4414 return join; | |
| 4415 } | |
| 4416 | |
| 4417 | |
| 4418 ConstantInstr* BranchSimplifier::CloneConstant(FlowGraph* flow_graph, | |
| 4419 ConstantInstr* constant) { | |
| 4420 ConstantInstr* new_constant = new ConstantInstr(constant->value()); | |
| 4421 new_constant->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index()); | |
| 4422 return new_constant; | |
| 4423 } | |
| 4424 | |
| 4425 | |
| 4426 BranchInstr* BranchSimplifier::RewriteBranch(BranchInstr* branch, | |
|
Vyacheslav Egorov (Google)
2013/03/06 16:44:22
I'd call it CloneBranch CloneRewrittenBranch or Cl
Kevin Millikin (Google)
2013/03/08 10:38:10
Functional update is the default :)
I'll change i
| |
| 4427 Value* left, | |
| 4428 Value* right) { | |
| 4429 ComparisonInstr* comparison = branch->comparison(); | |
| 4430 ComparisonInstr* new_comparison = NULL; | |
| 4431 if (comparison->IsStrictCompare()) { | |
| 4432 new_comparison = new StrictCompareInstr(comparison->kind(), left, right); | |
| 4433 } else if (comparison->IsEqualityCompare()) { | |
| 4434 new_comparison = | |
| 4435 new EqualityCompareInstr(comparison->AsEqualityCompare()->token_pos(), | |
| 4436 comparison->kind(), | |
| 4437 left, | |
| 4438 right); | |
| 4439 } else { | |
| 4440 ASSERT(comparison->IsRelationalOp()); | |
| 4441 new_comparison = | |
| 4442 new RelationalOpInstr(comparison->AsRelationalOp()->token_pos(), | |
| 4443 comparison->kind(), | |
| 4444 left, | |
| 4445 right); | |
| 4446 } | |
| 4447 return new BranchInstr(new_comparison, branch->is_checked()); | |
| 4448 } | |
| 4449 | |
| 4450 | |
| 4451 void BranchSimplifier::Simplify(FlowGraph* flow_graph) { | |
| 4452 // Optimize some branches that test the value of a phi. When it is safe | |
| 4453 // to do so, push the branch to each of the predecessor blocks. This is | |
| 4454 // an optimization when (a) it can avoid materializing a boolean object at | |
| 4455 // the phi only to test its value, and (b) it can expose opportunities for | |
| 4456 // constant propagation and unreachable code elimination. This | |
| 4457 // optimization is intended to run after inlining which creates | |
| 4458 // opportunities for optimization (a) and before constant folding which | |
| 4459 // can perform optimization (b). | |
| 4460 | |
| 4461 // Begin with a worklist of join blocks ending in branches. They are | |
| 4462 // candidates for the pattern below. | |
| 4463 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder(); | |
| 4464 GrowableArray<BlockEntryInstr*> worklist(postorder.length()); | |
| 4465 for (BlockIterator it(postorder); !it.Done(); it.Advance()) { | |
| 4466 BlockEntryInstr* block = it.Current(); | |
| 4467 if (block->IsJoinEntry() && block->last_instruction()->IsBranch()) { | |
| 4468 worklist.Add(block); | |
| 4469 } | |
| 4470 } | |
| 4471 | |
| 4472 // Rewrite until no more instance of the pattern exists. | |
| 4473 bool changed = false; | |
| 4474 while (!worklist.is_empty()) { | |
| 4475 // All blocks in the worklist are join blocks (ending with a branch). | |
| 4476 JoinEntryInstr* block = worklist.RemoveLast()->AsJoinEntry(); | |
| 4477 ASSERT(block != NULL); | |
| 4478 | |
| 4479 if (Match(block)) { | |
| 4480 changed = true; | |
| 4481 | |
| 4482 // The branch will be copied and pushed to all the join's | |
| 4483 // predecessors. Convert the true and false target blocks into join | |
| 4484 // blocks to join the control flows from all of the true | |
| 4485 // (respectively, false) targets of the copied branches. | |
| 4486 // | |
| 4487 // The converted join block will have no phis, so it cannot be another | |
| 4488 // instance of the pattern. There is thus no need to add it to the | |
| 4489 // worklist. | |
| 4490 BranchInstr* branch = block->last_instruction()->AsBranch(); | |
| 4491 ASSERT(branch != NULL); | |
| 4492 JoinEntryInstr* join_true = ToJoinEntry(branch->true_successor()); | |
| 4493 JoinEntryInstr* join_false = ToJoinEntry(branch->false_successor()); | |
| 4494 | |
| 4495 ComparisonInstr* comparison = branch->comparison(); | |
| 4496 PhiInstr* phi = comparison->left()->definition()->AsPhi(); | |
| 4497 ConstantInstr* constant = comparison->right()->definition()->AsConstant(); | |
| 4498 ASSERT(constant != NULL); | |
| 4499 // Copy the constant and branch and push it to all the predecessors. | |
| 4500 for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) { | |
| 4501 GotoInstr* old_goto = | |
| 4502 block->PredecessorAt(i)->last_instruction()->AsGoto(); | |
| 4503 ASSERT(old_goto != NULL); | |
| 4504 | |
| 4505 // Insert a copy of the constant in all the predecessors. | |
| 4506 ConstantInstr* new_constant = CloneConstant(flow_graph, constant); | |
| 4507 new_constant->InsertBefore(old_goto); | |
| 4508 | |
| 4509 // Replace the goto in each predecessor with a rewritten branch, | |
| 4510 // rewritten to use the corresponding phi input instead of the phi. | |
| 4511 Value* new_left = phi->InputAt(i)->Copy(); | |
| 4512 Value* new_right = new Value(new_constant); | |
| 4513 BranchInstr* new_branch = RewriteBranch(branch, new_left, new_right); | |
| 4514 new_branch->InsertBefore(old_goto); | |
| 4515 new_branch->set_next(NULL); // Detaching the goto from the graph. | |
| 4516 old_goto->UnuseAllInputs(); | |
| 4517 | |
| 4518 // Update the predecessor block. We may have created another | |
| 4519 // instance of the pattern so add it to the worklist if necessary. | |
| 4520 BlockEntryInstr* branch_block = new_branch->GetBlock(); | |
| 4521 branch_block->set_last_instruction(new_branch); | |
| 4522 if (branch_block->IsJoinEntry()) worklist.Add(branch_block); | |
| 4523 | |
| 4524 // Connect the branch to the true and false joins, via empty target | |
| 4525 // blocks. | |
| 4526 TargetEntryInstr* true_target = | |
| 4527 new TargetEntryInstr(flow_graph->max_block_id() + 1, | |
| 4528 block->try_index()); | |
| 4529 TargetEntryInstr* false_target = | |
| 4530 new TargetEntryInstr(flow_graph->max_block_id() + 2, | |
| 4531 block->try_index()); | |
| 4532 flow_graph->set_max_block_id(flow_graph->max_block_id() + 2); | |
| 4533 *new_branch->true_successor_address() = true_target; | |
| 4534 *new_branch->false_successor_address() = false_target; | |
| 4535 GotoInstr* goto_true = new GotoInstr(join_true); | |
| 4536 true_target->LinkTo(goto_true); | |
| 4537 true_target->set_last_instruction(goto_true); | |
| 4538 GotoInstr* goto_false = new GotoInstr(join_false); | |
| 4539 false_target->LinkTo(goto_false); | |
| 4540 false_target->set_last_instruction(goto_false); | |
| 4541 } | |
| 4542 // When all predecessors have been rewritten, the original block is | |
| 4543 // unreachable from the graph. | |
| 4544 phi->UnuseAllInputs(); | |
|
Vyacheslav Egorov (Google)
2013/03/06 16:44:22
What about old branch? I think it also should do U
Kevin Millikin (Google)
2013/03/08 10:38:10
Sure, I can. I didn't because it's inputs are kno
| |
| 4545 } | |
| 4546 } | |
| 4547 | |
| 4548 if (changed) { | |
| 4549 // We may have changed the block order and the dominator tree. | |
| 4550 flow_graph->DiscoverBlocks(); | |
| 4551 GrowableArray<BitVector*> dominance_frontier; | |
| 4552 flow_graph->ComputeDominators(&dominance_frontier); | |
| 4553 } | |
| 4554 } | |
| 4555 | |
| 4556 | |
| 4377 } // namespace dart | 4557 } // namespace dart |
| OLD | NEW |