| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_range_analysis.h" | 5 #include "vm/flow_graph_range_analysis.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/il_printer.h" | 8 #include "vm/il_printer.h" |
| 9 | 9 |
| 10 namespace dart { | 10 namespace dart { |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 UNREACHABLE(); | 192 UNREACHABLE(); |
| 193 return NULL; | 193 return NULL; |
| 194 } | 194 } |
| 195 } | 195 } |
| 196 | 196 |
| 197 | 197 |
| 198 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Value* use, | 198 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Value* use, |
| 199 Definition* defn, | 199 Definition* defn, |
| 200 Range* constraint_range, | 200 Range* constraint_range, |
| 201 Instruction* after) { | 201 Instruction* after) { |
| 202 // Avoid constraining inside the dead code. | |
| 203 if (!use->IsSmiValue()) return NULL; | |
| 204 | |
| 205 // No need to constrain constants. | 202 // No need to constrain constants. |
| 206 if (defn->IsConstant()) return NULL; | 203 if (defn->IsConstant()) return NULL; |
| 207 | 204 |
| 208 // Check if the value is already constrained to avoid inserting duplicated | 205 // Check if the value is already constrained to avoid inserting duplicated |
| 209 // constraints. | 206 // constraints. |
| 210 ConstraintInstr* constraint = after->next()->AsConstraint(); | 207 ConstraintInstr* constraint = after->next()->AsConstraint(); |
| 211 while (constraint != NULL) { | 208 while (constraint != NULL) { |
| 212 if ((constraint->value()->definition() == defn) && | 209 if ((constraint->value()->definition() == defn) && |
| 213 constraint->constraint()->Equals(constraint_range)) { | 210 constraint->constraint()->Equals(constraint_range)) { |
| 214 return NULL; | 211 return NULL; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 for (intptr_t i = 0; i < values_.length(); i++) { | 312 for (intptr_t i = 0; i < values_.length(); i++) { |
| 316 InsertConstraintsFor(values_[i]); | 313 InsertConstraintsFor(values_[i]); |
| 317 } | 314 } |
| 318 | 315 |
| 319 for (intptr_t i = 0; i < constraints_.length(); i++) { | 316 for (intptr_t i = 0; i < constraints_.length(); i++) { |
| 320 InsertConstraintsFor(constraints_[i]); | 317 InsertConstraintsFor(constraints_[i]); |
| 321 } | 318 } |
| 322 } | 319 } |
| 323 | 320 |
| 324 | 321 |
| 325 const Range* RangeAnalysis::GetRange(Value* value) const { | 322 const Range* RangeAnalysis::GetSmiRange(Value* value) const { |
| 326 Definition* defn = value->definition(); | 323 Definition* defn = value->definition(); |
| 327 const Range* range = defn->range(); | 324 const Range* range = defn->range(); |
| 328 | 325 |
| 329 if ((range == NULL) && | 326 if ((range == NULL) && (defn->Type()->ToCid() != kSmiCid)) { |
| 330 (value->Type()->ToCid() == kSmiCid) && | |
| 331 (defn->Type()->ToCid() != kSmiCid)) { | |
| 332 // Type propagator determined that reaching type for this use is Smi. | 327 // Type propagator determined that reaching type for this use is Smi. |
| 333 // However the definition itself is not a smi-definition and | 328 // However the definition itself is not a smi-definition and |
| 334 // thus it will never have range assigned to it. Just return the widest | 329 // thus it will never have range assigned to it. Just return the widest |
| 335 // range possible for this value. | 330 // range possible for this value. |
| 336 // We don't need to handle kMintCid here because all external mints | 331 // We don't need to handle kMintCid here because all external mints |
| 337 // (e.g. results of loads or function call) can be used only after they | 332 // (e.g. results of loads or function call) can be used only after they |
| 338 // pass through UnboxIntegerInstr which is considered as mint-definition | 333 // pass through UnboxIntegerInstr which is considered as mint-definition |
| 339 // and will have a range assigned to it. | 334 // and will have a range assigned to it. |
| 340 // Note: that we can't return NULL here because it is used as lattice's | 335 // Note: that we can't return NULL here because it is used as lattice's |
| 341 // bottom element to indicate that the range was not computed *yet*. | 336 // bottom element to indicate that the range was not computed *yet*. |
| (...skipping 1414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 } | 1751 } |
| 1757 | 1752 |
| 1758 return limit; | 1753 return limit; |
| 1759 } | 1754 } |
| 1760 | 1755 |
| 1761 | 1756 |
| 1762 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1757 void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1763 ASSERT(Type()->ToCid() == kSmiCid); | 1758 ASSERT(Type()->ToCid() == kSmiCid); |
| 1764 for (intptr_t i = 0; i < InputCount(); i++) { | 1759 for (intptr_t i = 0; i < InputCount(); i++) { |
| 1765 Value* input = InputAt(i); | 1760 Value* input = InputAt(i); |
| 1766 Join(range, input->definition(), analysis->GetRange(input)); | 1761 Join(range, input->definition(), analysis->GetSmiRange(input)); |
| 1767 } | 1762 } |
| 1768 | 1763 |
| 1769 BlockEntryInstr* phi_block = GetBlock(); | 1764 BlockEntryInstr* phi_block = GetBlock(); |
| 1770 range->set_min(EnsureAcyclicSymbol( | 1765 range->set_min(EnsureAcyclicSymbol( |
| 1771 phi_block, range->min(), RangeBoundary::MinSmi())); | 1766 phi_block, range->min(), RangeBoundary::MinSmi())); |
| 1772 range->set_max(EnsureAcyclicSymbol( | 1767 range->set_max(EnsureAcyclicSymbol( |
| 1773 phi_block, range->max(), RangeBoundary::MaxSmi())); | 1768 phi_block, range->max(), RangeBoundary::MaxSmi())); |
| 1774 } | 1769 } |
| 1775 | 1770 |
| 1776 | 1771 |
| 1777 void ConstantInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1772 void ConstantInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1778 if (value_.IsSmi()) { | 1773 if (value_.IsSmi()) { |
| 1779 int64_t value = Smi::Cast(value_).Value(); | 1774 int64_t value = Smi::Cast(value_).Value(); |
| 1780 *range = Range(RangeBoundary::FromConstant(value), | 1775 *range = Range(RangeBoundary::FromConstant(value), |
| 1781 RangeBoundary::FromConstant(value)); | 1776 RangeBoundary::FromConstant(value)); |
| 1782 } else if (value_.IsMint()) { | 1777 } else if (value_.IsMint()) { |
| 1783 int64_t value = Mint::Cast(value_).value(); | 1778 int64_t value = Mint::Cast(value_).value(); |
| 1784 *range = Range(RangeBoundary::FromConstant(value), | 1779 *range = Range(RangeBoundary::FromConstant(value), |
| 1785 RangeBoundary::FromConstant(value)); | 1780 RangeBoundary::FromConstant(value)); |
| 1786 } else { | 1781 } else { |
| 1787 // Only Smi and Mint supported. | 1782 // Only Smi and Mint supported. |
| 1788 UNREACHABLE(); | 1783 UNREACHABLE(); |
| 1789 } | 1784 } |
| 1790 } | 1785 } |
| 1791 | 1786 |
| 1792 | 1787 |
| 1793 void ConstraintInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1788 void ConstraintInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1794 // Only constraining smi values. | 1789 const Range* value_range = analysis->GetSmiRange(value()); |
| 1795 ASSERT(value()->IsSmiValue()); | |
| 1796 | |
| 1797 const Range* value_range = analysis->GetRange(value()); | |
| 1798 if (Range::IsUnknown(value_range)) { | 1790 if (Range::IsUnknown(value_range)) { |
| 1799 return; | 1791 return; |
| 1800 } | 1792 } |
| 1801 | 1793 |
| 1802 // TODO(vegorov) check if precision of the analysis can be improved by | 1794 // TODO(vegorov) check if precision of the analysis can be improved by |
| 1803 // recognizing intersections of the form: | 1795 // recognizing intersections of the form: |
| 1804 // | 1796 // |
| 1805 // (..., S+x] ^ [S+x, ...) = [S+x, S+x] | 1797 // (..., S+x] ^ [S+x, ...) = [S+x, S+x] |
| 1806 // | 1798 // |
| 1807 Range result = value_range->Intersect(constraint()); | 1799 Range result = value_range->Intersect(constraint()); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1896 *range = Range(RangeBoundary::FromConstant(min), | 1888 *range = Range(RangeBoundary::FromConstant(min), |
| 1897 RangeBoundary::FromConstant(max)); | 1889 RangeBoundary::FromConstant(max)); |
| 1898 } | 1890 } |
| 1899 | 1891 |
| 1900 | 1892 |
| 1901 void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1893 void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1902 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 1894 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
| 1903 // right and a non-constant on the left. | 1895 // right and a non-constant on the left. |
| 1904 Definition* left_defn = left()->definition(); | 1896 Definition* left_defn = left()->definition(); |
| 1905 | 1897 |
| 1906 const Range* left_range = analysis->GetRange(left()); | 1898 const Range* left_range = analysis->GetSmiRange(left()); |
| 1907 const Range* right_range = analysis->GetRange(right()); | 1899 const Range* right_range = analysis->GetSmiRange(right()); |
| 1908 | 1900 |
| 1909 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 1901 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { |
| 1910 return; | 1902 return; |
| 1911 } | 1903 } |
| 1912 | 1904 |
| 1913 Range::BinaryOp(op_kind(), | 1905 Range::BinaryOp(op_kind(), |
| 1914 left_range, | 1906 left_range, |
| 1915 right_range, | 1907 right_range, |
| 1916 left_defn, | 1908 left_defn, |
| 1917 range); | 1909 range); |
| 1918 ASSERT(!Range::IsUnknown(range)); | 1910 ASSERT(!Range::IsUnknown(range)); |
| 1919 | 1911 |
| 1920 // Calculate overflowed status before clamping. | 1912 // Calculate overflowed status before clamping. |
| 1921 const bool overflowed = range->min().LowerBound().OverflowedSmi() || | 1913 const bool overflowed = range->min().LowerBound().OverflowedSmi() || |
| 1922 range->max().UpperBound().OverflowedSmi(); | 1914 range->max().UpperBound().OverflowedSmi(); |
| 1923 set_overflow(overflowed); | 1915 set_overflow(overflowed); |
| 1924 | 1916 |
| 1925 // Clamp value to be within smi range. | 1917 // Clamp value to be within smi range. |
| 1926 range->Clamp(RangeBoundary::kRangeBoundarySmi); | 1918 range->Clamp(RangeBoundary::kRangeBoundarySmi); |
| 1927 } | 1919 } |
| 1928 | 1920 |
| 1929 | 1921 |
| 1930 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1922 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1931 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on | 1923 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on |
| 1932 // the right and a non-constant on the left. | 1924 // the right and a non-constant on the left. |
| 1933 Definition* left_defn = left()->definition(); | 1925 Definition* left_defn = left()->definition(); |
| 1934 | 1926 |
| 1935 const Range* left_range = analysis->GetRange(left()); | 1927 const Range* left_range = left_defn->range(); |
| 1936 const Range* right_range = analysis->GetRange(right()); | 1928 const Range* right_range = right()->definition()->range(); |
| 1937 | 1929 |
| 1938 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 1930 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { |
| 1939 return; | 1931 return; |
| 1940 } | 1932 } |
| 1941 | 1933 |
| 1942 Range::BinaryOp(op_kind(), | 1934 Range::BinaryOp(op_kind(), |
| 1943 left_range, | 1935 left_range, |
| 1944 right_range, | 1936 right_range, |
| 1945 left_defn, | 1937 left_defn, |
| 1946 range); | 1938 range); |
| 1947 ASSERT(!Range::IsUnknown(range)); | 1939 ASSERT(!Range::IsUnknown(range)); |
| 1948 | 1940 |
| 1949 // Calculate overflowed status before clamping. | 1941 // Calculate overflowed status before clamping. |
| 1950 const bool overflowed = range->min().LowerBound().OverflowedMint() || | 1942 const bool overflowed = range->min().LowerBound().OverflowedMint() || |
| 1951 range->max().UpperBound().OverflowedMint(); | 1943 range->max().UpperBound().OverflowedMint(); |
| 1952 set_can_overflow(overflowed); | 1944 set_can_overflow(overflowed); |
| 1953 | 1945 |
| 1954 // Clamp value to be within mint range. | 1946 // Clamp value to be within mint range. |
| 1955 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | 1947 range->Clamp(RangeBoundary::kRangeBoundaryInt64); |
| 1956 } | 1948 } |
| 1957 | 1949 |
| 1958 | 1950 |
| 1959 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1951 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1960 Definition* left_defn = left()->definition(); | 1952 Definition* left_defn = left()->definition(); |
| 1961 | 1953 |
| 1962 const Range* left_range = analysis->GetRange(left()); | 1954 const Range* left_range = left_defn->range(); |
| 1963 const Range* right_range = analysis->GetRange(right()); | 1955 const Range* right_range = right()->definition()->range(); |
| 1964 | 1956 |
| 1965 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | 1957 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { |
| 1966 return; | 1958 return; |
| 1967 } | 1959 } |
| 1968 | 1960 |
| 1969 Range::BinaryOp(op_kind(), | 1961 Range::BinaryOp(op_kind(), |
| 1970 left_range, | 1962 left_range, |
| 1971 right_range, | 1963 right_range, |
| 1972 left_defn, | 1964 left_defn, |
| 1973 range); | 1965 range); |
| 1974 ASSERT(!Range::IsUnknown(range)); | 1966 ASSERT(!Range::IsUnknown(range)); |
| 1975 | 1967 |
| 1976 // Calculate overflowed status before clamping. | 1968 // Calculate overflowed status before clamping. |
| 1977 const bool overflowed = range->min().LowerBound().OverflowedMint() || | 1969 const bool overflowed = range->min().LowerBound().OverflowedMint() || |
| 1978 range->max().UpperBound().OverflowedMint(); | 1970 range->max().UpperBound().OverflowedMint(); |
| 1979 set_can_overflow(overflowed); | 1971 set_can_overflow(overflowed); |
| 1980 | 1972 |
| 1981 // Clamp value to be within mint range. | 1973 // Clamp value to be within mint range. |
| 1982 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | 1974 range->Clamp(RangeBoundary::kRangeBoundaryInt64); |
| 1983 } | 1975 } |
| 1984 | 1976 |
| 1985 | 1977 |
| 1986 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1978 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1987 const Range* input_range = analysis->GetRange(value()); | 1979 const Range* input_range = value()->definition()->range(); |
| 1988 if (input_range != NULL) { | 1980 if (input_range != NULL) { |
| 1989 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && | 1981 bool is_smi = !input_range->min().LowerBound().OverflowedSmi() && |
| 1990 !input_range->max().UpperBound().OverflowedSmi(); | 1982 !input_range->max().UpperBound().OverflowedSmi(); |
| 1991 set_is_smi(is_smi); | 1983 set_is_smi(is_smi); |
| 1992 // The output range is the same as the input range. | 1984 // The output range is the same as the input range. |
| 1993 *range = *input_range; | 1985 *range = *input_range; |
| 1994 } | 1986 } |
| 1995 } | 1987 } |
| 1996 | 1988 |
| 1997 | 1989 |
| 1998 void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1990 void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1999 const Range* value_range = analysis->GetRange(value()); | 1991 const Range* value_range = value()->definition()->range(); |
| 2000 if (value_range != NULL) { | 1992 if (value_range != NULL) { |
| 2001 *range = *value_range; | 1993 *range = *value_range; |
| 2002 } else if (!value()->definition()->IsMintDefinition() && | 1994 } else if (!value()->definition()->IsMintDefinition() && |
| 2003 (value()->Type()->ToCid() != kSmiCid)) { | 1995 (value()->definition()->Type()->ToCid() != kSmiCid)) { |
| 2004 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); | 1996 *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
| 2005 } | 1997 } |
| 2006 } | 1998 } |
| 2007 | 1999 |
| 2008 | 2000 |
| 2009 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { | 2001 bool CheckArrayBoundInstr::IsRedundant(const RangeBoundary& length) { |
| 2010 Range* index_range = index()->definition()->range(); | 2002 Range* index_range = index()->definition()->range(); |
| 2011 | 2003 |
| 2012 // Range of the index is unknown can't decide if the check is redundant. | 2004 // Range of the index is unknown can't decide if the check is redundant. |
| 2013 if (index_range == NULL) { | 2005 if (index_range == NULL) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 } | 2044 } |
| 2053 } while (CanonicalizeMaxBoundary(&max) || | 2045 } while (CanonicalizeMaxBoundary(&max) || |
| 2054 CanonicalizeMinBoundary(&canonical_length)); | 2046 CanonicalizeMinBoundary(&canonical_length)); |
| 2055 | 2047 |
| 2056 // Failed to prove that maximum is bounded with array length. | 2048 // Failed to prove that maximum is bounded with array length. |
| 2057 return false; | 2049 return false; |
| 2058 } | 2050 } |
| 2059 | 2051 |
| 2060 | 2052 |
| 2061 } // namespace dart | 2053 } // namespace dart |
| OLD | NEW |