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