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" |
| 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 Propagate(FlowGraph* graph, | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
Propagate is a generic name. How about "AnalyzeLo
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1581 const GrowableArray<BitVector*>& avail_in, | |
| 1582 const GrowableArray<BitVector*>& avail_out, | |
| 1583 const GrowableArray<BitVector*>& avail_gen, | |
| 1584 const GrowableArray<BitVector*>& avail_kill) { | |
| 1585 for (BlockIterator block_it = graph->reverse_postorder_iterator(); | |
| 1586 !block_it.Done(); | |
| 1587 block_it.Advance()) { | |
| 1588 BlockEntryInstr* block = block_it.Current(); | |
| 1589 for (ForwardInstructionIterator instr_it(block); | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
If you iterate backward, you can break from the lo
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1590 !instr_it.Done(); | |
| 1591 instr_it.Advance()) { | |
| 1592 Instruction* instr = instr_it.Current(); | |
| 1593 if (instr->HasSideEffect()) { | |
| 1594 avail_gen[block->preorder_number()]->Clear(); | |
| 1595 avail_out[block->preorder_number()]->Clear(); | |
| 1596 avail_kill[block->preorder_number()]->SetAll(); | |
| 1597 continue; | |
| 1598 } | |
| 1599 Definition* defn = instr_it.Current()->AsDefinition(); | |
| 1600 if ((defn == NULL) || | |
| 1601 !defn->IsLoadField() || | |
| 1602 !defn->AffectedBySideEffect()) { | |
| 1603 // TODO(fschneider): Extend to other load instructions. | |
| 1604 continue; | |
| 1605 } | |
| 1606 avail_gen[block->preorder_number()]->Add(defn->expr_id()); | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
It might be more straightforward to compute kill a
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1607 avail_out[block->preorder_number()]->Add(defn->expr_id()); | |
| 1608 } | |
| 1609 } | |
| 1610 | |
| 1611 BitVector* temp = new BitVector(avail_in[0]->length()); | |
| 1612 | |
| 1613 bool changed = true; | |
| 1614 while (changed) { | |
| 1615 changed = false; | |
| 1616 | |
| 1617 for (BlockIterator block_it = graph->reverse_postorder_iterator(); | |
| 1618 !block_it.Done(); | |
| 1619 block_it.Advance()) { | |
| 1620 BlockEntryInstr* block = block_it.Current(); | |
| 1621 BitVector* block_in = avail_in[block->preorder_number()]; | |
| 1622 BitVector* block_out = avail_out[block->preorder_number()]; | |
| 1623 BitVector* block_kill = avail_kill[block->preorder_number()]; | |
| 1624 BitVector* block_gen = avail_gen[block->preorder_number()]; | |
| 1625 | |
| 1626 if (FLAG_trace_optimization) { | |
| 1627 OS::Print("B%"Pd"", block->block_id()); | |
| 1628 block_in->Print(); | |
| 1629 block_out->Print(); | |
| 1630 OS::Print("\n"); | |
| 1631 } | |
| 1632 | |
| 1633 // Compute block_in as the intersection of all out(p) where p | |
| 1634 // is a predecessor of the current block. | |
| 1635 temp->Clear(); | |
| 1636 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | |
| 1637 if (i == 0) temp->SetAll(); | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
I prefer:
if (block->IsGraphEntry()) {
temp->Cl
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1638 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 1639 BitVector* pred_out = avail_out[pred->preorder_number()]; | |
| 1640 temp->Intersect(*pred_out); | |
| 1641 } | |
| 1642 if (!temp->Equals(*block_in)) { | |
| 1643 block_in->Clear(); | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
Seems like we might as well combine Clear and AddA
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1644 block_in->AddAll(temp); | |
| 1645 if (block_out->KillAndAdd(block_kill, block_gen)) changed = true; | |
| 1646 } | |
| 1647 } | |
| 1648 } | |
| 1649 } | |
| 1650 | |
| 1651 | |
| 1652 static void OptimizeLoads( | |
| 1653 BlockEntryInstr* block, | |
| 1654 GrowableArray<Definition*>* definitions, | |
| 1655 const GrowableArray<BitVector*>& avail_in) { | |
| 1656 // TODO(fschneider): Factor out code shared with the existing CSE pass. | |
| 1657 | |
| 1658 // Delete loads that are killed (not available) at the entry. | |
| 1659 intptr_t pre_num = block->preorder_number(); | |
| 1660 ASSERT(avail_in[pre_num]->length() == definitions->length()); | |
| 1661 for (intptr_t i = 0; i < avail_in[pre_num]->length(); i++) { | |
| 1662 if (!avail_in[pre_num]->Contains(i)) { | |
| 1663 (*definitions)[i] = NULL; | |
| 1664 } | |
| 1665 } | |
| 1666 | |
| 1667 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 1668 Instruction* instr = it.Current(); | |
| 1669 if (instr->HasSideEffect()) { | |
| 1670 // Handle local side effects by clearing current definitions. | |
| 1671 for (intptr_t i = 0; i < definitions->length(); i++) { | |
| 1672 (*definitions)[i] = NULL; | |
| 1673 } | |
| 1674 continue; | |
| 1675 } | |
| 1676 Definition* defn = instr->AsDefinition(); | |
| 1677 if ((defn == NULL) || | |
| 1678 !defn->IsLoadField() || | |
| 1679 !defn->AffectedBySideEffect()) { | |
| 1680 // Immutable loads are handled in normal CSE. | |
| 1681 // TODO(fschneider): Extend to other load instructions. | |
| 1682 continue; | |
| 1683 } | |
| 1684 Definition* result = (*definitions)[defn->expr_id()]; | |
| 1685 if (result == NULL) { | |
| 1686 (*definitions)[defn->expr_id()] = defn; | |
| 1687 continue; | |
| 1688 } | |
| 1689 | |
| 1690 // Replace current with lookup result. | |
| 1691 defn->ReplaceUsesWith(result); | |
| 1692 it.RemoveCurrentFromGraph(); | |
| 1693 if (FLAG_trace_optimization) { | |
| 1694 OS::Print("Replacing load v%"Pd" with v%"Pd"\n", | |
| 1695 defn->ssa_temp_index(), | |
| 1696 result->ssa_temp_index()); | |
| 1697 } | |
| 1698 } | |
| 1699 | |
| 1700 // Process children in the dominator tree recursively. | |
| 1701 intptr_t num_children = block->dominated_blocks().length(); | |
| 1702 for (intptr_t i = 0; i < num_children; ++i) { | |
| 1703 BlockEntryInstr* child = block->dominated_blocks()[i]; | |
| 1704 if (i < num_children - 1) { | |
| 1705 GrowableArray<Definition*> child_defs(definitions->length()); | |
| 1706 child_defs.AddArray(*definitions); | |
| 1707 OptimizeLoads(child, &child_defs, avail_in); | |
| 1708 } else { | |
| 1709 OptimizeLoads(child, definitions, avail_in); | |
| 1710 } | |
| 1711 } | |
| 1712 } | |
| 1713 | |
| 1714 | |
| 1715 void DominatorBasedCSE::Optimize(FlowGraph* graph) { | |
| 1716 intptr_t max_expr_id = NumberLoadExpressions(graph); | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
Can we move NumberLoadExpressions(graph) inside an
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1717 if (max_expr_id > 0 && FLAG_load_cse) { | |
| 1718 intptr_t num_blocks = graph->preorder().length(); | |
| 1719 GrowableArray<BitVector*> avail_out(num_blocks); | |
|
Kevin Millikin (Google)
2012/09/17 12:09:47
I'd move avail_gen, and _kill into Propagate so it
Florian Schneider
2012/09/17 14:20:59
Done.
| |
| 1720 GrowableArray<BitVector*> avail_in(num_blocks); | |
| 1721 GrowableArray<BitVector*> avail_gen(num_blocks); | |
| 1722 GrowableArray<BitVector*> avail_kill(num_blocks); | |
| 1723 for (intptr_t i = 0; i < num_blocks; i++) { | |
| 1724 avail_out.Add(new BitVector(max_expr_id)); | |
| 1725 avail_in.Add(new BitVector(max_expr_id)); | |
| 1726 avail_gen.Add(new BitVector(max_expr_id)); | |
| 1727 avail_kill.Add(new BitVector(max_expr_id)); | |
| 1728 } | |
| 1729 | |
| 1730 Propagate(graph, avail_in, avail_out, avail_gen, avail_kill); | |
| 1731 | |
| 1732 GrowableArray<Definition*> definitions(max_expr_id); | |
| 1733 for (intptr_t j = 0; j < max_expr_id ; j++) { | |
| 1734 definitions.Add(NULL); | |
| 1735 } | |
| 1736 | |
| 1737 OptimizeLoads(graph->graph_entry(), &definitions, avail_in); | |
| 1738 } | |
| 1739 | |
| 1740 DirectChainedHashMap<Definition*> map; | |
| 1741 OptimizeRecursive(graph->graph_entry(), &map); | |
| 1553 } | 1742 } |
| 1554 | 1743 |
| 1555 | 1744 |
| 1556 void DominatorBasedCSE::OptimizeRecursive( | 1745 void DominatorBasedCSE::OptimizeRecursive( |
| 1557 BlockEntryInstr* block, | 1746 BlockEntryInstr* block, |
| 1558 DirectChainedHashMap<Definition*>* map) { | 1747 DirectChainedHashMap<Definition*>* map) { |
| 1559 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 1748 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 1560 Definition* defn = it.Current()->AsDefinition(); | 1749 Definition* defn = it.Current()->AsDefinition(); |
| 1561 if ((defn == NULL) || defn->AffectedBySideEffect()) continue; | 1750 if ((defn == NULL) || defn->AffectedBySideEffect()) continue; |
| 1562 Definition* result = map->Lookup(defn); | 1751 Definition* result = map->Lookup(defn); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1582 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. | 1771 DirectChainedHashMap<Definition*> child_map(*map); // Copy map. |
| 1583 OptimizeRecursive(child, &child_map); | 1772 OptimizeRecursive(child, &child_map); |
| 1584 } else { | 1773 } else { |
| 1585 OptimizeRecursive(child, map); // Reuse map for the last child. | 1774 OptimizeRecursive(child, map); // Reuse map for the last child. |
| 1586 } | 1775 } |
| 1587 } | 1776 } |
| 1588 } | 1777 } |
| 1589 | 1778 |
| 1590 | 1779 |
| 1591 } // namespace dart | 1780 } // namespace dart |
| OLD | NEW |