| 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" |
| 11 #include "vm/il_printer.h" | 11 #include "vm/il_printer.h" |
| 12 #include "vm/object_store.h" | 12 #include "vm/object_store.h" |
| 13 #include "vm/parser.h" | 13 #include "vm/parser.h" |
| 14 #include "vm/scopes.h" | 14 #include "vm/scopes.h" |
| 15 #include "vm/symbols.h" | 15 #include "vm/symbols.h" |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 DECLARE_FLAG(bool, eliminate_type_checks); | 19 DECLARE_FLAG(bool, eliminate_type_checks); |
| 20 DECLARE_FLAG(bool, enable_type_checks); | 20 DECLARE_FLAG(bool, enable_type_checks); |
| 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 | 25 |
| 25 void FlowGraphOptimizer::ApplyICData() { | 26 void FlowGraphOptimizer::ApplyICData() { |
| 26 VisitBlocks(); | 27 VisitBlocks(); |
| 27 } | 28 } |
| 28 | 29 |
| 29 | 30 |
| 30 void FlowGraphOptimizer::OptimizeComputations() { | 31 void FlowGraphOptimizer::OptimizeComputations() { |
| 31 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 32 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 32 BlockEntryInstr* entry = block_order_[i]; | 33 BlockEntryInstr* entry = block_order_[i]; |
| 33 entry->Accept(this); | 34 entry->Accept(this); |
| (...skipping 1505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1539 current->InputAt(0)->definition()->IsPhi()) { | 1540 current->InputAt(0)->definition()->IsPhi()) { |
| 1540 TryHoistCheckSmiThroughPhi(&it, header, pre_header, current); | 1541 TryHoistCheckSmiThroughPhi(&it, header, pre_header, current); |
| 1541 } | 1542 } |
| 1542 } | 1543 } |
| 1543 } | 1544 } |
| 1544 } | 1545 } |
| 1545 } | 1546 } |
| 1546 } | 1547 } |
| 1547 | 1548 |
| 1548 | 1549 |
| 1549 void DominatorBasedCSE::Optimize(BlockEntryInstr* graph_entry) { | 1550 static intptr_t NumberLoadExpressions(FlowGraph* graph) { |
| 1550 ASSERT(graph_entry->IsGraphEntry()); | |
| 1551 DirectChainedHashMap<Definition*> map; | 1551 DirectChainedHashMap<Definition*> map; |
| 1552 OptimizeRecursive(graph_entry, &map); | 1552 intptr_t expr_id = 0; |
| 1553 for (BlockIterator it = graph->reverse_postorder_iterator(); |
| 1554 !it.Done(); |
| 1555 it.Advance()) { |
| 1556 BlockEntryInstr* block = it.Current(); |
| 1557 for (ForwardInstructionIterator instr_it(block); |
| 1558 !instr_it.Done(); |
| 1559 instr_it.Advance()) { |
| 1560 Definition* defn = instr_it.Current()->AsDefinition(); |
| 1561 if ((defn == NULL) || |
| 1562 !defn->IsLoadField() || |
| 1563 !defn->AffectedBySideEffect()) { |
| 1564 // TODO(fschneider): Extend to other load instructions. |
| 1565 continue; |
| 1566 } |
| 1567 Definition* result = map.Lookup(defn); |
| 1568 if (result == NULL) { |
| 1569 map.Insert(defn); |
| 1570 defn->set_expr_id(expr_id++); |
| 1571 } else { |
| 1572 defn->set_expr_id(result->expr_id()); |
| 1573 } |
| 1574 } |
| 1575 } |
| 1576 return expr_id; |
| 1577 } |
| 1578 |
| 1579 |
| 1580 static void ComputeAvailableLoads( |
| 1581 FlowGraph* graph, |
| 1582 intptr_t max_expr_id, |
| 1583 const GrowableArray<BitVector*>& avail_in) { |
| 1584 // Initialize gen-, kill-, out-sets. |
| 1585 intptr_t num_blocks = graph->preorder().length(); |
| 1586 GrowableArray<BitVector*> avail_out(num_blocks); |
| 1587 GrowableArray<BitVector*> avail_gen(num_blocks); |
| 1588 GrowableArray<BitVector*> avail_kill(num_blocks); |
| 1589 for (intptr_t i = 0; i < num_blocks; i++) { |
| 1590 avail_out.Add(new BitVector(max_expr_id)); |
| 1591 avail_gen.Add(new BitVector(max_expr_id)); |
| 1592 avail_kill.Add(new BitVector(max_expr_id)); |
| 1593 } |
| 1594 |
| 1595 for (BlockIterator block_it = graph->reverse_postorder_iterator(); |
| 1596 !block_it.Done(); |
| 1597 block_it.Advance()) { |
| 1598 BlockEntryInstr* block = block_it.Current(); |
| 1599 intptr_t preorder_number = block->preorder_number(); |
| 1600 for (BackwardInstructionIterator instr_it(block); |
| 1601 !instr_it.Done(); |
| 1602 instr_it.Advance()) { |
| 1603 Instruction* instr = instr_it.Current(); |
| 1604 if (instr->HasSideEffect()) { |
| 1605 avail_kill[preorder_number]->SetAll(); |
| 1606 break; |
| 1607 } |
| 1608 Definition* defn = instr_it.Current()->AsDefinition(); |
| 1609 if ((defn == NULL) || |
| 1610 !defn->IsLoadField() || |
| 1611 !defn->AffectedBySideEffect()) { |
| 1612 // TODO(fschneider): Extend to other load instructions. |
| 1613 continue; |
| 1614 } |
| 1615 avail_gen[preorder_number]->Add(defn->expr_id()); |
| 1616 } |
| 1617 avail_out[preorder_number]->CopyFrom(avail_gen[preorder_number]); |
| 1618 } |
| 1619 |
| 1620 BitVector* temp = new BitVector(avail_in[0]->length()); |
| 1621 |
| 1622 bool changed = true; |
| 1623 while (changed) { |
| 1624 changed = false; |
| 1625 |
| 1626 for (BlockIterator block_it = graph->reverse_postorder_iterator(); |
| 1627 !block_it.Done(); |
| 1628 block_it.Advance()) { |
| 1629 BlockEntryInstr* block = block_it.Current(); |
| 1630 BitVector* block_in = avail_in[block->preorder_number()]; |
| 1631 BitVector* block_out = avail_out[block->preorder_number()]; |
| 1632 BitVector* block_kill = avail_kill[block->preorder_number()]; |
| 1633 BitVector* block_gen = avail_gen[block->preorder_number()]; |
| 1634 |
| 1635 if (FLAG_trace_optimization) { |
| 1636 OS::Print("B%"Pd"", block->block_id()); |
| 1637 block_in->Print(); |
| 1638 block_out->Print(); |
| 1639 OS::Print("\n"); |
| 1640 } |
| 1641 |
| 1642 // Compute block_in as the intersection of all out(p) where p |
| 1643 // is a predecessor of the current block. |
| 1644 if (block->IsGraphEntry()) { |
| 1645 temp->Clear(); |
| 1646 } else { |
| 1647 temp->SetAll(); |
| 1648 ASSERT(block->PredecessorCount() > 0); |
| 1649 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 1650 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 1651 BitVector* pred_out = avail_out[pred->preorder_number()]; |
| 1652 temp->Intersect(*pred_out); |
| 1653 } |
| 1654 } |
| 1655 if (!temp->Equals(*block_in)) { |
| 1656 block_in->CopyFrom(temp); |
| 1657 if (block_out->KillAndAdd(block_kill, block_gen)) changed = true; |
| 1658 } |
| 1659 } |
| 1660 } |
| 1661 } |
| 1662 |
| 1663 |
| 1664 static void OptimizeLoads( |
| 1665 BlockEntryInstr* block, |
| 1666 GrowableArray<Definition*>* definitions, |
| 1667 const GrowableArray<BitVector*>& avail_in) { |
| 1668 // TODO(fschneider): Factor out code shared with the existing CSE pass. |
| 1669 |
| 1670 // Delete loads that are killed (not available) at the entry. |
| 1671 intptr_t pre_num = block->preorder_number(); |
| 1672 ASSERT(avail_in[pre_num]->length() == definitions->length()); |
| 1673 for (intptr_t i = 0; i < avail_in[pre_num]->length(); i++) { |
| 1674 if (!avail_in[pre_num]->Contains(i)) { |
| 1675 (*definitions)[i] = NULL; |
| 1676 } |
| 1677 } |
| 1678 |
| 1679 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 1680 Instruction* instr = it.Current(); |
| 1681 if (instr->HasSideEffect()) { |
| 1682 // Handle local side effects by clearing current definitions. |
| 1683 for (intptr_t i = 0; i < definitions->length(); i++) { |
| 1684 (*definitions)[i] = NULL; |
| 1685 } |
| 1686 continue; |
| 1687 } |
| 1688 Definition* defn = instr->AsDefinition(); |
| 1689 if ((defn == NULL) || |
| 1690 !defn->IsLoadField() || |
| 1691 !defn->AffectedBySideEffect()) { |
| 1692 // Immutable loads are handled in normal CSE. |
| 1693 // TODO(fschneider): Extend to other load instructions. |
| 1694 continue; |
| 1695 } |
| 1696 Definition* result = (*definitions)[defn->expr_id()]; |
| 1697 if (result == NULL) { |
| 1698 (*definitions)[defn->expr_id()] = defn; |
| 1699 continue; |
| 1700 } |
| 1701 |
| 1702 // Replace current with lookup result. |
| 1703 defn->ReplaceUsesWith(result); |
| 1704 it.RemoveCurrentFromGraph(); |
| 1705 if (FLAG_trace_optimization) { |
| 1706 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", |
| 1707 defn->ssa_temp_index(), |
| 1708 result->ssa_temp_index()); |
| 1709 } |
| 1710 } |
| 1711 |
| 1712 // Process children in the dominator tree recursively. |
| 1713 intptr_t num_children = block->dominated_blocks().length(); |
| 1714 for (intptr_t i = 0; i < num_children; ++i) { |
| 1715 BlockEntryInstr* child = block->dominated_blocks()[i]; |
| 1716 if (i < num_children - 1) { |
| 1717 GrowableArray<Definition*> child_defs(definitions->length()); |
| 1718 child_defs.AddArray(*definitions); |
| 1719 OptimizeLoads(child, &child_defs, avail_in); |
| 1720 } else { |
| 1721 OptimizeLoads(child, definitions, avail_in); |
| 1722 } |
| 1723 } |
| 1724 } |
| 1725 |
| 1726 |
| 1727 void DominatorBasedCSE::Optimize(FlowGraph* graph) { |
| 1728 if (FLAG_load_cse) { |
| 1729 intptr_t max_expr_id = NumberLoadExpressions(graph); |
| 1730 if (max_expr_id > 0) { |
| 1731 intptr_t num_blocks = graph->preorder().length(); |
| 1732 GrowableArray<BitVector*> avail_in(num_blocks); |
| 1733 for (intptr_t i = 0; i < num_blocks; i++) { |
| 1734 avail_in.Add(new BitVector(max_expr_id)); |
| 1735 } |
| 1736 |
| 1737 ComputeAvailableLoads(graph, max_expr_id, avail_in); |
| 1738 |
| 1739 GrowableArray<Definition*> definitions(max_expr_id); |
| 1740 for (intptr_t j = 0; j < max_expr_id ; j++) { |
| 1741 definitions.Add(NULL); |
| 1742 } |
| 1743 |
| 1744 OptimizeLoads(graph->graph_entry(), &definitions, avail_in); |
| 1745 } |
| 1746 } |
| 1747 |
| 1748 DirectChainedHashMap<Definition*> map; |
| 1749 OptimizeRecursive(graph->graph_entry(), &map); |
| 1553 } | 1750 } |
| 1554 | 1751 |
| 1555 | 1752 |
| 1556 void DominatorBasedCSE::OptimizeRecursive( | 1753 void DominatorBasedCSE::OptimizeRecursive( |
| 1557 BlockEntryInstr* block, | 1754 BlockEntryInstr* block, |
| 1558 DirectChainedHashMap<Definition*>* map) { | 1755 DirectChainedHashMap<Definition*>* map) { |
| 1559 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 1756 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 1560 Definition* defn = it.Current()->AsDefinition(); | 1757 Definition* defn = it.Current()->AsDefinition(); |
| 1561 if ((defn == NULL) || defn->AffectedBySideEffect()) continue; | 1758 if ((defn == NULL) || defn->AffectedBySideEffect()) continue; |
| 1562 Definition* result = map->Lookup(defn); | 1759 Definition* result = map->Lookup(defn); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1582 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. | 1779 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. |
| 1583 OptimizeRecursive(child, &child_map); | 1780 OptimizeRecursive(child, &child_map); |
| 1584 } else { | 1781 } else { |
| 1585 OptimizeRecursive(child, map); // Reuse map for the last child. | 1782 OptimizeRecursive(child, map); // Reuse map for the last child. |
| 1586 } | 1783 } |
| 1587 } | 1784 } |
| 1588 } | 1785 } |
| 1589 | 1786 |
| 1590 | 1787 |
| 1591 } // namespace dart | 1788 } // namespace dart |
| OLD | NEW |