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/intermediate_language.h" | 12 #include "vm/intermediate_language.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/parser.h" | 14 #include "vm/parser.h" |
| 15 #include "vm/scopes.h" | 15 #include "vm/scopes.h" |
| 16 #include "vm/symbols.h" | 16 #include "vm/symbols.h" |
| 17 | 17 |
| 18 namespace dart { | 18 namespace dart { |
| 19 | 19 |
| 20 DECLARE_FLAG(bool, eliminate_type_checks); | 20 DECLARE_FLAG(bool, eliminate_type_checks); |
| 21 DECLARE_FLAG(bool, enable_type_checks); | 21 DECLARE_FLAG(bool, enable_type_checks); |
| 22 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 22 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 23 DECLARE_FLAG(bool, trace_type_check_elimination); | 23 DECLARE_FLAG(bool, trace_type_check_elimination); |
| 24 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 24 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 25 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); | 25 DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination."); |
| 26 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | |
| 26 | 27 |
| 27 void FlowGraphOptimizer::ApplyICData() { | 28 void FlowGraphOptimizer::ApplyICData() { |
| 28 VisitBlocks(); | 29 VisitBlocks(); |
| 29 } | 30 } |
| 30 | 31 |
| 31 | 32 |
| 32 static void ReplaceCurrentInstruction(ForwardInstructionIterator* it, | 33 static void ReplaceCurrentInstruction(ForwardInstructionIterator* it, |
| 33 Instruction* current, | 34 Instruction* current, |
| 34 Instruction* replacement) { | 35 Instruction* replacement) { |
| 35 if ((replacement != NULL) && current->IsDefinition()) { | 36 if ((replacement != NULL) && current->IsDefinition()) { |
| (...skipping 1196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1232 | 1233 |
| 1233 // Replace uses of the definition def that are dominated by instruction dom | 1234 // Replace uses of the definition def that are dominated by instruction dom |
| 1234 // with uses of other definition. | 1235 // with uses of other definition. |
| 1235 void RenameDominatedUses(Definition* def, | 1236 void RenameDominatedUses(Definition* def, |
| 1236 Instruction* dom, | 1237 Instruction* dom, |
| 1237 Definition* other); | 1238 Definition* other); |
| 1238 | 1239 |
| 1239 // Propagate range information until fix-point is reached. | 1240 // Propagate range information until fix-point is reached. |
| 1240 void InferRanges(); | 1241 void InferRanges(); |
| 1241 | 1242 |
| 1243 void ProcessWorklist(Definition::RangeOperator op); | |
| 1244 | |
| 1242 // Walk the dominator tree, initialize ranges for smi values and place them | 1245 // Walk the dominator tree, initialize ranges for smi values and place them |
| 1243 // to the worklist. | 1246 // to the worklist. |
| 1244 void InitializeRangesRecursive(BlockEntryInstr* block); | 1247 void InitializeRangesRecursive(BlockEntryInstr* block); |
| 1245 | 1248 |
| 1246 // Remove artificial Constraint instructions and replace them with actual | 1249 // Remove artificial Constraint instructions and replace them with actual |
| 1247 // unconstrained definitions. | 1250 // unconstrained definitions. |
| 1248 void RemoveConstraints(); | 1251 void RemoveConstraints(); |
| 1249 | 1252 |
| 1250 void CreateWorklists(); | 1253 void CreateWorklists(); |
| 1251 | 1254 |
| 1252 void AddToWorklist(Definition* value) { | 1255 void AddToWorklist(Definition* value) { |
| 1253 const intptr_t index = value->ssa_temp_index(); | 1256 const intptr_t index = value->ssa_temp_index(); |
| 1254 if (!in_inactive_worklist_->Contains(index)) { | 1257 if (!in_worklist_->Contains(index)) { |
| 1255 in_inactive_worklist_->Add(index); | 1258 in_worklist_->Add(index); |
| 1256 inactive_worklist_->Add(value); | 1259 worklist_.Add(value); |
| 1257 } | 1260 } |
| 1258 } | 1261 } |
| 1259 | 1262 |
| 1260 bool IsWorklistEmpty() const { | 1263 bool IsWorklistEmpty() const { |
| 1261 return active_worklist_->is_empty(); | 1264 return worklist_.is_empty(); |
| 1265 } | |
| 1266 | |
| 1267 Definition* RemoveLastFromWorklist() { | |
| 1268 Definition* defn = worklist_.Last(); | |
| 1269 worklist_.RemoveLast(); | |
| 1270 ASSERT(in_worklist_->Contains(defn->ssa_temp_index())); | |
| 1271 in_worklist_->Remove(defn->ssa_temp_index()); | |
| 1272 return defn; | |
| 1262 } | 1273 } |
| 1263 | 1274 |
| 1264 void SwapWorklists(); | 1275 void SwapWorklists(); |
| 1265 | 1276 |
| 1266 FlowGraph* flow_graph_; | 1277 FlowGraph* flow_graph_; |
| 1267 | 1278 |
| 1268 GrowableArray<Definition*> smi_values_; // Value that are known to be smi. | 1279 GrowableArray<Definition*> smi_values_; // Value that are known to be smi. |
| 1269 GrowableArray<CheckSmiInstr*> smi_checks_; // All CheckSmi instructions. | 1280 GrowableArray<CheckSmiInstr*> smi_checks_; // All CheckSmi instructions. |
| 1270 | 1281 |
| 1271 // All Constraints inserted during InsertConstraints phase. They are treated | 1282 // All Constraints inserted during InsertConstraints phase. They are treated |
| 1272 // as smi values. | 1283 // as smi values. |
| 1273 GrowableArray<ConstraintInstr*> constraints_; | 1284 GrowableArray<ConstraintInstr*> constraints_; |
| 1274 | 1285 |
| 1275 // Bitvector for a quick filtering of known smi values. | 1286 // Bitvector for a quick filtering of known smi values. |
| 1276 BitVector* smi_definitions_; | 1287 BitVector* smi_definitions_; |
| 1277 | 1288 |
| 1278 // Worklists using during range propagation. | 1289 // Worklist used during range propagation. |
| 1279 ZoneGrowableArray<Definition*>* active_worklist_; | 1290 GrowableArray<Definition*> worklist_; |
| 1280 ZoneGrowableArray<Definition*>* inactive_worklist_; | 1291 BitVector* in_worklist_; |
| 1281 BitVector* in_inactive_worklist_; | |
| 1282 | 1292 |
| 1283 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); | 1293 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); |
| 1284 }; | 1294 }; |
| 1285 | 1295 |
| 1286 | 1296 |
| 1287 void RangeAnalysis::Analyze() { | 1297 void RangeAnalysis::Analyze() { |
| 1288 CollectSmiValues(); | 1298 CollectSmiValues(); |
| 1289 InsertConstraints(); | 1299 InsertConstraints(); |
| 1290 InferRanges(); | 1300 InferRanges(); |
| 1291 RemoveConstraints(); | 1301 RemoveConstraints(); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1527 | 1537 |
| 1528 for (intptr_t i = 0; i < smi_values_.length(); i++) { | 1538 for (intptr_t i = 0; i < smi_values_.length(); i++) { |
| 1529 InsertConstraintsFor(smi_values_[i]); | 1539 InsertConstraintsFor(smi_values_[i]); |
| 1530 } | 1540 } |
| 1531 } | 1541 } |
| 1532 | 1542 |
| 1533 | 1543 |
| 1534 void RangeAnalysis::InitializeRangesRecursive(BlockEntryInstr* block) { | 1544 void RangeAnalysis::InitializeRangesRecursive(BlockEntryInstr* block) { |
| 1535 JoinEntryInstr* join = block->AsJoinEntry(); | 1545 JoinEntryInstr* join = block->AsJoinEntry(); |
| 1536 if ((join != NULL) && (join->phis() != NULL)) { | 1546 if ((join != NULL) && (join->phis() != NULL)) { |
| 1537 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | 1547 for (intptr_t i = 0; i < join->phis()->length(); ++i) { |
|
Florian Schneider
2012/09/24 11:29:59
Use PhiIterator here?
| |
| 1538 PhiInstr* phi = (*join->phis())[i]; | 1548 PhiInstr* phi = (*join->phis())[i]; |
| 1539 if (phi == NULL) continue; | 1549 if (phi == NULL) continue; |
| 1540 if (smi_definitions_->Contains(phi->ssa_temp_index())) { | 1550 if (smi_definitions_->Contains(phi->ssa_temp_index())) { |
| 1541 phi->InferRange(); | 1551 phi->InferRange(Definition::kRangeInit); |
| 1542 AddToWorklist(phi); | 1552 AddToWorklist(phi); |
| 1543 } | 1553 } |
| 1544 } | 1554 } |
| 1545 } | 1555 } |
| 1546 | 1556 |
| 1547 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 1557 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 1548 Definition* defn = it.Current()->AsDefinition(); | 1558 Definition* defn = it.Current()->AsDefinition(); |
| 1549 if ((defn != NULL) && | 1559 if ((defn != NULL) && |
| 1550 (defn->ssa_temp_index() != -1) && | 1560 (defn->ssa_temp_index() != -1) && |
| 1551 smi_definitions_->Contains(defn->ssa_temp_index())) { | 1561 smi_definitions_->Contains(defn->ssa_temp_index())) { |
| 1552 defn->InferRange(); | 1562 defn->InferRange(Definition::kRangeInit); |
| 1553 AddToWorklist(defn); | 1563 AddToWorklist(defn); |
| 1554 } | 1564 } |
| 1555 } | 1565 } |
| 1556 | 1566 |
| 1557 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | 1567 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { |
| 1558 InitializeRangesRecursive(block->dominated_blocks()[i]); | 1568 InitializeRangesRecursive(block->dominated_blocks()[i]); |
| 1559 } | 1569 } |
| 1560 } | 1570 } |
| 1561 | 1571 |
| 1562 | 1572 |
| 1563 void RangeAnalysis::CreateWorklists() { | 1573 void RangeAnalysis::CreateWorklists() { |
| 1564 active_worklist_ = new ZoneGrowableArray<Definition*>(10); | 1574 in_worklist_ = new BitVector( |
| 1565 inactive_worklist_ = new ZoneGrowableArray<Definition*>(10); | |
| 1566 in_inactive_worklist_ = new BitVector( | |
| 1567 flow_graph_->current_ssa_temp_index()); | 1575 flow_graph_->current_ssa_temp_index()); |
|
Florian Schneider
2012/09/24 11:29:59
Does it fit into the previous line?
| |
| 1568 } | 1576 } |
| 1569 | 1577 |
| 1570 | 1578 |
| 1571 void RangeAnalysis::SwapWorklists() { | 1579 void RangeAnalysis::ProcessWorklist(Definition::RangeOperator op) { |
| 1572 ZoneGrowableArray<Definition*>* temp = active_worklist_; | 1580 // Iterate until fix point is reached. |
| 1573 active_worklist_ = inactive_worklist_; | 1581 while (!IsWorklistEmpty()) { |
| 1574 inactive_worklist_ = temp; | 1582 Definition* defn = RemoveLastFromWorklist(); |
| 1575 inactive_worklist_->Clear(); | 1583 if (FLAG_trace_range_analysis) { |
| 1576 in_inactive_worklist_->Clear(); | 1584 OS::Print("infering range for v%"Pd" %s\n", |
| 1585 defn->ssa_temp_index(), | |
| 1586 Range::ToCString(defn->range())); | |
| 1587 } | |
| 1588 if (defn->InferRange(op)) { // Update the range. | |
| 1589 if (FLAG_trace_range_analysis) { | |
| 1590 OS::Print(" changed to %s\n", Range::ToCString(defn->range())); | |
| 1591 } | |
| 1592 // Range change. Place all uses to the worklist. | |
| 1593 for (Value* use = defn->input_use_list(); | |
| 1594 use != NULL; | |
| 1595 use = use->next_use()) { | |
| 1596 Definition* use_defn = use->instruction()->AsDefinition(); | |
| 1597 if ((use_defn != NULL) && | |
| 1598 (use_defn->ssa_temp_index() != -1) && | |
| 1599 smi_definitions_->Contains(use_defn->ssa_temp_index())) { | |
| 1600 AddToWorklist(use_defn); | |
| 1601 } | |
| 1602 } | |
| 1603 } | |
| 1604 } | |
| 1577 } | 1605 } |
| 1578 | 1606 |
| 1579 | 1607 |
| 1580 void RangeAnalysis::InferRanges() { | 1608 void RangeAnalysis::InferRanges() { |
| 1581 CreateWorklists(); | 1609 CreateWorklists(); |
| 1582 | 1610 |
| 1583 // Initialize bitvector for quick filtering of smi values. | 1611 // Initialize bitvector for quick filtering of smi values. |
| 1584 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); | 1612 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); |
| 1585 for (intptr_t i = 0; i < smi_values_.length(); i++) { | 1613 for (intptr_t i = 0; i < smi_values_.length(); i++) { |
| 1586 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); | 1614 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); |
| 1587 } | 1615 } |
| 1588 for (intptr_t i = 0; i < constraints_.length(); i++) { | 1616 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 1589 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); | 1617 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); |
| 1590 } | 1618 } |
| 1591 | 1619 |
| 1592 // Infer initial values of ranges. | 1620 // Infer initial values of ranges. |
| 1593 InitializeRangesRecursive(flow_graph_->graph_entry()); | 1621 InitializeRangesRecursive(flow_graph_->graph_entry()); |
| 1594 | 1622 |
| 1595 // Active worklist is empty, inactive now contains all smi values. | 1623 for (intptr_t i = 0; i < smi_values_.length(); i++) { |
| 1596 SwapWorklists(); | 1624 if (smi_values_[i]->IsPhi() && |
| 1597 | 1625 smi_values_[i]->InferRange(Definition::kRangeInit)) { |
| 1598 // Iterate until fix point is reached. | 1626 Definition* defn = smi_values_[i]; |
| 1599 while (!IsWorklistEmpty()) { | 1627 for (Value* use = defn->input_use_list(); |
| 1600 for (intptr_t i = 0; i < active_worklist_->length(); i++) { | 1628 use != NULL; |
| 1601 Definition* defn = (*active_worklist_)[i]; | 1629 use = use->next_use()) { |
| 1602 if (defn->InferRange()) { // Update the range. | 1630 Definition* use_defn = use->instruction()->AsDefinition(); |
| 1603 // Range change. Place all uses to the worklist. | 1631 if ((use_defn != NULL) && |
| 1604 for (Value* use = defn->input_use_list(); | 1632 (use_defn->ssa_temp_index() != -1) && |
| 1605 use != NULL; | 1633 smi_definitions_->Contains(use_defn->ssa_temp_index())) { |
| 1606 use = use->next_use()) { | 1634 AddToWorklist(use_defn); |
| 1607 Definition* use_defn = use->instruction()->AsDefinition(); | |
| 1608 if ((use_defn != NULL) && | |
| 1609 (use_defn->ssa_temp_index() != -1) && | |
| 1610 smi_definitions_->Contains(use_defn->ssa_temp_index())) { | |
| 1611 AddToWorklist(use_defn); | |
| 1612 } | |
| 1613 } | 1635 } |
| 1614 } | 1636 } |
| 1615 } | 1637 } |
| 1638 } | |
| 1616 | 1639 |
| 1617 // Active worklist has been processed. Inactive contains all values which | 1640 if (FLAG_trace_range_analysis) { |
| 1618 // can be affected by changed ranges. | 1641 OS::Print("---- after initialization -------\n"); |
| 1619 SwapWorklists(); | 1642 FlowGraphPrinter printer(*flow_graph_); |
| 1643 printer.PrintBlocks(); | |
| 1644 } | |
| 1645 | |
| 1646 if (FLAG_trace_range_analysis) { | |
| 1647 OS::Print("---- widening ---------\n"); | |
| 1648 } | |
| 1649 ProcessWorklist(Definition::kRangeWiden); | |
| 1650 | |
| 1651 if (FLAG_trace_range_analysis) { | |
| 1652 OS::Print("---- after widening -------\n"); | |
| 1653 FlowGraphPrinter printer(*flow_graph_); | |
| 1654 printer.PrintBlocks(); | |
| 1655 } | |
| 1656 | |
| 1657 for (intptr_t i = 0; i < smi_values_.length(); i++) { | |
|
Florian Schneider
2012/09/24 11:29:59
I assume that you only add phis here because only
| |
| 1658 if (smi_values_[i]->IsPhi()) AddToWorklist(smi_values_[i]); | |
| 1659 } | |
| 1660 | |
| 1661 if (FLAG_trace_range_analysis) { | |
| 1662 OS::Print("---- narrowing ---------\n"); | |
| 1663 } | |
| 1664 ProcessWorklist(Definition::kRangeNarrow); | |
| 1665 | |
| 1666 if (FLAG_trace_range_analysis) { | |
| 1667 OS::Print("---- after narrowing -------\n"); | |
| 1668 FlowGraphPrinter printer(*flow_graph_); | |
| 1669 printer.PrintBlocks(); | |
| 1620 } | 1670 } |
| 1621 } | 1671 } |
| 1622 | 1672 |
| 1623 | 1673 |
| 1624 void RangeAnalysis::RemoveConstraints() { | 1674 void RangeAnalysis::RemoveConstraints() { |
| 1625 for (intptr_t i = 0; i < constraints_.length(); i++) { | 1675 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 1626 Definition* def = constraints_[i]->value()->definition(); | 1676 Definition* def = constraints_[i]->value()->definition(); |
| 1627 // Some constraints might be constraining constraints. Unwind the chain of | 1677 // Some constraints might be constraining constraints. Unwind the chain of |
| 1628 // constraints until we reach the actual definition. | 1678 // constraints until we reach the actual definition. |
| 1629 while (def->IsConstraint()) { | 1679 while (def->IsConstraint()) { |
| (...skipping 1309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2939 it.Advance()) { | 2989 it.Advance()) { |
| 2940 JoinEntryInstr* join = it.Current()->AsJoinEntry(); | 2990 JoinEntryInstr* join = it.Current()->AsJoinEntry(); |
| 2941 if (join != NULL) join->EliminateUnreachablePhiInputs(); | 2991 if (join != NULL) join->EliminateUnreachablePhiInputs(); |
| 2942 } | 2992 } |
| 2943 | 2993 |
| 2944 graph_->ComputeUseLists(); | 2994 graph_->ComputeUseLists(); |
| 2945 } | 2995 } |
| 2946 | 2996 |
| 2947 | 2997 |
| 2948 } // namespace dart | 2998 } // namespace dart |
| OLD | NEW |