| Index: runtime/vm/flow_graph_range_analysis.cc
|
| diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
|
| index b0051f0fc182565c1230acc97427437943a28439..cad20f7ad1b9cdfc0873095ae663916f5ecb93d7 100644
|
| --- a/runtime/vm/flow_graph_range_analysis.cc
|
| +++ b/runtime/vm/flow_graph_range_analysis.cc
|
| @@ -31,6 +31,8 @@ void RangeAnalysis::Analyze() {
|
| EliminateRedundantBoundsChecks();
|
| MarkUnreachableBlocks();
|
|
|
| + NarrowMintToInt32();
|
| +
|
| IntegerInstructionSelector iis(flow_graph_);
|
| iis.Select();
|
|
|
| @@ -47,6 +49,8 @@ void RangeAnalysis::CollectValues() {
|
| values_.Add(current);
|
| } else if (current->IsMintDefinition()) {
|
| values_.Add(current);
|
| + } else if (current->IsInt32Definition()) {
|
| + values_.Add(current);
|
| }
|
| }
|
|
|
| @@ -66,6 +70,8 @@ void RangeAnalysis::CollectValues() {
|
| values_.Add(current);
|
| } else if (current->IsMintDefinition()) {
|
| values_.Add(current);
|
| + } else if (current->IsInt32Definition()) {
|
| + values_.Add(current);
|
| }
|
| }
|
| }
|
| @@ -76,6 +82,8 @@ void RangeAnalysis::CollectValues() {
|
| PhiInstr* current = phi_it.Current();
|
| if (current->Type()->ToCid() == kSmiCid) {
|
| values_.Add(current);
|
| + } else if (current->representation() == kUnboxedInt32) {
|
| + values_.Add(current);
|
| }
|
| }
|
| }
|
| @@ -92,6 +100,13 @@ void RangeAnalysis::CollectValues() {
|
| } else if ((defn->IsMintDefinition()) &&
|
| (defn->ssa_temp_index() != -1)) {
|
| values_.Add(defn);
|
| + if (defn->IsBinaryMintOp()) {
|
| + binary_mint_ops_.Add(defn->AsBinaryMintOp());
|
| + } else if (defn->IsShiftMintOp()) {
|
| + shift_mint_ops_.Add(defn->AsShiftMintOp());
|
| + }
|
| + } else if (defn->IsInt32Definition()) {
|
| + values_.Add(defn);
|
| }
|
| } else if (current->IsCheckArrayBound()) {
|
| bounds_checks_.Add(current->AsCheckArrayBound());
|
| @@ -370,49 +385,55 @@ static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) {
|
| // Given the current range of a phi and a newly computed range check
|
| // if it is growing towards negative infinity, if it does widen it to
|
| // MinSmi.
|
| -static RangeBoundary WidenMin(const Range* range, const Range* new_range) {
|
| +static RangeBoundary WidenMin(const Range* range,
|
| + const Range* new_range,
|
| + RangeBoundary::RangeSize size) {
|
| RangeBoundary min = range->min();
|
| RangeBoundary new_min = new_range->min();
|
|
|
| if (min.IsSymbol()) {
|
| - if (min.LowerBound().OverflowedSmi()) {
|
| - return RangeBoundary::MinSmi();
|
| + if (min.LowerBound().Overflowed(size)) {
|
| + return RangeBoundary::MinConstant(size);
|
| } else if (DependOnSameSymbol(min, new_min)) {
|
| - return min.offset() <= new_min.offset() ? min : RangeBoundary::MinSmi();
|
| - } else if (min.SmiUpperBound() <= new_min.SmiLowerBound()) {
|
| + return min.offset() <= new_min.offset() ?
|
| + min : RangeBoundary::MinConstant(size);
|
| + } else if (min.UpperBound(size) <= new_min.LowerBound(size)) {
|
| return min;
|
| }
|
| }
|
|
|
| - min = Range::ConstantMinSmi(range);
|
| - new_min = Range::ConstantMinSmi(new_range);
|
| + min = Range::ConstantMin(range, size);
|
| + new_min = Range::ConstantMin(new_range, size);
|
|
|
| return (min.ConstantValue() <= new_min.ConstantValue()) ?
|
| - min : RangeBoundary::MinSmi();
|
| + min : RangeBoundary::MinConstant(size);
|
| }
|
|
|
| // Given the current range of a phi and a newly computed range check
|
| // if it is growing towards positive infinity, if it does widen it to
|
| // MaxSmi.
|
| -static RangeBoundary WidenMax(const Range* range, const Range* new_range) {
|
| +static RangeBoundary WidenMax(const Range* range,
|
| + const Range* new_range,
|
| + RangeBoundary::RangeSize size) {
|
| RangeBoundary max = range->max();
|
| RangeBoundary new_max = new_range->max();
|
|
|
| if (max.IsSymbol()) {
|
| - if (max.UpperBound().OverflowedSmi()) {
|
| - return RangeBoundary::MaxSmi();
|
| + if (max.UpperBound().Overflowed(size)) {
|
| + return RangeBoundary::MaxConstant(size);
|
| } else if (DependOnSameSymbol(max, new_max)) {
|
| - return max.offset() >= new_max.offset() ? max : RangeBoundary::MaxSmi();
|
| - } else if (max.SmiLowerBound() >= new_max.SmiUpperBound()) {
|
| + return max.offset() >= new_max.offset() ?
|
| + max : RangeBoundary::MaxConstant(size);
|
| + } else if (max.LowerBound(size) >= new_max.UpperBound(size)) {
|
| return max;
|
| }
|
| }
|
|
|
| - max = Range::ConstantMaxSmi(range);
|
| - new_max = Range::ConstantMaxSmi(new_range);
|
| + max = Range::ConstantMax(range, size);
|
| + new_max = Range::ConstantMax(new_range, size);
|
|
|
| return (max.ConstantValue() >= new_max.ConstantValue()) ?
|
| - max : RangeBoundary::MaxSmi();
|
| + max : RangeBoundary::MaxConstant(size);
|
| }
|
|
|
|
|
| @@ -422,14 +443,16 @@ static RangeBoundary WidenMax(const Range* range, const Range* new_range) {
|
| // equal to MinSmi.
|
| // Newly computed minimum is expected to be greater of equal then old one as
|
| // we are running after widening phase.
|
| -static RangeBoundary NarrowMin(const Range* range, const Range* new_range) {
|
| +static RangeBoundary NarrowMin(const Range* range,
|
| + const Range* new_range,
|
| + RangeBoundary::RangeSize size) {
|
| #ifdef DEBUG
|
| - const RangeBoundary min = Range::ConstantMinSmi(range);
|
| - const RangeBoundary new_min = Range::ConstantMinSmi(new_range);
|
| + const RangeBoundary min = Range::ConstantMin(range, size);
|
| + const RangeBoundary new_min = Range::ConstantMin(new_range, size);
|
| ASSERT(min.ConstantValue() <= new_min.ConstantValue());
|
| #endif
|
| // TODO(vegorov): consider using negative infinity to indicate widened bound.
|
| - return range->min().IsSmiMinimumOrBelow() ? new_range->min() : range->min();
|
| + return range->min().IsMinimumOrBelow(size) ? new_range->min() : range->min();
|
| }
|
|
|
|
|
| @@ -439,14 +462,16 @@ static RangeBoundary NarrowMin(const Range* range, const Range* new_range) {
|
| // equal to MaxSmi.
|
| // Newly computed minimum is expected to be greater of equal then old one as
|
| // we are running after widening phase.
|
| -static RangeBoundary NarrowMax(const Range* range, const Range* new_range) {
|
| +static RangeBoundary NarrowMax(const Range* range,
|
| + const Range* new_range,
|
| + RangeBoundary::RangeSize size) {
|
| #ifdef DEBUG
|
| - const RangeBoundary max = Range::ConstantMaxSmi(range);
|
| - const RangeBoundary new_max = Range::ConstantMaxSmi(new_range);
|
| + const RangeBoundary max = Range::ConstantMax(range, size);
|
| + const RangeBoundary new_max = Range::ConstantMax(new_range, size);
|
| ASSERT(max.ConstantValue() >= new_max.ConstantValue());
|
| #endif
|
| // TODO(vegorov): consider using positive infinity to indicate widened bound.
|
| - return range->max().IsSmiMaximumOrAbove() ? new_range->max() : range->max();
|
| + return range->max().IsMaximumOrAbove(size) ? new_range->max() : range->max();
|
| }
|
|
|
|
|
| @@ -469,14 +494,17 @@ bool RangeAnalysis::InferRange(JoinOperator op,
|
|
|
| if (!Range::IsUnknown(&range)) {
|
| if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) {
|
| - // TODO(vegorov): we are currently supporting only smi phis.
|
| - ASSERT(defn->Type()->ToCid() == kSmiCid);
|
| + // TODO(vegorov): we are currently supporting only smi/int32 phis.
|
| + ASSERT((defn->Type()->ToCid() == kSmiCid) ||
|
| + (defn->representation() == kUnboxedInt32));
|
| + const RangeBoundary::RangeSize size = (defn->Type()->ToCid() == kSmiCid) ?
|
| + RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32;
|
| if (op == WIDEN) {
|
| - range = Range(WidenMin(defn->range(), &range),
|
| - WidenMax(defn->range(), &range));
|
| + range = Range(WidenMin(defn->range(), &range, size),
|
| + WidenMax(defn->range(), &range, size));
|
| } else if (op == NARROW) {
|
| - range = Range(NarrowMin(defn->range(), &range),
|
| - NarrowMax(defn->range(), &range));
|
| + range = Range(NarrowMin(defn->range(), &range, size),
|
| + NarrowMax(defn->range(), &range, size));
|
| }
|
| }
|
|
|
| @@ -658,6 +686,59 @@ void RangeAnalysis::RemoveConstraints() {
|
| }
|
|
|
|
|
| +static void NarrowBinaryMintOp(BinaryMintOpInstr* mint_op) {
|
| + if (Range::Fits(mint_op->range(), RangeBoundary::kRangeBoundaryInt32) &&
|
| + Range::Fits(mint_op->left()->definition()->range(),
|
| + RangeBoundary::kRangeBoundaryInt32) &&
|
| + Range::Fits(mint_op->right()->definition()->range(),
|
| + RangeBoundary::kRangeBoundaryInt32) &&
|
| + BinaryInt32OpInstr::IsSupported(mint_op->op_kind(),
|
| + mint_op->left(),
|
| + mint_op->right())) {
|
| + BinaryInt32OpInstr* int32_op =
|
| + new BinaryInt32OpInstr(mint_op->op_kind(),
|
| + mint_op->left()->CopyWithType(),
|
| + mint_op->right()->CopyWithType(),
|
| + mint_op->DeoptimizationTarget());
|
| + int32_op->set_range(*mint_op->range());
|
| + int32_op->set_overflow(false);
|
| + mint_op->ReplaceWith(int32_op, NULL);
|
| + }
|
| +}
|
| +
|
| +
|
| +static void NarrowShiftMintOp(ShiftMintOpInstr* mint_op) {
|
| + if (Range::Fits(mint_op->range(), RangeBoundary::kRangeBoundaryInt32) &&
|
| + Range::Fits(mint_op->left()->definition()->range(),
|
| + RangeBoundary::kRangeBoundaryInt32) &&
|
| + Range::Fits(mint_op->right()->definition()->range(),
|
| + RangeBoundary::kRangeBoundaryInt32) &&
|
| + BinaryInt32OpInstr::IsSupported(mint_op->op_kind(),
|
| + mint_op->left(),
|
| + mint_op->right())) {
|
| + BinaryInt32OpInstr* int32_op =
|
| + new BinaryInt32OpInstr(mint_op->op_kind(),
|
| + mint_op->left()->CopyWithType(),
|
| + mint_op->right()->CopyWithType(),
|
| + mint_op->DeoptimizationTarget());
|
| + int32_op->set_range(*mint_op->range());
|
| + int32_op->set_overflow(false);
|
| + mint_op->ReplaceWith(int32_op, NULL);
|
| + }
|
| +}
|
| +
|
| +
|
| +void RangeAnalysis::NarrowMintToInt32() {
|
| + for (intptr_t i = 0; i < binary_mint_ops_.length(); i++) {
|
| + NarrowBinaryMintOp(binary_mint_ops_[i]);
|
| + }
|
| +
|
| + for (intptr_t i = 0; i < shift_mint_ops_.length(); i++) {
|
| + NarrowShiftMintOp(shift_mint_ops_[i]);
|
| + }
|
| +}
|
| +
|
| +
|
| IntegerInstructionSelector::IntegerInstructionSelector(FlowGraph* flow_graph)
|
| : flow_graph_(flow_graph),
|
| isolate_(NULL) {
|
| @@ -904,6 +985,9 @@ void IntegerInstructionSelector::ReplaceInstructions() {
|
| OS::Print("Replacing %s with %s\n", defn->ToCString(),
|
| replacement->ToCString());
|
| }
|
| + if (!Range::IsUnknown(defn->range())) {
|
| + replacement->set_range(*defn->range());
|
| + }
|
| defn->ReplaceWith(replacement, NULL);
|
| ASSERT(flow_graph_->VerifyUseLists());
|
| }
|
| @@ -1177,7 +1261,9 @@ static bool CanonicalizeForComparison(RangeBoundary* a,
|
| }
|
|
|
|
|
| -RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) {
|
| +RangeBoundary RangeBoundary::JoinMin(RangeBoundary a,
|
| + RangeBoundary b,
|
| + RangeBoundary::RangeSize size) {
|
| if (a.Equals(b)) {
|
| return b;
|
| }
|
| @@ -1189,14 +1275,14 @@ RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) {
|
| return (a.offset() <= b.offset()) ? a : b;
|
| }
|
|
|
| - const int64_t inf_a = a.SmiLowerBound();
|
| - const int64_t inf_b = b.SmiLowerBound();
|
| - const int64_t sup_a = a.SmiUpperBound();
|
| - const int64_t sup_b = b.SmiUpperBound();
|
| + const int64_t inf_a = a.LowerBound(size);
|
| + const int64_t inf_b = b.LowerBound(size);
|
| + const int64_t sup_a = a.UpperBound(size);
|
| + const int64_t sup_b = b.UpperBound(size);
|
|
|
| - if ((sup_a <= inf_b) && !a.LowerBound().OverflowedSmi()) {
|
| + if ((sup_a <= inf_b) && !a.LowerBound().Overflowed(size)) {
|
| return a;
|
| - } else if ((sup_b <= inf_a) && !b.LowerBound().OverflowedSmi()) {
|
| + } else if ((sup_b <= inf_a) && !b.LowerBound().Overflowed(size)) {
|
| return b;
|
| } else {
|
| return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b));
|
| @@ -1204,7 +1290,9 @@ RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b) {
|
| }
|
|
|
|
|
| -RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b) {
|
| +RangeBoundary RangeBoundary::JoinMax(RangeBoundary a,
|
| + RangeBoundary b,
|
| + RangeBoundary::RangeSize size) {
|
| if (a.Equals(b)) {
|
| return b;
|
| }
|
| @@ -1216,14 +1304,14 @@ RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b) {
|
| return (a.offset() >= b.offset()) ? a : b;
|
| }
|
|
|
| - const int64_t inf_a = a.SmiLowerBound();
|
| - const int64_t inf_b = b.SmiLowerBound();
|
| - const int64_t sup_a = a.SmiUpperBound();
|
| - const int64_t sup_b = b.SmiUpperBound();
|
| + const int64_t inf_a = a.LowerBound(size);
|
| + const int64_t inf_b = b.LowerBound(size);
|
| + const int64_t sup_a = a.UpperBound(size);
|
| + const int64_t sup_b = b.UpperBound(size);
|
|
|
| - if ((sup_a <= inf_b) && !b.UpperBound().OverflowedSmi()) {
|
| + if ((sup_a <= inf_b) && !b.UpperBound().Overflowed(size)) {
|
| return b;
|
| - } else if ((sup_b <= inf_a) && !a.UpperBound().OverflowedSmi()) {
|
| + } else if ((sup_b <= inf_a) && !a.UpperBound().Overflowed(size)) {
|
| return a;
|
| } else {
|
| return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b));
|
| @@ -1239,9 +1327,9 @@ RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) {
|
| return a;
|
| }
|
|
|
| - if (a.IsSmiMinimumOrBelow()) {
|
| + if (a.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) {
|
| return b;
|
| - } else if (b.IsSmiMinimumOrBelow()) {
|
| + } else if (b.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) {
|
| return a;
|
| }
|
|
|
| @@ -1267,9 +1355,9 @@ RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) {
|
| return a;
|
| }
|
|
|
| - if (a.IsSmiMaximumOrAbove()) {
|
| + if (a.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) {
|
| return b;
|
| - } else if (b.IsSmiMaximumOrAbove()) {
|
| + } else if (b.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) {
|
| return a;
|
| }
|
|
|
| @@ -1550,15 +1638,13 @@ bool Range::Mul(const Range* left_range,
|
| ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) {
|
| // Product of left and right max values stays in 64 bit range.
|
| const int64_t mul_max = left_max * right_max;
|
| - if (Smi::IsValid(mul_max) && Smi::IsValid(-mul_max)) {
|
| - const int64_t r_min =
|
| - OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max;
|
| - *result_min = RangeBoundary::FromConstant(r_min);
|
| - const int64_t r_max =
|
| - OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max;
|
| - *result_max = RangeBoundary::FromConstant(r_max);
|
| - return true;
|
| - }
|
| + const int64_t r_min =
|
| + OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max;
|
| + *result_min = RangeBoundary::FromConstant(r_min);
|
| + const int64_t r_max =
|
| + OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max;
|
| + *result_max = RangeBoundary::FromConstant(r_max);
|
| + return true;
|
| }
|
|
|
| // TODO(vegorov): handle mixed sign case that leads to (-Infinity, 0] range.
|
| @@ -1664,6 +1750,8 @@ void Definition::InferRange(RangeAnalysis* analysis, Range* range) {
|
| *range = Range::Full(RangeBoundary::kRangeBoundarySmi);
|
| } else if (IsMintDefinition()) {
|
| *range = Range::Full(RangeBoundary::kRangeBoundaryInt64);
|
| + } else if (IsInt32Definition()) {
|
| + *range = Range::Full(RangeBoundary::kRangeBoundaryInt32);
|
| } else {
|
| // Only Smi and Mint supported.
|
| UNREACHABLE();
|
| @@ -1683,7 +1771,10 @@ static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) {
|
| //
|
| // [_|_, _|_] U a = a U [_|_, _|_] = a
|
| //
|
| -static void Join(Range* range, Definition* defn, const Range* defn_range) {
|
| +static void Join(Range* range,
|
| + Definition* defn,
|
| + const Range* defn_range,
|
| + RangeBoundary::RangeSize size) {
|
| if (Range::IsUnknown(defn_range)) {
|
| return;
|
| }
|
| @@ -1710,10 +1801,10 @@ static void Join(Range* range, Definition* defn, const Range* defn_range) {
|
| }
|
|
|
| // First try to compare ranges based on their upper and lower bounds.
|
| - const int64_t inf_range = range->min().SmiLowerBound();
|
| - const int64_t inf_other = other.min().SmiLowerBound();
|
| - const int64_t sup_range = range->max().SmiUpperBound();
|
| - const int64_t sup_other = other.max().SmiUpperBound();
|
| + const int64_t inf_range = range->min().LowerBound(size);
|
| + const int64_t inf_other = other.min().LowerBound(size);
|
| + const int64_t sup_range = range->max().UpperBound(size);
|
| + const int64_t sup_other = other.max().UpperBound(size);
|
|
|
| if (sup_range <= inf_other) {
|
| // The range is fully below defn's range. Keep the minimum and
|
| @@ -1725,8 +1816,8 @@ static void Join(Range* range, Definition* defn, const Range* defn_range) {
|
| range->set_min(other.min());
|
| } else {
|
| // Can't compare ranges as whole. Join minimum and maximum separately.
|
| - *range = Range(RangeBoundary::JoinMin(range->min(), other.min()),
|
| - RangeBoundary::JoinMax(range->max(), other.max()));
|
| + *range = Range(RangeBoundary::JoinMin(range->min(), other.min(), size),
|
| + RangeBoundary::JoinMax(range->max(), other.max(), size));
|
| }
|
| }
|
|
|
| @@ -1755,10 +1846,15 @@ static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block,
|
|
|
|
|
| void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| - ASSERT(Type()->ToCid() == kSmiCid);
|
| + ASSERT((Type()->ToCid() == kSmiCid) || (representation() == kUnboxedInt32));
|
| + const RangeBoundary::RangeSize size = (Type()->ToCid() == kSmiCid) ?
|
| + RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32;
|
| for (intptr_t i = 0; i < InputCount(); i++) {
|
| Value* input = InputAt(i);
|
| - Join(range, input->definition(), analysis->GetSmiRange(input));
|
| + const Range* input_range = (size == RangeBoundary::kRangeBoundarySmi) ?
|
| + analysis->GetSmiRange(input) : input->definition()->range();
|
| + Join(range,
|
| + input->definition(), input_range, size);
|
| }
|
|
|
| BlockEntryInstr* phi_block = GetBlock();
|
| @@ -1919,6 +2015,87 @@ void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| }
|
|
|
|
|
| +void BoxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| + const Range* value_range = value()->definition()->range();
|
| + if (!Range::IsUnknown(value_range)) {
|
| + *range = *value_range;
|
| + }
|
| +}
|
| +
|
| +
|
| +void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| + if (value()->definition()->Type()->ToCid() == kSmiCid) {
|
| + const Range* value_range = analysis->GetSmiRange(value());
|
| + if (!Range::IsUnknown(value_range)) {
|
| + *range = *value_range;
|
| + }
|
| + } else if (value()->definition()->IsMintDefinition() ||
|
| + value()->definition()->IsInt32Definition()) {
|
| + const Range* value_range = value()->definition()->range();
|
| + if (!Range::IsUnknown(value_range)) {
|
| + *range = *value_range;
|
| + }
|
| + } else if (value()->Type()->ToCid() == kSmiCid) {
|
| + *range = Range::Full(RangeBoundary::kRangeBoundarySmi);
|
| + } else {
|
| + *range = Range::Full(RangeBoundary::kRangeBoundaryInt32);
|
| + }
|
| +}
|
| +
|
| +
|
| +void UnboxedIntConverterInstr::InferRange(RangeAnalysis* analysis,
|
| + Range* range) {
|
| + ASSERT((from() == kUnboxedInt32) ||
|
| + (from() == kUnboxedMint) ||
|
| + (from() == kUnboxedUint32));
|
| + ASSERT((to() == kUnboxedInt32) ||
|
| + (to() == kUnboxedMint) ||
|
| + (to() == kUnboxedUint32));
|
| + const Range* value_range = value()->definition()->range();
|
| + if (Range::IsUnknown(value_range)) {
|
| + return;
|
| + }
|
| +
|
| + if (to() == kUnboxedUint32) {
|
| + // TODO(vegorov): improve range information for unboxing to Uint32.
|
| + *range = Range(
|
| + RangeBoundary::FromConstant(0),
|
| + RangeBoundary::FromConstant(static_cast<int64_t>(kMaxUint32)));
|
| + } else {
|
| + *range = *value_range;
|
| + if (to() == kUnboxedInt32) {
|
| + range->Clamp(RangeBoundary::kRangeBoundaryInt32);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void BinaryInt32OpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| + // TODO(vegorov): canonicalize BinarySmiOp to always have constant on the
|
| + // right and a non-constant on the left.
|
| + Definition* left_defn = left()->definition();
|
| +
|
| + const Range* left_range = analysis->GetSmiRange(left());
|
| + const Range* right_range = analysis->GetSmiRange(right());
|
| +
|
| + if (Range::IsUnknown(left_range) || Range::IsUnknown(right_range)) {
|
| + return;
|
| + }
|
| +
|
| + Range::BinaryOp(op_kind(),
|
| + left_range,
|
| + right_range,
|
| + left_defn,
|
| + range);
|
| + ASSERT(!Range::IsUnknown(range));
|
| +
|
| + // Calculate overflowed status before clamping.
|
| + set_overflow(!range->Fits(RangeBoundary::kRangeBoundaryInt32));
|
| +
|
| + // Clamp value to be within smi range.
|
| + range->Clamp(RangeBoundary::kRangeBoundaryInt32);
|
| +}
|
| +
|
| void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| // TODO(vegorov): canonicalize BinaryMintOpInstr to always have constant on
|
| // the right and a non-constant on the left.
|
| @@ -1939,9 +2116,7 @@ void BinaryMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| ASSERT(!Range::IsUnknown(range));
|
|
|
| // Calculate overflowed status before clamping.
|
| - const bool overflowed = range->min().LowerBound().OverflowedMint() ||
|
| - range->max().UpperBound().OverflowedMint();
|
| - set_can_overflow(overflowed);
|
| + set_can_overflow(!range->Fits(RangeBoundary::kRangeBoundaryInt64));
|
|
|
| // Clamp value to be within mint range.
|
| range->Clamp(RangeBoundary::kRangeBoundaryInt64);
|
| @@ -1978,8 +2153,7 @@ void ShiftMintOpInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) {
|
| const Range* input_range = value()->definition()->range();
|
| if (input_range != NULL) {
|
| - bool is_smi = !input_range->min().LowerBound().OverflowedSmi() &&
|
| - !input_range->max().UpperBound().OverflowedSmi();
|
| + bool is_smi = input_range->Fits(RangeBoundary::kRangeBoundarySmi);
|
| set_is_smi(is_smi);
|
| // The output range is the same as the input range.
|
| *range = *input_range;
|
|
|