Chromium Code Reviews| Index: runtime/vm/intermediate_language.cc |
| =================================================================== |
| --- runtime/vm/intermediate_language.cc (revision 31418) |
| +++ runtime/vm/intermediate_language.cc (working copy) |
| @@ -2618,6 +2618,30 @@ |
| } |
| +static int64_t ConstantAbsMax(const Range* range) { |
| + if (range == NULL) return Smi::kMaxValue; |
| + const int64_t a = Utils::Abs(Range::ConstantMin(range).value()); |
|
Florian Schneider
2014/01/06 19:11:43
Maybe rename a/b to abs_min/abs_max.
srdjan
2014/01/06 20:39:09
Done.
|
| + const int64_t b = Utils::Abs(Range::ConstantMax(range).value()); |
| + return a > b ? a : b; |
| +} |
| + |
| + |
| +static bool OnlyPositiveOrZero(const Range* a, const Range* b) { |
| + if ((a == NULL) || (b == NULL)) return false; |
| + if (Range::ConstantMin(a).value() < 0) return false; |
| + if (Range::ConstantMin(b).value() < 0) return false; |
| + return true; |
| +} |
| + |
| + |
| +static bool OnlyNegativeOrZero(const Range* a, const Range* b) { |
| + if ((a == NULL) || (b == NULL)) return false; |
| + if (Range::ConstantMax(a).value() > 0) return false; |
| + if (Range::ConstantMax(b).value() > 0) return false; |
| + return true; |
| +} |
| + |
| + |
| void BinarySmiOpInstr::InferRange() { |
| // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the |
| // right and a non-constant on the left. |
| @@ -2674,6 +2698,27 @@ |
| } |
| break; |
| + case Token::kMUL: { |
| + const int64_t left_max = ConstantAbsMax(left_range); |
| + const int64_t right_max = ConstantAbsMax(right_range); |
| + if ((left_max < 0x7FFFFFFF) && (right_max < 0x7FFFFFFF)) { |
| + // Product of left and right max values stays in 64 bit range. |
| + const int64_t result_max = left_max * right_max; |
| + if (Smi::IsValid64(result_max) && Smi::IsValid64(-result_max)) { |
| + const intptr_t r_min = |
| + OnlyPositiveOrZero(left_range, right_range) ? 0 : -result_max; |
| + min = RangeBoundary::FromConstant(r_min); |
| + const intptr_t r_max = |
| + OnlyNegativeOrZero(left_range, right_range) ? 0 : result_max; |
| + max = RangeBoundary::FromConstant(r_max); |
| + break; |
| + } |
| + } |
| + if (range_ == NULL) { |
| + range_ = Range::Unknown(); |
| + } |
| + return; |
| + } |
| case Token::kBIT_AND: |
| if (Range::ConstantMin(right_range).value() >= 0) { |
| min = RangeBoundary::FromConstant(0); |