Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/hash_map.h" | 10 #include "vm/hash_map.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 void FlowGraphOptimizer::ApplyICData() { | 26 void FlowGraphOptimizer::ApplyICData() { |
| 27 VisitBlocks(); | 27 VisitBlocks(); |
| 28 } | 28 } |
| 29 | 29 |
| 30 | 30 |
| 31 void FlowGraphOptimizer::OptimizeComputations() { | 31 void FlowGraphOptimizer::OptimizeComputations() { |
| 32 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 32 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 33 BlockEntryInstr* entry = block_order_[i]; | 33 BlockEntryInstr* entry = block_order_[i]; |
| 34 entry->Accept(this); | 34 entry->Accept(this); |
| 35 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 35 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 36 Definition* defn = it.Current()->AsDefinition(); | 36 Instruction* current = it.Current(); |
| 37 if (defn != NULL) { | 37 Instruction* replacement = current->Canonicalize(); |
| 38 Definition* result = defn->Canonicalize(); | 38 if (replacement != current) { |
|
Florian Schneider
2012/09/19 13:24:49
Maybe assert that Canonicalize for Instructions re
Vyacheslav Egorov (Google)
2012/09/21 12:51:40
Done.
| |
| 39 if (result != defn) { | 39 if ((replacement != NULL) && current->IsDefinition()) { |
| 40 if (result != NULL) { | 40 Definition* current_defn = current->AsDefinition(); |
| 41 defn->ReplaceUsesWith(result); | 41 Definition* replacement_defn = replacement->AsDefinition(); |
| 42 if (FLAG_trace_optimization) { | 42 ASSERT(replacement_defn != NULL); |
| 43 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | 43 current_defn->ReplaceUsesWith(replacement_defn); |
| 44 defn->ssa_temp_index(), | 44 if (FLAG_trace_optimization) { |
| 45 result->ssa_temp_index()); | 45 OS::Print("Replacing v%"Pd" with v%"Pd"\n", |
| 46 } | 46 current_defn->ssa_temp_index(), |
| 47 } else if (FLAG_trace_optimization) { | 47 replacement_defn->ssa_temp_index()); |
| 48 OS::Print("Removing v%"Pd".\n", defn->ssa_temp_index()); | |
| 49 } | 48 } |
| 50 it.RemoveCurrentFromGraph(); | 49 } else if (FLAG_trace_optimization) { |
| 50 ASSERT(!current->IsDefinition() || | |
| 51 ((current->AsDefinition()->input_use_list() == NULL) && | |
| 52 (current->AsDefinition()->env_use_list() == NULL))); | |
| 53 if (current->IsDefinition()) { | |
| 54 OS::Print("Removing v%"Pd".\n", | |
| 55 current->AsDefinition()->ssa_temp_index()); | |
| 56 } else { | |
| 57 OS::Print("Removing %s\n", current->DebugName()); | |
| 58 } | |
| 51 } | 59 } |
| 60 it.RemoveCurrentFromGraph(); | |
| 52 } | 61 } |
| 53 } | 62 } |
| 54 } | 63 } |
| 55 } | 64 } |
| 56 | 65 |
| 57 | 66 |
| 58 static Definition* CreateConversion(Representation from, | 67 static Definition* CreateConversion(Representation from, |
| 59 Representation to, | 68 Representation to, |
| 60 Definition* def, | 69 Definition* def, |
| 61 Instruction* deopt_target) { | 70 Instruction* deopt_target) { |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 407 call->ReplaceWith(array_op, current_iterator()); | 416 call->ReplaceWith(array_op, current_iterator()); |
| 408 RemovePushArguments(call); | 417 RemovePushArguments(call); |
| 409 return true; | 418 return true; |
| 410 } | 419 } |
| 411 default: | 420 default: |
| 412 return false; | 421 return false; |
| 413 } | 422 } |
| 414 } | 423 } |
| 415 | 424 |
| 416 | 425 |
| 417 void FlowGraphOptimizer::InsertBefore(Instruction* instr, | 426 void FlowGraphOptimizer::InsertBefore(Instruction* next, |
| 418 Definition* defn, | 427 Instruction* instr, |
| 419 Environment* env, | 428 Environment* env, |
| 420 Definition::UseKind use_kind) { | 429 Definition::UseKind use_kind) { |
| 421 if (env != NULL) env->DeepCopyTo(defn); | 430 if (env != NULL) env->DeepCopyTo(instr); |
| 422 if (use_kind == Definition::kValue) { | 431 if (use_kind == Definition::kValue) { |
| 423 defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 432 ASSERT(instr->IsDefinition()); |
| 433 instr->AsDefinition()->set_ssa_temp_index( | |
| 434 flow_graph_->alloc_ssa_temp_index()); | |
| 424 } | 435 } |
| 425 defn->InsertBefore(instr); | 436 instr->InsertBefore(next); |
| 426 } | 437 } |
| 427 | 438 |
| 428 | 439 |
| 429 void FlowGraphOptimizer::InsertAfter(Instruction* instr, | 440 void FlowGraphOptimizer::InsertAfter(Instruction* prev, |
| 430 Definition* defn, | 441 Instruction* instr, |
| 431 Environment* env, | 442 Environment* env, |
| 432 Definition::UseKind use_kind) { | 443 Definition::UseKind use_kind) { |
| 433 if (env != NULL) env->DeepCopyTo(defn); | 444 if (env != NULL) env->DeepCopyTo(instr); |
| 434 if (use_kind == Definition::kValue) { | 445 if (use_kind == Definition::kValue) { |
| 435 defn->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | 446 ASSERT(instr->IsDefinition()); |
| 447 instr->AsDefinition()->set_ssa_temp_index( | |
| 448 flow_graph_->alloc_ssa_temp_index()); | |
| 436 } | 449 } |
| 437 defn->InsertAfter(instr); | 450 instr->InsertAfter(prev); |
| 438 } | 451 } |
| 439 | 452 |
| 440 | 453 |
| 441 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 454 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 442 Token::Kind op_kind) { | 455 Token::Kind op_kind) { |
| 443 intptr_t operands_type = kIllegalCid; | 456 intptr_t operands_type = kIllegalCid; |
| 444 ASSERT(call->HasICData()); | 457 ASSERT(call->HasICData()); |
| 445 const ICData& ic_data = *call->ic_data(); | 458 const ICData& ic_data = *call->ic_data(); |
| 446 switch (op_kind) { | 459 switch (op_kind) { |
| 447 case Token::kADD: | 460 case Token::kADD: |
| (...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1424 if (header->dominator() == candidate) { | 1437 if (header->dominator() == candidate) { |
| 1425 return candidate; | 1438 return candidate; |
| 1426 } | 1439 } |
| 1427 } | 1440 } |
| 1428 return NULL; | 1441 return NULL; |
| 1429 } | 1442 } |
| 1430 | 1443 |
| 1431 | 1444 |
| 1432 void LICM::Hoist(ForwardInstructionIterator* it, | 1445 void LICM::Hoist(ForwardInstructionIterator* it, |
| 1433 BlockEntryInstr* pre_header, | 1446 BlockEntryInstr* pre_header, |
| 1434 Definition* current) { | 1447 Instruction* current) { |
| 1435 // TODO(fschneider): Avoid repeated deoptimization when | 1448 // TODO(fschneider): Avoid repeated deoptimization when |
| 1436 // speculatively hoisting checks. | 1449 // speculatively hoisting checks. |
| 1437 if (FLAG_trace_optimization) { | 1450 if (FLAG_trace_optimization) { |
| 1438 OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n", | 1451 OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n", |
| 1439 current->DebugName(), | 1452 current->DebugName(), |
| 1440 current->deopt_id(), | 1453 current->deopt_id(), |
| 1441 current->GetBlock()->block_id(), | 1454 current->GetBlock()->block_id(), |
| 1442 pre_header->block_id()); | 1455 pre_header->block_id()); |
| 1443 } | 1456 } |
| 1444 // Move the instruction out of the loop. | 1457 // Move the instruction out of the loop. |
| 1445 it->RemoveCurrentFromGraph(); | 1458 it->RemoveCurrentFromGraph(); |
| 1446 GotoInstr* last = pre_header->last_instruction()->AsGoto(); | 1459 GotoInstr* last = pre_header->last_instruction()->AsGoto(); |
| 1447 current->InsertBefore(last); | 1460 current->InsertBefore(last); |
| 1448 // Attach the environment of the Goto instruction to the hoisted | 1461 // Attach the environment of the Goto instruction to the hoisted |
| 1449 // instruction and set the correct deopt_id. | 1462 // instruction and set the correct deopt_id. |
| 1450 ASSERT(last->env() != NULL); | 1463 ASSERT(last->env() != NULL); |
| 1451 last->env()->DeepCopyTo(current); | 1464 last->env()->DeepCopyTo(current); |
| 1452 current->deopt_id_ = last->GetDeoptId(); | 1465 current->deopt_id_ = last->GetDeoptId(); |
| 1453 } | 1466 } |
| 1454 | 1467 |
| 1455 | 1468 |
| 1456 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, | 1469 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, |
| 1457 BlockEntryInstr* header, | 1470 BlockEntryInstr* header, |
| 1458 BlockEntryInstr* pre_header, | 1471 BlockEntryInstr* pre_header, |
| 1459 Definition* current) { | 1472 Instruction* current) { |
| 1460 PhiInstr* phi = current->InputAt(0)->definition()->AsPhi(); | 1473 PhiInstr* phi = current->InputAt(0)->definition()->AsPhi(); |
| 1461 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { | 1474 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { |
| 1462 return; | 1475 return; |
| 1463 } | 1476 } |
| 1464 | 1477 |
| 1465 if (phi->GetPropagatedCid() == kSmiCid) { | 1478 if (phi->GetPropagatedCid() == kSmiCid) { |
| 1466 it->RemoveCurrentFromGraph(); | 1479 it->RemoveCurrentFromGraph(); |
| 1467 return; | 1480 return; |
| 1468 } | 1481 } |
| 1469 | 1482 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1506 BlockEntryInstr* pre_header = FindPreHeader(header); | 1519 BlockEntryInstr* pre_header = FindPreHeader(header); |
| 1507 if (pre_header == NULL) continue; | 1520 if (pre_header == NULL) continue; |
| 1508 | 1521 |
| 1509 for (BitVector::Iterator loop_it(header->loop_info()); | 1522 for (BitVector::Iterator loop_it(header->loop_info()); |
| 1510 !loop_it.Done(); | 1523 !loop_it.Done(); |
| 1511 loop_it.Advance()) { | 1524 loop_it.Advance()) { |
| 1512 BlockEntryInstr* block = flow_graph->preorder()[loop_it.Current()]; | 1525 BlockEntryInstr* block = flow_graph->preorder()[loop_it.Current()]; |
| 1513 for (ForwardInstructionIterator it(block); | 1526 for (ForwardInstructionIterator it(block); |
| 1514 !it.Done(); | 1527 !it.Done(); |
| 1515 it.Advance()) { | 1528 it.Advance()) { |
| 1516 Definition* current = it.Current()->AsDefinition(); | 1529 Instruction* current = it.Current(); |
| 1517 if (current != NULL && | 1530 if (!current->IsPushArgument() && !current->AffectedBySideEffect()) { |
| 1518 !current->IsPushArgument() && | |
| 1519 !current->AffectedBySideEffect()) { | |
| 1520 bool inputs_loop_invariant = true; | 1531 bool inputs_loop_invariant = true; |
| 1521 for (int i = 0; i < current->InputCount(); ++i) { | 1532 for (int i = 0; i < current->InputCount(); ++i) { |
| 1522 Definition* input_def = current->InputAt(i)->definition(); | 1533 Definition* input_def = current->InputAt(i)->definition(); |
| 1523 if (!input_def->GetBlock()->Dominates(pre_header)) { | 1534 if (!input_def->GetBlock()->Dominates(pre_header)) { |
| 1524 inputs_loop_invariant = false; | 1535 inputs_loop_invariant = false; |
| 1525 break; | 1536 break; |
| 1526 } | 1537 } |
| 1527 } | 1538 } |
| 1528 if (inputs_loop_invariant) { | 1539 if (inputs_loop_invariant) { |
| 1529 Hoist(&it, pre_header, current); | 1540 Hoist(&it, pre_header, current); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1729 | 1740 |
| 1730 GrowableArray<Definition*> definitions(max_expr_id); | 1741 GrowableArray<Definition*> definitions(max_expr_id); |
| 1731 for (intptr_t j = 0; j < max_expr_id ; j++) { | 1742 for (intptr_t j = 0; j < max_expr_id ; j++) { |
| 1732 definitions.Add(NULL); | 1743 definitions.Add(NULL); |
| 1733 } | 1744 } |
| 1734 | 1745 |
| 1735 OptimizeLoads(graph->graph_entry(), &definitions, avail_in); | 1746 OptimizeLoads(graph->graph_entry(), &definitions, avail_in); |
| 1736 } | 1747 } |
| 1737 } | 1748 } |
| 1738 | 1749 |
| 1739 DirectChainedHashMap<Definition*> map; | 1750 DirectChainedHashMap<Instruction*> map; |
| 1740 OptimizeRecursive(graph->graph_entry(), &map); | 1751 OptimizeRecursive(graph->graph_entry(), &map); |
| 1741 } | 1752 } |
| 1742 | 1753 |
| 1743 | 1754 |
| 1744 void DominatorBasedCSE::OptimizeRecursive( | 1755 void DominatorBasedCSE::OptimizeRecursive( |
| 1745 BlockEntryInstr* block, | 1756 BlockEntryInstr* block, |
| 1746 DirectChainedHashMap<Definition*>* map) { | 1757 DirectChainedHashMap<Instruction*>* map) { |
| 1747 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 1758 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 1748 Definition* defn = it.Current()->AsDefinition(); | 1759 Instruction* current = it.Current(); |
| 1749 if ((defn == NULL) || defn->AffectedBySideEffect()) continue; | 1760 if (current->AffectedBySideEffect()) continue; |
| 1750 Definition* result = map->Lookup(defn); | 1761 Instruction* replacement = map->Lookup(current); |
| 1751 if (result == NULL) { | 1762 if (replacement == NULL) { |
| 1752 map->Insert(defn); | 1763 map->Insert(current); |
| 1753 continue; | 1764 continue; |
| 1754 } | 1765 } |
| 1755 // Replace current with lookup result. | 1766 // Replace current with lookup result. |
| 1756 defn->ReplaceUsesWith(result); | 1767 if (current->IsDefinition()) { |
| 1768 ASSERT(replacement->IsDefinition()); | |
| 1769 current->AsDefinition()->ReplaceUsesWith(replacement->AsDefinition()); | |
| 1770 if (FLAG_trace_optimization) { | |
| 1771 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | |
| 1772 current->AsDefinition()->ssa_temp_index(), | |
| 1773 replacement->AsDefinition()->ssa_temp_index()); | |
| 1774 } | |
| 1775 } | |
|
Florian Schneider
2012/09/19 13:24:49
Maybe add the same debug output as in the Canonica
Vyacheslav Egorov (Google)
2012/09/21 12:51:40
Done.
| |
| 1757 it.RemoveCurrentFromGraph(); | 1776 it.RemoveCurrentFromGraph(); |
| 1758 if (FLAG_trace_optimization) { | |
| 1759 OS::Print("Replacing v%"Pd" with v%"Pd"\n", | |
| 1760 defn->ssa_temp_index(), | |
| 1761 result->ssa_temp_index()); | |
| 1762 } | |
| 1763 } | 1777 } |
| 1764 | 1778 |
| 1765 // Process children in the dominator tree recursively. | 1779 // Process children in the dominator tree recursively. |
| 1766 intptr_t num_children = block->dominated_blocks().length(); | 1780 intptr_t num_children = block->dominated_blocks().length(); |
| 1767 for (intptr_t i = 0; i < num_children; ++i) { | 1781 for (intptr_t i = 0; i < num_children; ++i) { |
| 1768 BlockEntryInstr* child = block->dominated_blocks()[i]; | 1782 BlockEntryInstr* child = block->dominated_blocks()[i]; |
| 1769 if (i < num_children - 1) { | 1783 if (i < num_children - 1) { |
| 1770 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. | 1784 DirectChainedHashMap<Instruction*> child_map(*map); // Copy map. |
| 1771 OptimizeRecursive(child, &child_map); | 1785 OptimizeRecursive(child, &child_map); |
| 1772 } else { | 1786 } else { |
| 1773 OptimizeRecursive(child, map); // Reuse map for the last child. | 1787 OptimizeRecursive(child, map); // Reuse map for the last child. |
| 1774 } | 1788 } |
| 1775 } | 1789 } |
| 1776 } | 1790 } |
| 1777 | 1791 |
| 1778 | 1792 |
| 1779 } // namespace dart | 1793 } // namespace dart |
| OLD | NEW |