Chromium Code Reviews| 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 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 694 RangeBoundary::kRangeBoundaryInt32) && | 694 RangeBoundary::kRangeBoundaryInt32) && |
| 695 BinaryInt32OpInstr::IsSupported(mint_op->op_kind(), | 695 BinaryInt32OpInstr::IsSupported(mint_op->op_kind(), |
| 696 mint_op->left(), | 696 mint_op->left(), |
| 697 mint_op->right())) { | 697 mint_op->right())) { |
| 698 BinaryInt32OpInstr* int32_op = | 698 BinaryInt32OpInstr* int32_op = |
| 699 new BinaryInt32OpInstr(mint_op->op_kind(), | 699 new BinaryInt32OpInstr(mint_op->op_kind(), |
| 700 mint_op->left()->CopyWithType(), | 700 mint_op->left()->CopyWithType(), |
| 701 mint_op->right()->CopyWithType(), | 701 mint_op->right()->CopyWithType(), |
| 702 mint_op->DeoptimizationTarget()); | 702 mint_op->DeoptimizationTarget()); |
| 703 int32_op->set_range(*mint_op->range()); | 703 int32_op->set_range(*mint_op->range()); |
| 704 int32_op->set_overflow(false); | 704 int32_op->set_can_overflow(false); |
| 705 mint_op->ReplaceWith(int32_op, NULL); | 705 mint_op->ReplaceWith(int32_op, NULL); |
| 706 } | 706 } |
| 707 } | 707 } |
| 708 | 708 |
| 709 | 709 |
| 710 static void NarrowShiftMintOp(ShiftMintOpInstr* mint_op) { | 710 static void NarrowShiftMintOp(ShiftMintOpInstr* mint_op) { |
| 711 if (RangeUtils::Fits(mint_op->range(), RangeBoundary::kRangeBoundaryInt32) && | 711 if (RangeUtils::Fits(mint_op->range(), RangeBoundary::kRangeBoundaryInt32) && |
| 712 RangeUtils::Fits(mint_op->left()->definition()->range(), | 712 RangeUtils::Fits(mint_op->left()->definition()->range(), |
| 713 RangeBoundary::kRangeBoundaryInt32) && | 713 RangeBoundary::kRangeBoundaryInt32) && |
| 714 RangeUtils::Fits(mint_op->right()->definition()->range(), | 714 RangeUtils::Fits(mint_op->right()->definition()->range(), |
| 715 RangeBoundary::kRangeBoundaryInt32) && | 715 RangeBoundary::kRangeBoundaryInt32) && |
| 716 BinaryInt32OpInstr::IsSupported(mint_op->op_kind(), | 716 BinaryInt32OpInstr::IsSupported(mint_op->op_kind(), |
| 717 mint_op->left(), | 717 mint_op->left(), |
| 718 mint_op->right())) { | 718 mint_op->right())) { |
| 719 BinaryInt32OpInstr* int32_op = | 719 BinaryInt32OpInstr* int32_op = |
| 720 new BinaryInt32OpInstr(mint_op->op_kind(), | 720 new BinaryInt32OpInstr(mint_op->op_kind(), |
| 721 mint_op->left()->CopyWithType(), | 721 mint_op->left()->CopyWithType(), |
| 722 mint_op->right()->CopyWithType(), | 722 mint_op->right()->CopyWithType(), |
| 723 mint_op->DeoptimizationTarget()); | 723 mint_op->DeoptimizationTarget()); |
| 724 int32_op->set_range(*mint_op->range()); | 724 int32_op->set_range(*mint_op->range()); |
| 725 int32_op->set_overflow(false); | 725 int32_op->set_can_overflow(false); |
| 726 mint_op->ReplaceWith(int32_op, NULL); | 726 mint_op->ReplaceWith(int32_op, NULL); |
| 727 } | 727 } |
| 728 } | 728 } |
| 729 | 729 |
| 730 | 730 |
| 731 void RangeAnalysis::NarrowMintToInt32() { | 731 void RangeAnalysis::NarrowMintToInt32() { |
| 732 for (intptr_t i = 0; i < binary_mint_ops_.length(); i++) { | 732 for (intptr_t i = 0; i < binary_mint_ops_.length(); i++) { |
| 733 NarrowBinaryMintOp(binary_mint_ops_[i]); | 733 NarrowBinaryMintOp(binary_mint_ops_[i]); |
| 734 } | 734 } |
| 735 | 735 |
| (...skipping 1250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1986 | 1986 |
| 1987 | 1987 |
| 1988 void IfThenElseInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1988 void IfThenElseInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 1989 const intptr_t min = Utils::Minimum(if_true_, if_false_); | 1989 const intptr_t min = Utils::Minimum(if_true_, if_false_); |
| 1990 const intptr_t max = Utils::Maximum(if_true_, if_false_); | 1990 const intptr_t max = Utils::Maximum(if_true_, if_false_); |
| 1991 *range = Range(RangeBoundary::FromConstant(min), | 1991 *range = Range(RangeBoundary::FromConstant(min), |
| 1992 RangeBoundary::FromConstant(max)); | 1992 RangeBoundary::FromConstant(max)); |
| 1993 } | 1993 } |
| 1994 | 1994 |
| 1995 | 1995 |
| 1996 void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 1996 static RangeBoundary::RangeSize RepresentationToRangeSize(Representation r) { |
| 1997 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | 1997 switch (r) { |
| 1998 case kTagged: | |
| 1999 return RangeBoundary::kRangeBoundarySmi; | |
| 2000 case kUnboxedInt32: | |
| 2001 return RangeBoundary::kRangeBoundaryInt32; | |
| 2002 case kUnboxedMint: | |
| 2003 return RangeBoundary::kRangeBoundaryInt64; | |
| 2004 default: | |
| 2005 UNREACHABLE(); | |
| 2006 return RangeBoundary::kRangeBoundarySmi; | |
| 2007 } | |
| 2008 } | |
| 2009 | |
| 2010 | |
| 2011 void BinaryIntegerOpInstr::InferRangeHelper(const Range* left_range, | |
| 2012 const Range* right_range, | |
| 2013 Range* range) { | |
| 2014 // TODO(vegorov): canonicalize BinaryIntegerOp to always have constant on the | |
| 1998 // right and a non-constant on the left. | 2015 // right and a non-constant on the left. |
| 1999 Definition* left_defn = left()->definition(); | 2016 if (Range::IsUnknown(left_range) || |
| 2000 | 2017 Range::IsUnknown(right_range)) { |
|
srdjan
2014/09/11 17:38:11
One line?
| |
| 2001 const Range* left_range = analysis->GetSmiRange(left()); | |
| 2002 const Range* right_range = analysis->GetSmiRange(right()); | |
| 2003 | |
| 2004 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | |
| 2005 return; | 2018 return; |
| 2006 } | 2019 } |
| 2007 | 2020 |
| 2008 Range::BinaryOp(op_kind(), | 2021 Range::BinaryOp(op_kind(), |
| 2009 left_range, | 2022 left_range, |
| 2010 right_range, | 2023 right_range, |
| 2011 left_defn, | 2024 left()->definition(), |
| 2012 range); | 2025 range); |
| 2013 ASSERT(!Range::IsUnknown(range)); | 2026 ASSERT(!Range::IsUnknown(range)); |
| 2014 | 2027 |
| 2015 // Calculate overflowed status before clamping. | 2028 const RangeBoundary::RangeSize range_size = |
| 2016 const bool overflowed = range->min().LowerBound().OverflowedSmi() || | 2029 RepresentationToRangeSize(representation()); |
| 2017 range->max().UpperBound().OverflowedSmi(); | |
| 2018 set_overflow(overflowed); | |
| 2019 | 2030 |
| 2020 // Clamp value to be within smi range. | 2031 // Calculate overflowed status before clamping if operation is |
| 2021 range->Clamp(RangeBoundary::kRangeBoundarySmi); | 2032 // not truncating. |
| 2033 if (!is_truncating()) { | |
| 2034 set_can_overflow(!range->Fits(range_size)); | |
| 2035 } | |
| 2036 | |
| 2037 range->Clamp(range_size); | |
| 2022 } | 2038 } |
| 2023 | 2039 |
| 2024 | 2040 |
| 2041 void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2042 // TODO(vegorov) completely remove this once GetSmiRange is eliminated. | |
| 2043 InferRangeHelper(analysis->GetSmiRange(left()), | |
| 2044 analysis->GetSmiRange(right()), | |
| 2045 range); | |
| 2046 } | |
| 2047 | |
| 2048 | |
| 2049 void BinaryInt32OpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2050 InferRangeHelper(analysis->GetSmiRange(left()), | |
| 2051 analysis->GetSmiRange(right()), | |
| 2052 range); | |
| 2053 } | |
| 2054 | |
| 2055 | |
| 2056 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2057 InferRangeHelper(left()->definition()->range(), | |
| 2058 right()->definition()->range(), | |
| 2059 range); | |
| 2060 } | |
| 2061 | |
| 2062 | |
| 2063 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2064 InferRangeHelper(left()->definition()->range(), | |
| 2065 right()->definition()->range(), | |
| 2066 range); | |
| 2067 } | |
| 2068 | |
| 2069 | |
| 2025 void BoxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { | 2070 void BoxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2026 const Range* value_range = value()->definition()->range(); | 2071 const Range* value_range = value()->definition()->range(); |
| 2027 if (!Range::IsUnknown(value_range)) { | 2072 if (!Range::IsUnknown(value_range)) { |
| 2028 *range = *value_range; | 2073 *range = *value_range; |
| 2029 } | 2074 } |
| 2030 } | 2075 } |
| 2031 | 2076 |
| 2032 | 2077 |
| 2033 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { | 2078 void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2034 if (value()->definition()->Type()->ToCid() == kSmiCid) { | 2079 if (value()->definition()->Type()->ToCid() == kSmiCid) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2070 RangeBoundary::FromConstant(static_cast<int64_t>(kMaxUint32))); | 2115 RangeBoundary::FromConstant(static_cast<int64_t>(kMaxUint32))); |
| 2071 } else { | 2116 } else { |
| 2072 *range = *value_range; | 2117 *range = *value_range; |
| 2073 if (to() == kUnboxedInt32) { | 2118 if (to() == kUnboxedInt32) { |
| 2074 range->Clamp(RangeBoundary::kRangeBoundaryInt32); | 2119 range->Clamp(RangeBoundary::kRangeBoundaryInt32); |
| 2075 } | 2120 } |
| 2076 } | 2121 } |
| 2077 } | 2122 } |
| 2078 | 2123 |
| 2079 | 2124 |
| 2080 void BinaryInt32OpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2081 // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the | |
| 2082 // right and a non-constant on the left. | |
| 2083 Definition* left_defn = left()->definition(); | |
| 2084 | |
| 2085 const Range* left_range = analysis->GetSmiRange(left()); | |
| 2086 const Range* right_range = analysis->GetSmiRange(right()); | |
| 2087 | |
| 2088 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | |
| 2089 return; | |
| 2090 } | |
| 2091 | |
| 2092 Range::BinaryOp(op_kind(), | |
| 2093 left_range, | |
| 2094 right_range, | |
| 2095 left_defn, | |
| 2096 range); | |
| 2097 ASSERT(!Range::IsUnknown(range)); | |
| 2098 | |
| 2099 // Calculate overflowed status before clamping. | |
| 2100 set_overflow(!range->Fits(RangeBoundary::kRangeBoundaryInt32)); | |
| 2101 | |
| 2102 // Clamp value to be within smi range. | |
| 2103 range->Clamp(RangeBoundary::kRangeBoundaryInt32); | |
| 2104 } | |
| 2105 | |
| 2106 void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2107 // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on | |
| 2108 // the right and a non-constant on the left. | |
| 2109 Definition* left_defn = left()->definition(); | |
| 2110 | |
| 2111 const Range* left_range = left_defn->range(); | |
| 2112 const Range* right_range = right()->definition()->range(); | |
| 2113 | |
| 2114 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | |
| 2115 return; | |
| 2116 } | |
| 2117 | |
| 2118 Range::BinaryOp(op_kind(), | |
| 2119 left_range, | |
| 2120 right_range, | |
| 2121 left_defn, | |
| 2122 range); | |
| 2123 ASSERT(!Range::IsUnknown(range)); | |
| 2124 | |
| 2125 // Calculate overflowed status before clamping. | |
| 2126 set_can_overflow(!range->Fits(RangeBoundary::kRangeBoundaryInt64)); | |
| 2127 | |
| 2128 // Clamp value to be within mint range. | |
| 2129 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | |
| 2130 } | |
| 2131 | |
| 2132 | |
| 2133 void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { | |
| 2134 Definition* left_defn = left()->definition(); | |
| 2135 | |
| 2136 const Range* left_range = left_defn->range(); | |
| 2137 const Range* right_range = right()->definition()->range(); | |
| 2138 | |
| 2139 if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) { | |
| 2140 return; | |
| 2141 } | |
| 2142 | |
| 2143 Range::BinaryOp(op_kind(), | |
| 2144 left_range, | |
| 2145 right_range, | |
| 2146 left_defn, | |
| 2147 range); | |
| 2148 ASSERT(!Range::IsUnknown(range)); | |
| 2149 | |
| 2150 // Calculate overflowed status before clamping. | |
| 2151 const bool overflowed = range->min().LowerBound().OverflowedMint() || | |
| 2152 range->max().UpperBound().OverflowedMint(); | |
| 2153 set_can_overflow(overflowed); | |
| 2154 | |
| 2155 // Clamp value to be within mint range. | |
| 2156 range->Clamp(RangeBoundary::kRangeBoundaryInt64); | |
| 2157 } | |
| 2158 | |
| 2159 | |
| 2160 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { | 2125 void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
| 2161 const Range* input_range = value()->definition()->range(); | 2126 const Range* input_range = value()->definition()->range(); |
| 2162 if (input_range != NULL) { | 2127 if (input_range != NULL) { |
| 2163 bool is_smi = input_range->Fits(RangeBoundary::kRangeBoundarySmi); | 2128 bool is_smi = input_range->Fits(RangeBoundary::kRangeBoundarySmi); |
| 2164 set_is_smi(is_smi); | 2129 set_is_smi(is_smi); |
| 2165 // The output range is the same as the input range. | 2130 // The output range is the same as the input range. |
| 2166 *range = *input_range; | 2131 *range = *input_range; |
| 2167 } | 2132 } |
| 2168 } | 2133 } |
| 2169 | 2134 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2225 } | 2190 } |
| 2226 } while (CanonicalizeMaxBoundary(&max) || | 2191 } while (CanonicalizeMaxBoundary(&max) || |
| 2227 CanonicalizeMinBoundary(&canonical_length)); | 2192 CanonicalizeMinBoundary(&canonical_length)); |
| 2228 | 2193 |
| 2229 // Failed to prove that maximum is bounded with array length. | 2194 // Failed to prove that maximum is bounded with array length. |
| 2230 return false; | 2195 return false; |
| 2231 } | 2196 } |
| 2232 | 2197 |
| 2233 | 2198 |
| 2234 } // namespace dart | 2199 } // namespace dart |
| OLD | NEW |