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

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: 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 GrowthDirection {
Florian Schneider 2012/10/25 11:15:43 I'd rename this to just Direction. Growth implies
Vyacheslav Egorov (Google) 2012/10/25 11:24:27 Done.
1646 UNKNOWN,
Florian Schneider 2012/10/25 11:15:43 Maybe rename to the more common style kUnknown, k
Vyacheslav Egorov (Google) 2012/10/25 11:24:27 Done.
1647 POSITIVE,
1648 NEGATIVE,
1649 BOTH
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 GrowthDirection ToGrowthDirection(Value* val);
1659
1660 static GrowthDirection Invert(GrowthDirection direction) {
1661 return (direction == POSITIVE) ? NEGATIVE : POSITIVE;
1662 }
1663
1664 static void UpdateDirection(GrowthDirection* direction,
1665 GrowthDirection new_direction) {
1666 if (*direction != new_direction) {
1667 if (*direction != UNKNOWN) new_direction = BOTH;
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::GrowthDirection RangeAnalysis::ToGrowthDirection(Value* val) {
1969 if (val->BindsToConstant()) {
1970 return (Smi::Cast(val->BoundConstant()).Value() >= 0) ? POSITIVE : NEGATIVE;
1971 } else if (val->definition()->range() != NULL) {
1972 Range* range = val->definition()->range();
1973 if (Range::ConstantMin(range).value() >= 0) {
1974 return POSITIVE;
1975 } else if (Range::ConstantMax(range).value() <= 0) {
1976 return NEGATIVE;
1977 }
1978 }
1979 return UNKNOWN;
1980 }
1981
1982
1983 Range* RangeAnalysis::InferInductionVariableRange(JoinEntryInstr* loop_header,
1984 PhiInstr* var) {
1985 BitVector* loop_info = loop_header->loop_info();
1986
1987 Definition* initial_value = NULL;
1988 GrowthDirection direction = UNKNOWN;
1989
1990 ResetWorklist();
1991 MarkDefinition(var);
1992 while (!worklist_.is_empty()) {
1993 Definition* defn = worklist_.Last();
1994 worklist_.RemoveLast();
1995
1996 if (defn->IsPhi()) {
1997 PhiInstr* phi = defn->AsPhi();
1998 for (intptr_t i = 0; i < phi->InputCount(); i++) {
1999 Definition* defn = phi->InputAt(i)->definition();
2000
2001 if (!loop_info->Contains(defn->GetBlock()->preorder_number())) {
2002 // The value is comming from outside of the loop.
Florian Schneider 2012/10/25 11:15:43 s/comming/coming/
Vyacheslav Egorov (Google) 2012/10/25 11:24:27 Done.
2003 if (initial_value == NULL) {
2004 initial_value = defn;
2005 continue;
2006 } else if (initial_value == defn) {
2007 continue;
2008 } else {
2009 return NULL;
2010 }
2011 }
2012
2013 MarkDefinition(defn);
2014 }
2015 } else if (defn->IsBinarySmiOp()) {
2016 BinarySmiOpInstr* binary_op = defn->AsBinarySmiOp();
2017
2018 switch (binary_op->op_kind()) {
2019 case Token::kADD: {
2020 const GrowthDirection growth_right =
2021 ToGrowthDirection(binary_op->right());
2022 if (growth_right != UNKNOWN) {
2023 UpdateDirection(&direction, growth_right);
2024 MarkDefinition(binary_op->left()->definition());
2025 break;
2026 }
2027
2028 const GrowthDirection growth_left =
2029 ToGrowthDirection(binary_op->left());
2030 if (growth_left != UNKNOWN) {
2031 UpdateDirection(&direction, growth_left);
2032 MarkDefinition(binary_op->right()->definition());
2033 break;
2034 }
2035
2036 return NULL;
2037 }
2038
2039 case Token::kSUB: {
2040 const GrowthDirection growth_right =
2041 ToGrowthDirection(binary_op->right());
2042 if (growth_right != UNKNOWN) {
2043 UpdateDirection(&direction, Invert(growth_right));
2044 MarkDefinition(binary_op->left()->definition());
2045 break;
2046 }
2047 return NULL;
2048 }
2049
2050 default:
2051 return NULL;
2052 }
2053 } else {
2054 return NULL;
2055 }
2056 }
2057
2058
2059 // We transitively discovered all dependecies of the given phi
Florian Schneider 2012/10/25 11:15:43 s/dependecies/dependencies/
Vyacheslav Egorov (Google) 2012/10/25 11:24:27 Done.
2060 // and confirmed that it depends on a sigle value comming from outside of
Florian Schneider 2012/10/25 11:15:43 s/sigle/single/ s/comming/coming/g
Vyacheslav Egorov (Google) 2012/10/25 11:24:27 Done.
2061 // the loop and some linear combinations of itself.
2062 // Compute the range based on initial value and the direction of the growth.
2063 switch (direction) {
2064 case POSITIVE:
2065 return new Range(RangeBoundary::FromDefinition(initial_value),
2066 RangeBoundary::MaxSmi());
2067
2068 case NEGATIVE:
2069 return new Range(RangeBoundary::MinSmi(),
2070 RangeBoundary::FromDefinition(initial_value));
2071
2072 case UNKNOWN:
2073 case BOTH:
2074 return Range::Unknown();
2075 }
2076
2077 UNREACHABLE();
2078 return NULL;
2079 }
2080
2081
2082 void RangeAnalysis::InferRangesRecursive(BlockEntryInstr* block) {
1945 JoinEntryInstr* join = block->AsJoinEntry(); 2083 JoinEntryInstr* join = block->AsJoinEntry();
1946 if (join != NULL) { 2084 if (join != NULL) {
2085 const bool is_loop_header = (join->loop_info() != NULL);
1947 for (PhiIterator it(join); !it.Done(); it.Advance()) { 2086 for (PhiIterator it(join); !it.Done(); it.Advance()) {
1948 PhiInstr* phi = it.Current(); 2087 PhiInstr* phi = it.Current();
1949 if (smi_definitions_->Contains(phi->ssa_temp_index())) { 2088 if (smi_definitions_->Contains(phi->ssa_temp_index())) {
1950 phi->InferRange(Definition::kRangeInit); 2089 if (is_loop_header) {
1951 AddToWorklist(phi); 2090 // Try recognizing simple induction variables.
2091 Range* range = InferInductionVariableRange(join, phi);
2092 if (range != NULL) {
2093 phi->range_ = range;
2094 continue;
2095 }
2096 }
2097
2098 phi->InferRange();
1952 } 2099 }
1953 } 2100 }
1954 } 2101 }
1955 2102
1956 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { 2103 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
1957 Definition* defn = it.Current()->AsDefinition(); 2104 Definition* defn = it.Current()->AsDefinition();
1958 if ((defn != NULL) && 2105 if ((defn != NULL) &&
1959 (defn->ssa_temp_index() != -1) && 2106 (defn->ssa_temp_index() != -1) &&
1960 smi_definitions_->Contains(defn->ssa_temp_index())) { 2107 smi_definitions_->Contains(defn->ssa_temp_index())) {
1961 defn->InferRange(Definition::kRangeInit); 2108 defn->InferRange();
1962 AddToWorklist(defn);
1963 } 2109 }
1964 } 2110 }
1965 2111
1966 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { 2112 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
1967 InitializeRangesRecursive(block->dominated_blocks()[i]); 2113 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 } 2114 }
2003 } 2115 }
2004 2116
2005 2117
2006 void RangeAnalysis::InferRanges() { 2118 void RangeAnalysis::InferRanges() {
2007 CreateWorklists();
2008
2009 // Initialize bitvector for quick filtering of smi values. 2119 // Initialize bitvector for quick filtering of smi values.
2010 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); 2120 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index());
2011 for (intptr_t i = 0; i < smi_values_.length(); i++) { 2121 for (intptr_t i = 0; i < smi_values_.length(); i++) {
2012 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); 2122 smi_definitions_->Add(smi_values_[i]->ssa_temp_index());
2013 } 2123 }
2014 for (intptr_t i = 0; i < constraints_.length(); i++) { 2124 for (intptr_t i = 0; i < constraints_.length(); i++) {
2015 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); 2125 smi_definitions_->Add(constraints_[i]->ssa_temp_index());
2016 } 2126 }
2017 2127
2018 // Infer initial values of ranges. 2128 // Infer initial values of ranges.
2019 InitializeRangesRecursive(flow_graph_->graph_entry()); 2129 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 2130
2038 if (FLAG_trace_range_analysis) { 2131 if (FLAG_trace_range_analysis) {
2039 OS::Print("---- after initialization -------\n"); 2132 OS::Print("---- after range analysis -------\n");
2040 FlowGraphPrinter printer(*flow_graph_); 2133 FlowGraphPrinter printer(*flow_graph_);
2041 printer.PrintBlocks(); 2134 printer.PrintBlocks();
2042 } 2135 }
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 } 2136 }
2071 2137
2072 2138
2073 void RangeAnalysis::RemoveConstraints() { 2139 void RangeAnalysis::RemoveConstraints() {
2074 for (intptr_t i = 0; i < constraints_.length(); i++) { 2140 for (intptr_t i = 0; i < constraints_.length(); i++) {
2075 Definition* def = constraints_[i]->value()->definition(); 2141 Definition* def = constraints_[i]->value()->definition();
2076 // Some constraints might be constraining constraints. Unwind the chain of 2142 // Some constraints might be constraining constraints. Unwind the chain of
2077 // constraints until we reach the actual definition. 2143 // constraints until we reach the actual definition.
2078 while (def->IsConstraint()) { 2144 while (def->IsConstraint()) {
2079 def = def->AsConstraint()->value()->definition(); 2145 def = def->AsConstraint()->value()->definition();
(...skipping 1394 matching lines...) Expand 10 before | Expand all | Expand 10 after
3474 3540
3475 if (FLAG_trace_constant_propagation) { 3541 if (FLAG_trace_constant_propagation) {
3476 OS::Print("\n==== After constant propagation ====\n"); 3542 OS::Print("\n==== After constant propagation ====\n");
3477 FlowGraphPrinter printer(*graph_); 3543 FlowGraphPrinter printer(*graph_);
3478 printer.PrintBlocks(); 3544 printer.PrintBlocks();
3479 } 3545 }
3480 } 3546 }
3481 3547
3482 3548
3483 } // namespace dart 3549 } // 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