Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 11283002: Simplify range analysis algorithm. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address comments Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/flow_graph_compiler.h" 10 #include "vm/flow_graph_compiler.h"
(...skipping 1584 matching lines...) Expand 10 before | Expand all | Expand 10 after
1595 1595
1596 void FlowGraphOptimizer::PropagateSminess() { 1596 void FlowGraphOptimizer::PropagateSminess() {
1597 SminessPropagator propagator(flow_graph_); 1597 SminessPropagator propagator(flow_graph_);
1598 propagator.Propagate(); 1598 propagator.Propagate();
1599 } 1599 }
1600 1600
1601 1601
1602 // Range analysis for smi values. 1602 // Range analysis for smi values.
1603 class RangeAnalysis : public ValueObject { 1603 class RangeAnalysis : public ValueObject {
1604 public: 1604 public:
1605 explicit RangeAnalysis(FlowGraph* flow_graph) : flow_graph_(flow_graph) { } 1605 explicit RangeAnalysis(FlowGraph* flow_graph)
1606 : flow_graph_(flow_graph),
1607 marked_defns_(NULL) { }
1606 1608
1607 // Infer ranges for all values and remove overflow checks from binary smi 1609 // Infer ranges for all values and remove overflow checks from binary smi
1608 // operations when proven redundant. 1610 // operations when proven redundant.
1609 void Analyze(); 1611 void Analyze();
1610 1612
1611 private: 1613 private:
1612 // Collect all values that were proven to be smi in smi_values_ array and all 1614 // Collect all values that were proven to be smi in smi_values_ array and all
1613 // CheckSmi instructions in smi_check_ array. 1615 // CheckSmi instructions in smi_check_ array.
1614 void CollectSmiValues(); 1616 void CollectSmiValues();
1615 1617
(...skipping 12 matching lines...) Expand all
1628 ConstraintInstr* InsertConstraintFor(Definition* defn, 1630 ConstraintInstr* InsertConstraintFor(Definition* defn,
1629 Range* constraint, 1631 Range* constraint,
1630 Instruction* after); 1632 Instruction* after);
1631 1633
1632 // Replace uses of the definition def that are dominated by instruction dom 1634 // Replace uses of the definition def that are dominated by instruction dom
1633 // with uses of other definition. 1635 // with uses of other definition.
1634 void RenameDominatedUses(Definition* def, 1636 void RenameDominatedUses(Definition* def,
1635 Instruction* dom, 1637 Instruction* dom,
1636 Definition* other); 1638 Definition* other);
1637 1639
1638 // Propagate range information until fix-point is reached. 1640
1641 // Walk the dominator tree and infer ranges for smi values.
1639 void InferRanges(); 1642 void InferRanges();
1643 void InferRangesRecursive(BlockEntryInstr* block);
1640 1644
1641 void ProcessWorklist(Definition::RangeOperator op); 1645 enum Direction {
1646 kUnknown,
1647 kPositive,
1648 kNegative,
1649 kBoth
1650 };
1642 1651
1643 // Walk the dominator tree, initialize ranges for smi values and place them 1652 Range* InferInductionVariableRange(JoinEntryInstr* loop_header,
1644 // to the worklist. 1653 PhiInstr* var);
1645 void InitializeRangesRecursive(BlockEntryInstr* block); 1654
1655 void ResetWorklist();
1656 void MarkDefinition(Definition* defn);
1657
1658 static Direction ToDirection(Value* val);
1659
1660 static Direction Invert(Direction direction) {
1661 return (direction == kPositive) ? kNegative : kPositive;
1662 }
1663
1664 static void UpdateDirection(Direction* direction,
1665 Direction new_direction) {
1666 if (*direction != new_direction) {
1667 if (*direction != kUnknown) new_direction = kBoth;
1668 *direction = new_direction;
1669 }
1670 }
1646 1671
1647 // Remove artificial Constraint instructions and replace them with actual 1672 // Remove artificial Constraint instructions and replace them with actual
1648 // unconstrained definitions. 1673 // unconstrained definitions.
1649 void RemoveConstraints(); 1674 void RemoveConstraints();
1650 1675
1651 void CreateWorklists();
1652
1653 void AddToWorklist(Definition* value) {
1654 const intptr_t index = value->ssa_temp_index();
1655 if (!in_worklist_->Contains(index)) {
1656 in_worklist_->Add(index);
1657 worklist_.Add(value);
1658 }
1659 }
1660
1661 bool IsWorklistEmpty() const {
1662 return worklist_.is_empty();
1663 }
1664
1665 Definition* RemoveLastFromWorklist() {
1666 Definition* defn = worklist_.Last();
1667 worklist_.RemoveLast();
1668 ASSERT(in_worklist_->Contains(defn->ssa_temp_index()));
1669 in_worklist_->Remove(defn->ssa_temp_index());
1670 return defn;
1671 }
1672
1673 void SwapWorklists();
1674
1675 FlowGraph* flow_graph_; 1676 FlowGraph* flow_graph_;
1676 1677
1677 GrowableArray<Definition*> smi_values_; // Value that are known to be smi. 1678 GrowableArray<Definition*> smi_values_; // Value that are known to be smi.
1678 GrowableArray<CheckSmiInstr*> smi_checks_; // All CheckSmi instructions. 1679 GrowableArray<CheckSmiInstr*> smi_checks_; // All CheckSmi instructions.
1679 1680
1680 // All Constraints inserted during InsertConstraints phase. They are treated 1681 // All Constraints inserted during InsertConstraints phase. They are treated
1681 // as smi values. 1682 // as smi values.
1682 GrowableArray<ConstraintInstr*> constraints_; 1683 GrowableArray<ConstraintInstr*> constraints_;
1683 1684
1684 // Bitvector for a quick filtering of known smi values. 1685 // Bitvector for a quick filtering of known smi values.
1685 BitVector* smi_definitions_; 1686 BitVector* smi_definitions_;
1686 1687
1687 // Worklist used during range propagation. 1688 // Worklist for induction variables analysis.
1688 GrowableArray<Definition*> worklist_; 1689 GrowableArray<Definition*> worklist_;
1689 BitVector* in_worklist_; 1690 BitVector* marked_defns_;
1690 1691
1691 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); 1692 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis);
1692 }; 1693 };
1693 1694
1694 1695
1695 void RangeAnalysis::Analyze() { 1696 void RangeAnalysis::Analyze() {
1696 CollectSmiValues(); 1697 CollectSmiValues();
1697 InsertConstraints(); 1698 InsertConstraints();
1698 InferRanges(); 1699 InferRanges();
1699 RemoveConstraints(); 1700 RemoveConstraints();
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
1934 InsertConstraintsFor(constraint); // Constrain uses further. 1935 InsertConstraintsFor(constraint); // Constrain uses further.
1935 } 1936 }
1936 } 1937 }
1937 1938
1938 for (intptr_t i = 0; i < smi_values_.length(); i++) { 1939 for (intptr_t i = 0; i < smi_values_.length(); i++) {
1939 InsertConstraintsFor(smi_values_[i]); 1940 InsertConstraintsFor(smi_values_[i]);
1940 } 1941 }
1941 } 1942 }
1942 1943
1943 1944
1944 void RangeAnalysis::InitializeRangesRecursive(BlockEntryInstr* block) { 1945 void RangeAnalysis::ResetWorklist() {
1946 if (marked_defns_ == NULL) {
1947 marked_defns_ = new BitVector(flow_graph_->current_ssa_temp_index());
1948 } else {
1949 marked_defns_->Clear();
1950 }
1951 worklist_.Clear();
1952 }
1953
1954
1955 void RangeAnalysis::MarkDefinition(Definition* defn) {
1956 // Unwrap constrained value.
1957 while (defn->IsConstraint()) {
1958 defn = defn->AsConstraint()->value()->definition();
1959 }
1960
1961 if (!marked_defns_->Contains(defn->ssa_temp_index())) {
1962 worklist_.Add(defn);
1963 marked_defns_->Add(defn->ssa_temp_index());
1964 }
1965 }
1966
1967
1968 RangeAnalysis::Direction RangeAnalysis::ToDirection(Value* val) {
1969 if (val->BindsToConstant()) {
1970 return (Smi::Cast(val->BoundConstant()).Value() >= 0) ? kPositive
1971 : kNegative;
1972 } else if (val->definition()->range() != NULL) {
1973 Range* range = val->definition()->range();
1974 if (Range::ConstantMin(range).value() >= 0) {
1975 return kPositive;
1976 } else if (Range::ConstantMax(range).value() <= 0) {
1977 return kNegative;
1978 }
1979 }
1980 return kUnknown;
1981 }
1982
1983
1984 Range* RangeAnalysis::InferInductionVariableRange(JoinEntryInstr* loop_header,
1985 PhiInstr* var) {
1986 BitVector* loop_info = loop_header->loop_info();
1987
1988 Definition* initial_value = NULL;
1989 Direction direction = kUnknown;
1990
1991 ResetWorklist();
1992 MarkDefinition(var);
1993 while (!worklist_.is_empty()) {
1994 Definition* defn = worklist_.Last();
1995 worklist_.RemoveLast();
1996
1997 if (defn->IsPhi()) {
1998 PhiInstr* phi = defn->AsPhi();
1999 for (intptr_t i = 0; i < phi->InputCount(); i++) {
2000 Definition* defn = phi->InputAt(i)->definition();
2001
2002 if (!loop_info->Contains(defn->GetBlock()->preorder_number())) {
2003 // The value is coming from outside of the loop.
2004 if (initial_value == NULL) {
2005 initial_value = defn;
2006 continue;
2007 } else if (initial_value == defn) {
2008 continue;
2009 } else {
2010 return NULL;
2011 }
2012 }
2013
2014 MarkDefinition(defn);
2015 }
2016 } else if (defn->IsBinarySmiOp()) {
2017 BinarySmiOpInstr* binary_op = defn->AsBinarySmiOp();
2018
2019 switch (binary_op->op_kind()) {
2020 case Token::kADD: {
2021 const Direction growth_right =
2022 ToDirection(binary_op->right());
2023 if (growth_right != kUnknown) {
2024 UpdateDirection(&direction, growth_right);
2025 MarkDefinition(binary_op->left()->definition());
2026 break;
2027 }
2028
2029 const Direction growth_left =
2030 ToDirection(binary_op->left());
2031 if (growth_left != kUnknown) {
2032 UpdateDirection(&direction, growth_left);
2033 MarkDefinition(binary_op->right()->definition());
2034 break;
2035 }
2036
2037 return NULL;
2038 }
2039
2040 case Token::kSUB: {
2041 const Direction growth_right =
2042 ToDirection(binary_op->right());
2043 if (growth_right != kUnknown) {
2044 UpdateDirection(&direction, Invert(growth_right));
2045 MarkDefinition(binary_op->left()->definition());
2046 break;
2047 }
2048 return NULL;
2049 }
2050
2051 default:
2052 return NULL;
2053 }
2054 } else {
2055 return NULL;
2056 }
2057 }
2058
2059
2060 // We transitively discovered all dependencies of the given phi
2061 // and confirmed that it depends on a single value coming from outside of
2062 // the loop and some linear combinations of itself.
2063 // Compute the range based on initial value and the direction of the growth.
2064 switch (direction) {
2065 case kPositive:
2066 return new Range(RangeBoundary::FromDefinition(initial_value),
2067 RangeBoundary::MaxSmi());
2068
2069 case kNegative:
2070 return new Range(RangeBoundary::MinSmi(),
2071 RangeBoundary::FromDefinition(initial_value));
2072
2073 case kUnknown:
2074 case kBoth:
2075 return Range::Unknown();
2076 }
2077
2078 UNREACHABLE();
2079 return NULL;
2080 }
2081
2082
2083 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) {
1945 JoinEntryInstr* join = block->AsJoinEntry(); 2084 JoinEntryInstr* join = block->AsJoinEntry();
1946 if (join != NULL) { 2085 if (join != NULL) {
2086 const bool is_loop_header = (join->loop_info() != NULL);
1947 for (PhiIterator it(join); !it.Done(); it.Advance()) { 2087 for (PhiIterator it(join); !it.Done(); it.Advance()) {
1948 PhiInstr* phi = it.Current(); 2088 PhiInstr* phi = it.Current();
1949 if (smi_definitions_->Contains(phi->ssa_temp_index())) { 2089 if (smi_definitions_->Contains(phi->ssa_temp_index())) {
1950 phi->InferRange(Definition::kRangeInit); 2090 if (is_loop_header) {
1951 AddToWorklist(phi); 2091 // Try recognizing simple induction variables.
2092 Range* range = InferInductionVariableRange(join, phi);
2093 if (range != NULL) {
2094 phi->range_ = range;
2095 continue;
2096 }
2097 }
2098
2099 phi->InferRange();
1952 } 2100 }
1953 } 2101 }
1954 } 2102 }
1955 2103
1956 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { 2104 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
1957 Definition* defn = it.Current()->AsDefinition(); 2105 Definition* defn = it.Current()->AsDefinition();
1958 if ((defn != NULL) && 2106 if ((defn != NULL) &&
1959 (defn->ssa_temp_index() != -1) && 2107 (defn->ssa_temp_index() != -1) &&
1960 smi_definitions_->Contains(defn->ssa_temp_index())) { 2108 smi_definitions_->Contains(defn->ssa_temp_index())) {
1961 defn->InferRange(Definition::kRangeInit); 2109 defn->InferRange();
1962 AddToWorklist(defn);
1963 } 2110 }
1964 } 2111 }
1965 2112
1966 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { 2113 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
1967 InitializeRangesRecursive(block->dominated_blocks()[i]); 2114 InferRangesRecursive(block->dominated_blocks()[i]);
1968 }
1969 }
1970
1971
1972 void RangeAnalysis::CreateWorklists() {
1973 in_worklist_ = new BitVector(flow_graph_->current_ssa_temp_index());
1974 }
1975
1976
1977 void RangeAnalysis::ProcessWorklist(Definition::RangeOperator op) {
1978 // Iterate until fix point is reached.
1979 while (!IsWorklistEmpty()) {
1980 Definition* defn = RemoveLastFromWorklist();
1981 if (FLAG_trace_range_analysis) {
1982 OS::Print("infering range for v%"Pd" %s\n",
1983 defn->ssa_temp_index(),
1984 Range::ToCString(defn->range()));
1985 }
1986 if (defn->InferRange(op)) { // Update the range.
1987 if (FLAG_trace_range_analysis) {
1988 OS::Print(" changed to %s\n", Range::ToCString(defn->range()));
1989 }
1990 // Range change. Place all uses to the worklist.
1991 for (Value* use = defn->input_use_list();
1992 use != NULL;
1993 use = use->next_use()) {
1994 Definition* use_defn = use->instruction()->AsDefinition();
1995 if ((use_defn != NULL) &&
1996 (use_defn->ssa_temp_index() != -1) &&
1997 smi_definitions_->Contains(use_defn->ssa_temp_index())) {
1998 AddToWorklist(use_defn);
1999 }
2000 }
2001 }
2002 } 2115 }
2003 } 2116 }
2004 2117
2005 2118
2006 void RangeAnalysis::InferRanges() { 2119 void RangeAnalysis::InferRanges() {
2007 CreateWorklists();
2008
2009 // Initialize bitvector for quick filtering of smi values. 2120 // Initialize bitvector for quick filtering of smi values.
2010 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); 2121 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index());
2011 for (intptr_t i = 0; i < smi_values_.length(); i++) { 2122 for (intptr_t i = 0; i < smi_values_.length(); i++) {
2012 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); 2123 smi_definitions_->Add(smi_values_[i]->ssa_temp_index());
2013 } 2124 }
2014 for (intptr_t i = 0; i < constraints_.length(); i++) { 2125 for (intptr_t i = 0; i < constraints_.length(); i++) {
2015 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); 2126 smi_definitions_->Add(constraints_[i]->ssa_temp_index());
2016 } 2127 }
2017 2128
2018 // Infer initial values of ranges. 2129 // Infer initial values of ranges.
2019 InitializeRangesRecursive(flow_graph_->graph_entry()); 2130 InferRangesRecursive(flow_graph_->graph_entry());
2020
2021 for (intptr_t i = 0; i < smi_values_.length(); i++) {
2022 if (smi_values_[i]->IsPhi() &&
2023 smi_values_[i]->InferRange(Definition::kRangeInit)) {
2024 Definition* defn = smi_values_[i];
2025 for (Value* use = defn->input_use_list();
2026 use != NULL;
2027 use = use->next_use()) {
2028 Definition* use_defn = use->instruction()->AsDefinition();
2029 if ((use_defn != NULL) &&
2030 (use_defn->ssa_temp_index() != -1) &&
2031 smi_definitions_->Contains(use_defn->ssa_temp_index())) {
2032 AddToWorklist(use_defn);
2033 }
2034 }
2035 }
2036 }
2037 2131
2038 if (FLAG_trace_range_analysis) { 2132 if (FLAG_trace_range_analysis) {
2039 OS::Print("---- after initialization -------\n"); 2133 OS::Print("---- after range analysis -------\n");
2040 FlowGraphPrinter printer(*flow_graph_); 2134 FlowGraphPrinter printer(*flow_graph_);
2041 printer.PrintBlocks(); 2135 printer.PrintBlocks();
2042 } 2136 }
2043
2044 if (FLAG_trace_range_analysis) {
2045 OS::Print("---- widening ---------\n");
2046 }
2047 ProcessWorklist(Definition::kRangeWiden);
2048
2049 if (FLAG_trace_range_analysis) {
2050 OS::Print("---- after widening -------\n");
2051 FlowGraphPrinter printer(*flow_graph_);
2052 printer.PrintBlocks();
2053 }
2054
2055 if (FLAG_trace_range_analysis) {
2056 OS::Print("---- narrowing ---------\n");
2057 }
2058 // Only phis can change under narrowing operator. Place all phis
2059 // into the worklist.
2060 for (intptr_t i = 0; i < smi_values_.length(); i++) {
2061 if (smi_values_[i]->IsPhi()) AddToWorklist(smi_values_[i]);
2062 }
2063 ProcessWorklist(Definition::kRangeNarrow);
2064
2065 if (FLAG_trace_range_analysis) {
2066 OS::Print("---- after narrowing -------\n");
2067 FlowGraphPrinter printer(*flow_graph_);
2068 printer.PrintBlocks();
2069 }
2070 } 2137 }
2071 2138
2072 2139
2073 void RangeAnalysis::RemoveConstraints() { 2140 void RangeAnalysis::RemoveConstraints() {
2074 for (intptr_t i = 0; i < constraints_.length(); i++) { 2141 for (intptr_t i = 0; i < constraints_.length(); i++) {
2075 Definition* def = constraints_[i]->value()->definition(); 2142 Definition* def = constraints_[i]->value()->definition();
2076 // Some constraints might be constraining constraints. Unwind the chain of 2143 // Some constraints might be constraining constraints. Unwind the chain of
2077 // constraints until we reach the actual definition. 2144 // constraints until we reach the actual definition.
2078 while (def->IsConstraint()) { 2145 while (def->IsConstraint()) {
2079 def = def->AsConstraint()->value()->definition(); 2146 def = def->AsConstraint()->value()->definition();
(...skipping 1394 matching lines...) Expand 10 before | Expand all | Expand 10 after
3474 3541
3475 if (FLAG_trace_constant_propagation) { 3542 if (FLAG_trace_constant_propagation) {
3476 OS::Print("\n==== After constant propagation ====\n"); 3543 OS::Print("\n==== After constant propagation ====\n");
3477 FlowGraphPrinter printer(*graph_); 3544 FlowGraphPrinter printer(*graph_);
3478 printer.PrintBlocks(); 3545 printer.PrintBlocks();
3479 } 3546 }
3480 } 3547 }
3481 3548
3482 3549
3483 } // namespace dart 3550 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698