diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc index 5a54b99b724..aec05b5cd91 100644 --- a/runtime/vm/compiler/backend/flow_graph.cc +++ b/runtime/vm/compiler/backend/flow_graph.cc @@ -2177,10 +2177,9 @@ class PhiUnboxingHeuristic : public ValueObject { // If all the inputs are unboxed integers but with different // representations, then pick a representation based on the range // of values that flow into the phi node. - new_representation = - RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32) - ? kUnboxedInt32 - : kUnboxedInt64; + new_representation = Range::Fits(phi->range(), kUnboxedInt32) + ? kUnboxedInt32 + : kUnboxedInt64; } // Decide if it is worth to unbox an boxed integer phi. @@ -2202,10 +2201,9 @@ class PhiUnboxingHeuristic : public ValueObject { const bool flows_into_unboxed_use = FlowsIntoUnboxedUse(phi); if (has_unboxed_incoming_value && flows_into_unboxed_use) { - new_representation = - RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32) - ? kUnboxedInt32 - : kUnboxedInt64; + new_representation = Range::Fits(phi->range(), kUnboxedInt32) + ? kUnboxedInt32 + : kUnboxedInt64; } #endif } diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index e317be49236..44f5ff50ef6 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -3182,7 +3182,8 @@ Definition* UnboxLaneInstr::Canonicalize(FlowGraph* flow_graph) { bool BoxIntegerInstr::ValueFitsSmi() const { Range* range = value()->definition()->range(); - return RangeUtils::Fits(range, RangeBoundary::kRangeBoundarySmi); + return RangeUtils::IsWithin(range, compiler::target::kSmiMin, + compiler::target::kSmiMax); } Definition* BoxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc index a1b4a869247..3fc160a2924 100644 --- a/runtime/vm/compiler/backend/range_analysis.cc +++ b/runtime/vm/compiler/backend/range_analysis.cc @@ -59,27 +59,6 @@ static void CheckRangeForRepresentation(const Assert& assert, } while (false) #endif -static RangeBoundary::RangeSize RepresentationToRangeSize(Representation r) { - switch (r) { - case kTagged: - return RangeBoundary::kRangeBoundarySmi; - case kUnboxedInt8: - return RangeBoundary::kRangeBoundaryInt8; - case kUnboxedInt16: - case kUnboxedUint8: // Overapproximate Uint8 as Int16. - return RangeBoundary::kRangeBoundaryInt16; - case kUnboxedInt32: - case kUnboxedUint16: // Overapproximate Uint16 as Int32. - return RangeBoundary::kRangeBoundaryInt32; - case kUnboxedInt64: - case kUnboxedUint32: // Overapproximate Uint32 as Int64. - return RangeBoundary::kRangeBoundaryInt64; - default: - UNREACHABLE(); - return RangeBoundary::kRangeBoundarySmi; - } -} - void RangeAnalysis::Analyze() { CollectValues(); InsertConstraints(); @@ -181,25 +160,25 @@ void RangeAnalysis::CollectValues() { // [min, b - 1]. Range* RangeAnalysis::ConstraintRange(Token::Kind op, Definition* boundary, - RangeBoundary::RangeSize size) { + const Range& full_range) { switch (op) { case Token::kEQ: return new (Z) Range(RangeBoundary::FromDefinition(boundary), RangeBoundary::FromDefinition(boundary)); case Token::kNE: - return new (Z) Range(Range::Full(size)); + return new (Z) Range(full_range); case Token::kLT: - return new (Z) Range(RangeBoundary::MinConstant(size), - RangeBoundary::FromDefinition(boundary, -1)); + return new (Z) + Range(full_range.min(), RangeBoundary::FromDefinition(boundary, -1)); case Token::kGT: - return new (Z) Range(RangeBoundary::FromDefinition(boundary, 1), - RangeBoundary::MaxConstant(size)); + return new (Z) + Range(RangeBoundary::FromDefinition(boundary, 1), full_range.max()); case Token::kLTE: - return new (Z) Range(RangeBoundary::MinConstant(size), - RangeBoundary::FromDefinition(boundary)); + return new (Z) + Range(full_range.min(), RangeBoundary::FromDefinition(boundary)); case Token::kGTE: - return new (Z) Range(RangeBoundary::FromDefinition(boundary), - RangeBoundary::MaxConstant(size)); + return new (Z) + Range(RangeBoundary::FromDefinition(boundary), full_range.max()); default: UNREACHABLE(); return nullptr; @@ -251,23 +230,23 @@ bool RangeAnalysis::ConstrainValueAfterBranch(Value* use, Definition* defn) { // comparison if it is right operand flip the comparison. op_kind = Token::FlipComparison(rel_op->kind()); } - RangeBoundary::RangeSize size; - if (rel_op->input_representation() == kTagged) { - size = RangeBoundary::kRangeBoundarySmi; + const Representation representation = rel_op->input_representation(); + Range full_range; + if (representation == kTagged) { + full_range = Range::Smi(); } else { - ASSERT(RepresentationUtils::IsUnboxedInteger( - rel_op->input_representation())); + ASSERT(RepresentationUtils::IsUnboxedInteger(representation)); // Can only create symbolic boundaries based on Smi values. if (!Definition::IsLengthLoad(boundary)) { return false; } - size = RepresentationToRangeSize(rel_op->input_representation()); + full_range = Range::Full(representation); } // Constrain definition at the true successor. - ConstraintInstr* true_constraint = - InsertConstraintFor(use, defn, ConstraintRange(op_kind, boundary, size), - branch->true_successor()); + ConstraintInstr* true_constraint = InsertConstraintFor( + use, defn, ConstraintRange(op_kind, boundary, full_range), + branch->true_successor()); if (true_constraint != nullptr) { true_constraint->set_target(branch->true_successor()); } @@ -275,7 +254,7 @@ bool RangeAnalysis::ConstrainValueAfterBranch(Value* use, Definition* defn) { // Constrain definition with a negated condition at the false successor. ConstraintInstr* false_constraint = InsertConstraintFor( use, defn, - ConstraintRange(Token::NegateComparison(op_kind), boundary, size), + ConstraintRange(Token::NegateComparison(op_kind), boundary, full_range), branch->false_successor()); if (false_constraint != nullptr) { false_constraint->set_target(branch->false_successor()); @@ -332,44 +311,6 @@ void RangeAnalysis::InsertConstraints() { } } -const Range* RangeAnalysis::GetSmiRange(Value* value) const { - Definition* defn = value->definition(); - const Range* range = defn->range(); - - if ((range == nullptr) && (defn->Type()->ToCid() != kSmiCid)) { - // Type propagator determined that reaching type for this use is Smi. - // However the definition itself is not a smi-definition and - // thus it will never have range assigned to it. Just return the widest - // range possible for this value. - // We don't need to handle kMintCid here because all external mints - // (e.g. results of loads or function call) can be used only after they - // pass through UnboxInt64Instr which is considered as mint-definition - // and will have a range assigned to it. - // Note: that we can't return nullptr here because it is used as lattice's - // bottom element to indicate that the range was not computed *yet*. - return &smi_range_; - } - - return range; -} - -const Range* RangeAnalysis::GetIntRange(Value* value) const { - Definition* defn = value->definition(); - const Range* range = defn->range(); - - if ((range == nullptr) && !defn->Type()->IsInt()) { - // Type propagator determined that reaching type for this use is int. - // However the definition itself is not a int-definition and - // thus it will never have range assigned to it. Just return the widest - // range possible for this value. - // Note: that we can't return nullptr here because it is used as lattice's - // bottom element to indicate that the range was not computed *yet*. - return &int64_range_; - } - - return range; -} - static bool AreEqualDefinitions(Definition* a, Definition* b) { a = UnwrapConstraint(a); b = UnwrapConstraint(b); @@ -386,28 +327,25 @@ static bool DependOnSameSymbol(const RangeBoundary& a, const RangeBoundary& b) { // MinSmi. static RangeBoundary WidenMin(const Range* range, const Range* new_range, - RangeBoundary::RangeSize size) { + const Range& full_range) { RangeBoundary min = range->min(); RangeBoundary new_min = new_range->min(); if (min.IsSymbol()) { - if (min.LowerBound().Overflowed(size)) { - return RangeBoundary::MinConstant(size); + if (min.LowerBound().Overflowed(full_range)) { + return full_range.min(); } else if (DependOnSameSymbol(min, new_min)) { - return min.offset() <= new_min.offset() - ? min - : RangeBoundary::MinConstant(size); - } else if (min.UpperBound(size) <= new_min.LowerBound(size)) { + return min.offset() <= new_min.offset() ? min : full_range.min(); + } else if (min.UpperBound(full_range) <= new_min.LowerBound(full_range)) { return min; } } - min = Range::ConstantMin(range, size); - new_min = Range::ConstantMin(new_range, size); + min = Range::ConstantMin(range, full_range); + new_min = Range::ConstantMin(new_range, full_range); - return (min.ConstantValue() <= new_min.ConstantValue()) - ? min - : RangeBoundary::MinConstant(size); + return (min.ConstantValue() <= new_min.ConstantValue()) ? min + : full_range.min(); } // Given the current range of a phi and a newly computed range check @@ -415,28 +353,25 @@ static RangeBoundary WidenMin(const Range* range, // MaxSmi. static RangeBoundary WidenMax(const Range* range, const Range* new_range, - RangeBoundary::RangeSize size) { + const Range& full_range) { RangeBoundary max = range->max(); RangeBoundary new_max = new_range->max(); if (max.IsSymbol()) { - if (max.UpperBound().Overflowed(size)) { - return RangeBoundary::MaxConstant(size); + if (max.UpperBound().Overflowed(full_range)) { + return full_range.max(); } else if (DependOnSameSymbol(max, new_max)) { - return max.offset() >= new_max.offset() - ? max - : RangeBoundary::MaxConstant(size); - } else if (max.LowerBound(size) >= new_max.UpperBound(size)) { + return max.offset() >= new_max.offset() ? max : full_range.max(); + } else if (max.LowerBound(full_range) >= new_max.UpperBound(full_range)) { return max; } } - max = Range::ConstantMax(range, size); - new_max = Range::ConstantMax(new_range, size); + max = Range::ConstantMax(range, full_range); + new_max = Range::ConstantMax(new_range, full_range); - return (max.ConstantValue() >= new_max.ConstantValue()) - ? max - : RangeBoundary::MaxConstant(size); + return (max.ConstantValue() >= new_max.ConstantValue()) ? max + : full_range.max(); } // Given the current range of a phi and a newly computed range check @@ -447,13 +382,14 @@ static RangeBoundary WidenMax(const Range* range, // we are running after widening phase. static RangeBoundary NarrowMin(const Range* range, const Range* new_range, - RangeBoundary::RangeSize size) { - const RangeBoundary min = Range::ConstantMin(range, size); - const RangeBoundary new_min = Range::ConstantMin(new_range, size); + const Range& full_range) { + const RangeBoundary min = Range::ConstantMin(range, full_range); + const RangeBoundary new_min = Range::ConstantMin(new_range, full_range); if (min.ConstantValue() > new_min.ConstantValue()) return range->min(); // TODO(vegorov): consider using negative infinity to indicate widened bound. - return range->min().IsMinimumOrBelow(size) ? new_range->min() : range->min(); + return range->min().IsLessOrEqual(full_range.min()) ? new_range->min() + : range->min(); } // Given the current range of a phi and a newly computed range check @@ -464,13 +400,14 @@ static RangeBoundary NarrowMin(const Range* range, // we are running after widening phase. static RangeBoundary NarrowMax(const Range* range, const Range* new_range, - RangeBoundary::RangeSize size) { - const RangeBoundary max = Range::ConstantMax(range, size); - const RangeBoundary new_max = Range::ConstantMax(new_range, size); + const Range& full_range) { + const RangeBoundary max = Range::ConstantMax(range, full_range); + const RangeBoundary new_max = Range::ConstantMax(new_range, full_range); if (max.ConstantValue() < new_max.ConstantValue()) return range->max(); // TODO(vegorov): consider using positive infinity to indicate widened bound. - return range->max().IsMaximumOrAbove(size) ? new_range->max() : range->max(); + return range->max().IsGreaterOrEqual(full_range.max()) ? new_range->max() + : range->max(); } char RangeAnalysis::OpPrefix(JoinOperator op) { @@ -486,17 +423,20 @@ char RangeAnalysis::OpPrefix(JoinOperator op) { return ' '; } -static RangeBoundary::RangeSize RangeSizeForPhi(Definition* phi) { +static Range FullRangeForPhi(Definition* phi) { ASSERT(phi->IsPhi()); if (phi->Type()->ToCid() == kSmiCid) { - return RangeBoundary::kRangeBoundarySmi; - } else if (phi->representation() == kUnboxedInt32) { - return RangeBoundary::kRangeBoundaryInt32; - } else if (phi->Type()->IsInt()) { - return RangeBoundary::kRangeBoundaryInt64; + return Range::Smi(); + } + const Representation rep = phi->representation(); + if (RepresentationUtils::IsUnboxedInteger(rep)) { + return Range::Full(rep); + } + ASSERT(rep == kTagged); + if (phi->Type()->IsInt()) { + return Range::Int64(); } else { UNREACHABLE(); - return RangeBoundary::kRangeBoundaryInt64; } } @@ -508,13 +448,13 @@ bool RangeAnalysis::InferRange(JoinOperator op, if (!Range::IsUnknown(&range)) { if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { - const RangeBoundary::RangeSize size = RangeSizeForPhi(defn); + const Range full_range = FullRangeForPhi(defn); if (op == WIDEN) { - range = Range(WidenMin(defn->range(), &range, size), - WidenMax(defn->range(), &range, size)); + range = Range(WidenMin(defn->range(), &range, full_range), + WidenMax(defn->range(), &range, full_range)); } else if (op == NARROW) { - range = Range(NarrowMin(defn->range(), &range, size), - NarrowMax(defn->range(), &range, size)); + range = Range(NarrowMin(defn->range(), &range, full_range), + NarrowMax(defn->range(), &range, full_range)); } } @@ -842,8 +782,7 @@ class BoundsCheckGeneralizer { GrowableArray positive_constraints( non_positive_symbols.length()); Range* positive_range = - new Range(RangeBoundary::FromConstant(0), - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundarySmi)); + new Range(RangeBoundary::FromConstant(0), RangeBoundary::MaxSmi()); for (intptr_t i = 0; i < non_positive_symbols.length(); i++) { Definition* symbol = non_positive_symbols[i]; positive_constraints.Add(new ConstraintInstr( @@ -1451,11 +1390,9 @@ void RangeAnalysis::RemoveConstraints() { } static void NarrowBinaryInt64Op(BinaryInt64OpInstr* int64_op) { - if (RangeUtils::Fits(int64_op->range(), RangeBoundary::kRangeBoundaryInt32) && - RangeUtils::Fits(int64_op->left()->definition()->range(), - RangeBoundary::kRangeBoundaryInt32) && - RangeUtils::Fits(int64_op->right()->definition()->range(), - RangeBoundary::kRangeBoundaryInt32) && + if (Range::Fits(int64_op->range(), kUnboxedInt32) && + Range::Fits(int64_op->left()->definition()->range(), kUnboxedInt32) && + Range::Fits(int64_op->right()->definition()->range(), kUnboxedInt32) && BinaryInt32OpInstr::IsSupported(int64_op->op_kind(), int64_op->left(), int64_op->right())) { BinaryInt32OpInstr* int32_op = new BinaryInt32OpInstr( @@ -1469,10 +1406,8 @@ static void NarrowBinaryInt64Op(BinaryInt64OpInstr* int64_op) { #if defined(TARGET_ARCH_IS_32_BIT) static void NarrowInt64ComparisonInstr(ComparisonInstr* int64_op) { - if (RangeUtils::Fits(int64_op->left()->definition()->range(), - RangeBoundary::kRangeBoundaryInt32) && - RangeUtils::Fits(int64_op->right()->definition()->range(), - RangeBoundary::kRangeBoundaryInt32)) { + if (Range::Fits(int64_op->left()->definition()->range(), kUnboxedInt32) && + Range::Fits(int64_op->right()->definition()->range(), kUnboxedInt32)) { int64_op->set_input_representation(kUnboxedInt32); } } @@ -1985,20 +1920,20 @@ static bool CanonicalizeMaxBoundary(RangeBoundary* a) { if ((range == nullptr) || !range->max().IsSymbol()) return false; if (Utils::WillAddOverflow(range->max().offset(), a->offset())) { - *a = RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *a = RangeBoundary::MaxInt64(); return true; } const int64_t offset = range->max().offset() + a->offset(); if (!RangeBoundary::IsValidOffsetForSymbolicRangeBoundary(offset)) { - *a = RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *a = RangeBoundary::MaxInt64(); return true; } *a = CanonicalizeBoundary( RangeBoundary::FromDefinition(range->max().symbol(), offset), - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64)); + RangeBoundary::MaxInt64()); return true; } @@ -2010,20 +1945,20 @@ static bool CanonicalizeMinBoundary(RangeBoundary* a) { if ((range == nullptr) || !range->min().IsSymbol()) return false; if (Utils::WillAddOverflow(range->min().offset(), a->offset())) { - *a = RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); + *a = RangeBoundary::MinInt64(); return true; } const int64_t offset = range->min().offset() + a->offset(); if (!RangeBoundary::IsValidOffsetForSymbolicRangeBoundary(offset)) { - *a = RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); + *a = RangeBoundary::MinInt64(); return true; } *a = CanonicalizeBoundary( RangeBoundary::FromDefinition(range->min().symbol(), offset), - RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64)); + RangeBoundary::MinInt64()); return true; } @@ -2032,8 +1967,7 @@ typedef bool (*BoundaryOp)(RangeBoundary*); static bool CanonicalizeForComparison(RangeBoundary* a, RangeBoundary* b, - BoundaryOp op, - const RangeBoundary& overflow) { + BoundaryOp op) { if (!a->IsSymbol() || !b->IsSymbol()) { return false; } @@ -2054,24 +1988,23 @@ static bool CanonicalizeForComparison(RangeBoundary* a, RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary b, - RangeBoundary::RangeSize size) { + const Range& full_range) { if (a.Equals(b)) { return b; } - if (CanonicalizeForComparison(&a, &b, &CanonicalizeMinBoundary, - RangeBoundary::MinConstant(size))) { + if (CanonicalizeForComparison(&a, &b, &CanonicalizeMinBoundary)) { return (a.offset() <= b.offset()) ? a : b; } - 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); + const int64_t inf_a = a.LowerBound(full_range); + const int64_t inf_b = b.LowerBound(full_range); + const int64_t sup_a = a.UpperBound(full_range); + const int64_t sup_b = b.UpperBound(full_range); - if ((sup_a <= inf_b) && !a.LowerBound().Overflowed(size)) { + if ((sup_a <= inf_b) && !a.LowerBound().Overflowed(full_range)) { return a; - } else if ((sup_b <= inf_a) && !b.LowerBound().Overflowed(size)) { + } else if ((sup_b <= inf_a) && !b.LowerBound().Overflowed(full_range)) { return b; } else { return RangeBoundary::FromConstant(Utils::Minimum(inf_a, inf_b)); @@ -2080,25 +2013,23 @@ RangeBoundary RangeBoundary::JoinMin(RangeBoundary a, RangeBoundary RangeBoundary::JoinMax(RangeBoundary a, RangeBoundary b, - RangeBoundary::RangeSize size) { + const Range& full_range) { if (a.Equals(b)) { return b; } - if (CanonicalizeForComparison( - &a, &b, &CanonicalizeMaxBoundary, - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64))) { + if (CanonicalizeForComparison(&a, &b, &CanonicalizeMaxBoundary)) { return (a.offset() >= b.offset()) ? a : b; } - 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); + const int64_t inf_a = a.LowerBound(full_range); + const int64_t inf_b = b.LowerBound(full_range); + const int64_t sup_a = a.UpperBound(full_range); + const int64_t sup_b = b.UpperBound(full_range); - if ((sup_a <= inf_b) && !b.UpperBound().Overflowed(size)) { + if ((sup_a <= inf_b) && !b.UpperBound().Overflowed(full_range)) { return b; - } else if ((sup_b <= inf_a) && !a.UpperBound().Overflowed(size)) { + } else if ((sup_b <= inf_a) && !a.UpperBound().Overflowed(full_range)) { return a; } else { return RangeBoundary::FromConstant(Utils::Maximum(sup_a, sup_b)); @@ -2116,20 +2047,12 @@ RangeBoundary RangeBoundary::IntersectionMin(RangeBoundary a, RangeBoundary b) { return RangeBoundary(Utils::Maximum(a.ConstantValue(), b.ConstantValue())); } - if (a.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) { - return b; - } else if (b.IsMinimumOrBelow(RangeBoundary::kRangeBoundarySmi)) { - return a; - } - - if (CanonicalizeForComparison( - &a, &b, &CanonicalizeMinBoundary, - RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64))) { + if (CanonicalizeForComparison(&a, &b, &CanonicalizeMinBoundary)) { return (a.offset() >= b.offset()) ? a : b; } - const int64_t inf_a = a.SmiLowerBound(); - const int64_t inf_b = b.SmiLowerBound(); + const int64_t inf_a = a.LowerBound().ConstantValue(); + const int64_t inf_b = b.LowerBound().ConstantValue(); return (inf_a >= inf_b) ? a : b; } @@ -2145,30 +2068,48 @@ RangeBoundary RangeBoundary::IntersectionMax(RangeBoundary a, RangeBoundary b) { return RangeBoundary(Utils::Minimum(a.ConstantValue(), b.ConstantValue())); } - if (a.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) { - return b; - } else if (b.IsMaximumOrAbove(RangeBoundary::kRangeBoundarySmi)) { - return a; - } - - if (CanonicalizeForComparison( - &a, &b, &CanonicalizeMaxBoundary, - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64))) { + if (CanonicalizeForComparison(&a, &b, &CanonicalizeMaxBoundary)) { return (a.offset() <= b.offset()) ? a : b; } - const int64_t sup_a = a.SmiUpperBound(); - const int64_t sup_b = b.SmiUpperBound(); + const int64_t sup_a = a.UpperBound().ConstantValue(); + const int64_t sup_b = b.UpperBound().ConstantValue(); return (sup_a <= sup_b) ? a : b; } +RangeBoundary RangeBoundary::Clamp(const Range& full_range) const { + if (IsConstant()) { + const RangeBoundary range_min = full_range.min(); + const RangeBoundary range_max = full_range.max(); + + if (ConstantValue() <= range_min.ConstantValue()) { + return range_min; + } + if (ConstantValue() >= range_max.ConstantValue()) { + return range_max; + } + } + + // If this range is a symbolic range, we do not clamp it. + // This could lead to some imprecision later on. + return *this; +} + int64_t RangeBoundary::ConstantValue() const { ASSERT(IsConstant()); return value_; } -Range Range::Full(Representation rep) { +Range Range::Full(Representation rep, TaggedMode tagged_mode) { + if (rep == kTagged) { + switch (tagged_mode) { + case TaggedMode::kTaggedIsSmi: + return Range::Smi(); + case TaggedMode::kTaggedNotAllowed: + UNREACHABLE(); + } + } ASSERT(RepresentationUtils::IsUnboxedInteger(rep)); return Range(RangeBoundary::FromConstant(RepresentationUtils::MinValue(rep)), RangeBoundary::FromConstant(RepresentationUtils::MaxValue(rep))); @@ -2224,14 +2165,14 @@ bool Range::IsUnsatisfiable() const { return DependOnSameSymbol(min(), max()) && min().offset() > max().offset(); } -void Range::Clamp(RangeBoundary::RangeSize size) { - min_ = min_.Clamp(size); - max_ = max_.Clamp(size); +void Range::Clamp(const Range& full_range) { + min_ = min_.Clamp(full_range); + max_ = max_.Clamp(full_range); } -void Range::ClampToConstant(RangeBoundary::RangeSize size) { - min_ = min_.LowerBound().Clamp(size); - max_ = max_.UpperBound().Clamp(size); +void Range::ClampToConstant(const Range& full_range) { + min_ = min_.LowerBound().Clamp(full_range); + max_ = max_.UpperBound().Clamp(full_range); } void Range::Shl(const Range* left, @@ -2270,10 +2211,8 @@ void Range::Shl(const Range* left, } } if (overflow) { - *result_min = - RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); - *result_max = - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *result_min = RangeBoundary::MinInt64(); + *result_max = RangeBoundary::MaxInt64(); } } @@ -2451,10 +2390,8 @@ void Range::Add(const Range* left_range, } } if (overflow) { - *result_min = - RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); - *result_max = - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *result_min = RangeBoundary::MinInt64(); + *result_max = RangeBoundary::MaxInt64(); } } @@ -2496,10 +2433,8 @@ void Range::Sub(const Range* left_range, } } if (overflow) { - *result_min = - RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); - *result_max = - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *result_min = RangeBoundary::MinInt64(); + *result_max = RangeBoundary::MaxInt64(); } } @@ -2538,8 +2473,8 @@ void Range::Mul(const Range* left_range, return; } - *result_min = RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); - *result_max = RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *result_min = RangeBoundary::MinInt64(); + *result_max = RangeBoundary::MaxInt64(); } void Range::TruncDiv(const Range* left_range, @@ -2563,8 +2498,8 @@ void Range::TruncDiv(const Range* left_range, return; } - *result_min = RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64); - *result_max = RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64); + *result_min = RangeBoundary::MinInt64(); + *result_max = RangeBoundary::MaxInt64(); } void Range::Mod(const Range* right_range, @@ -2600,7 +2535,7 @@ bool Range::OnlyNegativeOrZero(const Range& a, const Range& b) { // Return the maximum absolute value included in range. int64_t Range::ConstantAbsMax(const Range* range) { if (range == nullptr) { - return RangeBoundary::kMax; + return kMaxInt64; } const int64_t abs_min = Utils::AbsWithSaturation(Range::ConstantMin(range).ConstantValue()); @@ -2676,9 +2611,7 @@ void Range::BinaryOp(const Token::Kind op, break; default: - *result = - Range(RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64), - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64)); + *result = Range::Int64(); return; } @@ -2700,13 +2633,13 @@ void Definition::set_range(const Range& range) { void Definition::InferRange(RangeAnalysis* analysis, Range* range) { if (Type()->ToCid() == kSmiCid) { - *range = Range::Full(RangeBoundary::kRangeBoundarySmi); + *range = Range::Smi(); } else if (IsInt64Definition()) { - *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); + *range = Range::Int64(); } else if (IsInt32Definition()) { - *range = Range::Full(RangeBoundary::kRangeBoundaryInt32); + *range = Range::Full(kUnboxedInt32); } else if (Type()->IsInt()) { - *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); + *range = Range::Int64(); } else { // Only Smi and Mint supported. FATAL("Unsupported type in: %s", ToCString()); @@ -2733,7 +2666,7 @@ static bool DependsOnSymbol(const RangeBoundary& a, Definition* symbol) { static void Join(Range* range, Definition* defn, const Range* defn_range, - RangeBoundary::RangeSize size) { + const Range& full_range) { if (Range::IsUnknown(defn_range)) { return; } @@ -2760,10 +2693,10 @@ static void Join(Range* range, } // First try to compare ranges based on their upper and lower bounds. - 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); + const int64_t inf_range = range->min().LowerBound(full_range); + const int64_t inf_other = other.min().LowerBound(full_range); + const int64_t sup_range = range->max().UpperBound(full_range); + const int64_t sup_other = other.max().UpperBound(full_range); if (sup_range <= inf_other) { // The range is fully below defn's range. Keep the minimum and @@ -2775,8 +2708,9 @@ static void Join(Range* 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(), size), - RangeBoundary::JoinMax(range->max(), other.max(), size)); + *range = + Range(RangeBoundary::JoinMin(range->min(), other.min(), full_range), + RangeBoundary::JoinMax(range->max(), other.max(), full_range)); } } @@ -2808,30 +2742,29 @@ static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block, return limit; } -static const Range* GetInputRange(RangeAnalysis* analysis, - RangeBoundary::RangeSize size, - Value* input) { - switch (size) { - case RangeBoundary::kRangeBoundarySmi: - return analysis->GetSmiRange(input); - case RangeBoundary::kRangeBoundaryInt8: - case RangeBoundary::kRangeBoundaryInt16: - case RangeBoundary::kRangeBoundaryInt32: - return input->definition()->range(); - case RangeBoundary::kRangeBoundaryInt64: - return analysis->GetIntRange(input); - default: - UNREACHABLE(); - return nullptr; +static const Range* GetInputRange(Value* input, const Range* full_range) { + Definition* defn = input->definition(); + const Range* range = defn->range(); + + if ((range == nullptr) && !RangeAnalysis::IsIntegerDefinition(defn)) { + // Type propagator determined that reaching type for this use is int. + // However the definition itself is not a int-definition and + // thus it will never have range assigned to it. Just return the widest + // range possible for this value. + // Note: that we can't return nullptr here because it is used as lattice's + // bottom element to indicate that the range was not computed *yet*. + return full_range; } + + return range; } void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { - const RangeBoundary::RangeSize size = RangeSizeForPhi(this); + const Range full_range = FullRangeForPhi(this); for (intptr_t i = 0; i < InputCount(); i++) { Value* input = InputAt(i); - Join(range, input->definition(), GetInputRange(analysis, size, input), - size); + Join(range, input->definition(), GetInputRange(input, &full_range), + full_range); } BlockEntryInstr* phi_block = GetBlock(); @@ -2853,8 +2786,9 @@ void ConstantInstr::InferRange(RangeAnalysis* analysis, Range* range) { } void ConstraintInstr::InferRange(RangeAnalysis* analysis, Range* range) { - const Range* value_range = GetInputRange( - analysis, RepresentationToRangeSize(representation_), value()); + const Range full_range = + Range::Full(representation_, TaggedMode::kTaggedIsSmi); + const Range* value_range = GetInputRange(value(), &full_range); if (Range::IsUnknown(value_range)) { return; } @@ -2889,7 +2823,7 @@ void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) { case Slot::Kind::kAbstractType_hash: case Slot::Kind::kTypeArguments_hash: - *range = Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); + *range = Range::Smi(); break; case Slot::Kind::kTypeArguments_length: @@ -3055,21 +2989,19 @@ void BinaryIntegerOpInstr::InferRangeHelper(const Range* left_range, range); ASSERT(!Range::IsUnknown(range)); - const RangeBoundary::RangeSize range_size = - RepresentationToRangeSize(representation()); - // Calculate overflowed status before clamping if operation is // not truncating. if (!is_truncating()) { - set_can_overflow(!range->Fits(range_size)); + set_can_overflow( + !Range::Fits(range, representation(), TaggedMode::kTaggedIsSmi)); } - range->Clamp(range_size); + range->Clamp(Range::Full(representation(), TaggedMode::kTaggedIsSmi)); } static void CacheRange(Range** slot, const Range* range, - RangeBoundary::RangeSize size) { + const Range& full_range) { if (range != nullptr) { if (*slot == nullptr) { *slot = new Range(); @@ -3077,31 +3009,30 @@ static void CacheRange(Range** slot, **slot = *range; // Eliminate any symbolic dependencies from the range information. - (*slot)->ClampToConstant(size); + (*slot)->ClampToConstant(full_range); } else if (*slot != nullptr) { **slot = Range(); // Clear cached range information. } } void BinaryIntegerOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { - auto const left_size = - RepresentationToRangeSize(RequiredInputRepresentation(0)); - auto const right_size = - RepresentationToRangeSize(RequiredInputRepresentation(1)); - InferRangeHelper(GetInputRange(analysis, left_size, left()), - GetInputRange(analysis, right_size, right()), range); + const Range left_range = + Range::Full(RequiredInputRepresentation(0), TaggedMode::kTaggedIsSmi); + const Range right_range = + Range::Full(RequiredInputRepresentation(1), TaggedMode::kTaggedIsSmi); + InferRangeHelper(GetInputRange(left(), &left_range), + GetInputRange(right(), &right_range), range); } void BinarySmiOpInstr::InferRange(RangeAnalysis* analysis, Range* range) { - const Range* right_smi_range = analysis->GetSmiRange(right()); - // TODO(vegorov) completely remove this once GetSmiRange is eliminated. + const Range smi_range = Range::Smi(); + const Range* right_smi_range = GetInputRange(right(), &smi_range); if (op_kind() == Token::kSHL || op_kind() == Token::kSHR || op_kind() == Token::kUSHR || op_kind() == Token::kMOD || op_kind() == Token::kTRUNCDIV) { - CacheRange(&right_range_, right_smi_range, - RangeBoundary::kRangeBoundarySmi); + CacheRange(&right_range_, right_smi_range, smi_range); } - InferRangeHelper(analysis->GetSmiRange(left()), right_smi_range, range); + InferRangeHelper(GetInputRange(left(), &smi_range), right_smi_range, range); } void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { @@ -3122,9 +3053,7 @@ void UnboxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { *range = Range(v, v); return; } - auto* const value_range = value()->Type()->ToCid() == kSmiCid - ? analysis->GetSmiRange(value()) - : value()->definition()->range(); + Range* const value_range = value()->definition()->range(); const Range to_range = Range::Full(representation()); if (Range::IsUnknown(value_range)) { @@ -3186,7 +3115,7 @@ void AssertAssignableInstr::InferRange(RangeAnalysis* analysis, Range* range) { if (!Range::IsUnknown(value_range)) { *range = *value_range; } else { - *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); + *range = Range::Int64(); } } @@ -3260,9 +3189,8 @@ static bool IsRedundantBasedOnRangeInformation(Value* index, Value* length) { return true; } - RangeBoundary canonical_length = CanonicalizeBoundary( - array_length, - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64)); + RangeBoundary canonical_length = + CanonicalizeBoundary(array_length, RangeBoundary::MaxInt64()); if (canonical_length.OverflowedSmi()) { TRACE_RANGE_ANALYSIS( THR_Print(" ... canonical length boundary (%s) overflows Smi\n", diff --git a/runtime/vm/compiler/backend/range_analysis.h b/runtime/vm/compiler/backend/range_analysis.h index 044a84da205..17202d265c7 100644 --- a/runtime/vm/compiler/backend/range_analysis.h +++ b/runtime/vm/compiler/backend/range_analysis.h @@ -14,6 +14,12 @@ namespace dart { +// How to interpret values with kTagged representation. +enum class TaggedMode { + kTaggedNotAllowed, + kTaggedIsSmi, +}; + class RangeBoundary : public ValueObject { public: #define FOR_EACH_RANGE_BOUNDARY_KIND(V) \ @@ -25,14 +31,6 @@ class RangeBoundary : public ValueObject { enum Kind { FOR_EACH_RANGE_BOUNDARY_KIND(KIND_DEFN) }; #undef KIND_DEFN - enum RangeSize { - kRangeBoundarySmi, - kRangeBoundaryInt8, - kRangeBoundaryInt16, - kRangeBoundaryInt32, - kRangeBoundaryInt64, - }; - RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) {} RangeBoundary(const RangeBoundary& other) @@ -51,9 +49,6 @@ class RangeBoundary : public ValueObject { return *this; } - static constexpr int64_t kMin = kMinInt64; - static constexpr int64_t kMax = kMaxInt64; - // Construct a RangeBoundary for a constant value. static RangeBoundary FromConstant(int64_t val) { return RangeBoundary(val); } @@ -79,40 +74,9 @@ class RangeBoundary : public ValueObject { return FromConstant(compiler::target::kSmiMax); } - // Construct a RangeBoundary for the constant kMin value. - static RangeBoundary MinConstant(RangeSize size) { - switch (size) { - case kRangeBoundarySmi: - return FromConstant(compiler::target::kSmiMin); - case kRangeBoundaryInt8: - return FromConstant(kMinInt8); - case kRangeBoundaryInt16: - return FromConstant(kMinInt16); - case kRangeBoundaryInt32: - return FromConstant(kMinInt32); - case kRangeBoundaryInt64: - return FromConstant(kMinInt64); - } - UNREACHABLE(); - return FromConstant(kMinInt64); - } + static RangeBoundary MinInt64() { return FromConstant(kMinInt64); } - static RangeBoundary MaxConstant(RangeSize size) { - switch (size) { - case kRangeBoundarySmi: - return FromConstant(compiler::target::kSmiMax); - case kRangeBoundaryInt8: - return FromConstant(kMaxInt8); - case kRangeBoundaryInt16: - return FromConstant(kMaxInt16); - case kRangeBoundaryInt32: - return FromConstant(kMaxInt32); - case kRangeBoundaryInt64: - return FromConstant(kMaxInt64); - } - UNREACHABLE(); - return FromConstant(kMaxInt64); - } + static RangeBoundary MaxInt64() { return FromConstant(kMaxInt64); } // Given two boundaries a and b, select one of them as c so that // @@ -134,7 +98,7 @@ class RangeBoundary : public ValueObject { // as possible. static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b, - RangeBoundary::RangeSize size); + const Range& full_range); // Given two boundaries a and b compute boundary c such that // @@ -144,45 +108,29 @@ class RangeBoundary : public ValueObject { // as possible. static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b, - RangeBoundary::RangeSize size); + const Range& full_range); // Returns true when this is a constant that is outside of Smi range. bool OverflowedSmi() const { return IsConstant() && !compiler::target::IsSmi(ConstantValue()); } - bool Overflowed(RangeBoundary::RangeSize size) const { + bool Overflowed(const Range& full_range) const { ASSERT(IsConstant()); - return !Equals(Clamp(size)); + return !Equals(Clamp(full_range)); } - // Clamp constant boundary to MinConstant/MaxConstant of the given size. - RangeBoundary Clamp(RangeSize size) const { - if (IsConstant()) { - const RangeBoundary range_min = RangeBoundary::MinConstant(size); - const RangeBoundary range_max = RangeBoundary::MaxConstant(size); + // Clamp constant boundary to the given [full_range]. + RangeBoundary Clamp(const Range& full_range) const; - if (ConstantValue() <= range_min.ConstantValue()) { - return range_min; - } - if (ConstantValue() >= range_max.ConstantValue()) { - return range_max; - } - } - - // If this range is a symbolic range, we do not clamp it. - // This could lead to some imprecision later on. - return *this; + bool IsLessOrEqual(const RangeBoundary& other) const { + ASSERT(other.IsConstant()); + return IsConstant() && (ConstantValue() <= other.ConstantValue()); } - bool IsMinimumOrBelow(RangeSize size) const { - return IsConstant() && (ConstantValue() <= - RangeBoundary::MinConstant(size).ConstantValue()); - } - - bool IsMaximumOrAbove(RangeSize size) const { - return IsConstant() && (ConstantValue() >= - RangeBoundary::MaxConstant(size).ConstantValue()); + bool IsGreaterOrEqual(const RangeBoundary& other) const { + ASSERT(other.IsConstant()); + return IsConstant() && (ConstantValue() >= other.ConstantValue()); } intptr_t kind() const { return kind_; } @@ -250,18 +198,14 @@ class RangeBoundary : public ValueObject { bool Equals(const RangeBoundary& other) const; - int64_t UpperBound(RangeSize size) const { - return UpperBound().Clamp(size).ConstantValue(); + int64_t UpperBound(const Range& full_range) const { + return UpperBound().Clamp(full_range).ConstantValue(); } - int64_t LowerBound(RangeSize size) const { - return LowerBound().Clamp(size).ConstantValue(); + int64_t LowerBound(const Range& full_range) const { + return LowerBound().Clamp(full_range).ConstantValue(); } - int64_t SmiUpperBound() const { return UpperBound(kRangeBoundarySmi); } - - int64_t SmiLowerBound() const { return LowerBound(kRangeBoundarySmi); } - void Write(FlowGraphSerializer* s) const; explicit RangeBoundary(FlowGraphDeserializer* d); @@ -298,12 +242,16 @@ class Range : public ZoneAllocated { return other->min().IsUnknown(); } - static Range Full(RangeBoundary::RangeSize size) { - return Range(RangeBoundary::MinConstant(size), - RangeBoundary::MaxConstant(size)); + static Range Smi() { + return Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); } - static Range Full(Representation rep); + static Range Int64() { + return Range(RangeBoundary::MinInt64(), RangeBoundary::MaxInt64()); + } + + static Range Full(Representation rep, + TaggedMode tagged_mode = TaggedMode::kTaggedNotAllowed); void PrintTo(BaseTextBuffer* f) const; static const char* ToCString(const Range* range); @@ -324,35 +272,35 @@ class Range : public ZoneAllocated { void set_max(const RangeBoundary& value) { max_ = value; } static RangeBoundary ConstantMinSmi(const Range* range) { - return ConstantMin(range, RangeBoundary::kRangeBoundarySmi); + return ConstantMin(range, Range::Smi()); } static RangeBoundary ConstantMaxSmi(const Range* range) { - return ConstantMax(range, RangeBoundary::kRangeBoundarySmi); + return ConstantMax(range, Range::Smi()); } static RangeBoundary ConstantMin(const Range* range) { - return ConstantMin(range, RangeBoundary::kRangeBoundaryInt64); + return ConstantMin(range, Range::Int64()); } static RangeBoundary ConstantMax(const Range* range) { - return ConstantMax(range, RangeBoundary::kRangeBoundaryInt64); + return ConstantMax(range, Range::Int64()); } static RangeBoundary ConstantMin(const Range* range, - RangeBoundary::RangeSize size) { + const Range& full_range) { if (range == nullptr) { - return RangeBoundary::MinConstant(size); + return full_range.min(); } - return range->min().LowerBound().Clamp(size); + return range->min().LowerBound().Clamp(full_range); } static RangeBoundary ConstantMax(const Range* range, - RangeBoundary::RangeSize size) { + const Range& full_range) { if (range == nullptr) { - return RangeBoundary::MaxConstant(size); + return full_range.max(); } - return range->max().UpperBound().Clamp(size); + return range->max().UpperBound().Clamp(full_range); } // [0, +inf] @@ -393,25 +341,21 @@ class Range : public ZoneAllocated { RangeBoundary::IntersectionMax(max(), other->max())); } - bool Fits(RangeBoundary::RangeSize size) const { - return !min().LowerBound().Overflowed(size) && - !max().UpperBound().Overflowed(size); - } - // Returns true if this range fits without truncation into // the given representation. - static bool Fits(Range* range, Representation rep) { + static bool Fits(Range* range, + Representation rep, + TaggedMode tagged_mode = TaggedMode::kTaggedNotAllowed) { if (range == nullptr) return false; - if (!RepresentationUtils::IsUnboxedInteger(rep)) return false; - const Range& other = Range::Full(rep); + const Range& other = Range::Full(rep, tagged_mode); return range->IsWithin(&other); } // Clamp this to be within size. - void Clamp(RangeBoundary::RangeSize size); + void Clamp(const Range& full_range); // Clamp this to be within size and eliminate symbols. - void ClampToConstant(RangeBoundary::RangeSize size); + void ClampToConstant(const Range& full_range); static void Add(const Range* left_range, const Range* right_range, @@ -492,10 +436,6 @@ class Range : public ZoneAllocated { class RangeUtils : public AllStatic { public: - static bool Fits(Range* range, RangeBoundary::RangeSize size) { - return !Range::IsUnknown(range) && range->Fits(size); - } - static bool IsWithin(const Range* range, int64_t min, int64_t max) { return !Range::IsUnknown(range) && range->IsWithin(min, max); } @@ -530,21 +470,12 @@ class RangeUtils : public AllStatic { class RangeAnalysis : public ValueObject { public: explicit RangeAnalysis(FlowGraph* flow_graph) - : flow_graph_(flow_graph), - smi_range_(Range::Full(RangeBoundary::kRangeBoundarySmi)), - int64_range_(Range::Full(RangeBoundary::kRangeBoundaryInt64)) {} + : flow_graph_(flow_graph), smi_range_(Range::Smi()) {} // Infer ranges for all values and remove overflow checks from binary smi // operations when proven redundant. void Analyze(); - // Helper that should be used to access ranges of inputs during range - // inference. - // Returns meaningful results for uses of non-smi/non-int definitions that - // have smi/int as a reaching type. - const Range* GetSmiRange(Value* value) const; - const Range* GetIntRange(Value* value) const; - static bool IsIntegerDefinition(Definition* defn) { return defn->Type()->IsInt(); } @@ -609,17 +540,16 @@ class RangeAnalysis : public ValueObject { Range* ConstraintRange(Token::Kind op, Definition* boundary, - RangeBoundary::RangeSize size); + const Range& full_range); Zone* zone() const { return flow_graph_->zone(); } + const Range& smi_range() const { return smi_range_; } + FlowGraph* flow_graph_; - // Range object representing full Smi range. Range smi_range_; - Range int64_range_; - // All values that are known to be smi or mint. GrowableArray values_; diff --git a/runtime/vm/compiler/backend/range_analysis_test.cc b/runtime/vm/compiler/backend/range_analysis_test.cc index d9a95f6a684..94c89edc2d9 100644 --- a/runtime/vm/compiler/backend/range_analysis_test.cc +++ b/runtime/vm/compiler/backend/range_analysis_test.cc @@ -52,7 +52,7 @@ TEST_CASE(RangeTests) { TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, NO_CLAMP, result_min, \ result_max) -#define CLAMP_TO_SMI(b) (b.Clamp(RangeBoundary::kRangeBoundarySmi)) +#define CLAMP_TO_SMI(b) (b.Clamp(Range::Smi())) #define TEST_RANGE_OP_SMI(Op, l_min, l_max, r_min, r_max, res_min, res_max) \ TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, CLAMP_TO_SMI, res_min, res_max) @@ -101,7 +101,7 @@ TEST_CASE(RangeTests) { } TEST_CASE(RangeTestsInt64Range) { - const Range fullInt64Range = Range::Full(RangeBoundary::kRangeBoundaryInt64); + const Range fullInt64Range = Range::Int64(); Range* all = new Range(RangeBoundary(kMinInt64), RangeBoundary(kMaxInt64)); EXPECT(all->Equals(&fullInt64Range)); @@ -131,12 +131,10 @@ TEST_CASE(RangeTestsInt64Range) { } TEST_CASE(RangeUtils) { - // Use kMin/kMax instead of +/-inf as any range with a +/-inf bound is - // converted to the full int64 range due to wrap-around. - const RangeBoundary negativeInfinity = - RangeBoundary::FromConstant(RangeBoundary::kMin); - const RangeBoundary positiveInfinity = - RangeBoundary::FromConstant(RangeBoundary::kMax); + // Use MinInt64/MaxInt64 bounds as any wrap-around range is + // converted to the full int64 range. + const RangeBoundary negativeInfinity = RangeBoundary::MinInt64(); + const RangeBoundary positiveInfinity = RangeBoundary::MaxInt64(); // [-inf, +inf]. const Range& range_0 = *(new Range(negativeInfinity, positiveInfinity)); @@ -197,7 +195,7 @@ TEST_CASE(RangeUtils) { EXPECT(!Range::OnlyNegativeOrZero(range_0, range_0)); EXPECT(!Range::OnlyPositiveOrZero(range_0, range_0)); - EXPECT(Range::ConstantAbsMax(&range_0) == RangeBoundary::kMax); + EXPECT(Range::ConstantAbsMax(&range_0) == kMaxInt64); EXPECT(Range::ConstantAbsMax(&range_h) == 2); EXPECT(Range::ConstantAbsMax(&range_i) == 1); @@ -208,28 +206,26 @@ TEST_CASE(RangeUtils) { } TEST_CASE(RangeBinaryOp) { - Range* range_a = new Range(RangeBoundary::FromConstant(-1), - RangeBoundary::FromConstant(RangeBoundary::kMax)); - range_a->Clamp(RangeBoundary::kRangeBoundaryInt32); + Range* range_a = + new Range(RangeBoundary::FromConstant(-1), RangeBoundary::MaxInt64()); + range_a->Clamp(Range::Full(kUnboxedInt32)); EXPECT(range_a->min().ConstantValue() == -1); EXPECT(range_a->max().ConstantValue() == kMaxInt32); - range_a->set_max(RangeBoundary::FromConstant(RangeBoundary::kMax)); + range_a->set_max(RangeBoundary::MaxInt64()); - Range* range_b = new Range(RangeBoundary::FromConstant(RangeBoundary::kMin), - RangeBoundary::FromConstant(1)); - range_b->Clamp(RangeBoundary::kRangeBoundaryInt32); + Range* range_b = + new Range(RangeBoundary::MinInt64(), RangeBoundary::FromConstant(1)); + range_b->Clamp(Range::Full(kUnboxedInt32)); EXPECT(range_b->min().ConstantValue() == kMinInt32); EXPECT(range_b->max().ConstantValue() == 1); - range_b->set_min(RangeBoundary::FromConstant(RangeBoundary::kMin)); + range_b->set_min(RangeBoundary::MinInt64()); { Range result; Range::BinaryOp(Token::kADD, range_a, range_b, nullptr, &result); ASSERT(!Range::IsUnknown(&result)); - EXPECT(result.min().Equals( - RangeBoundary::MinConstant(RangeBoundary::kRangeBoundaryInt64))); - EXPECT(result.max().Equals( - RangeBoundary::MaxConstant(RangeBoundary::kRangeBoundaryInt64))); + EXPECT(result.min().Equals(RangeBoundary::MinInt64())); + EXPECT(result.max().Equals(RangeBoundary::MaxInt64())); } // Test that [5, 10] + [0, 5] = [5, 15]. @@ -527,66 +523,66 @@ TEST_CASE(RangeIntersectionMinMax) { TEST_CASE(RangeJoinMinMax) { // Test IntersectionMin and IntersectionMax methods which for constants are // simply defined as Min/Max respectively. - const RangeBoundary::RangeSize size = RangeBoundary::kRangeBoundarySmi; + const Range full_range = Range::Smi(); // Constants. EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(0), - RangeBoundary::FromConstant(1), size) + RangeBoundary::FromConstant(1), full_range) .ConstantValue() == 1); EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(0), - RangeBoundary::FromConstant(-1), size) + RangeBoundary::FromConstant(-1), full_range) .ConstantValue() == 0); EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(1), - RangeBoundary::FromConstant(0), size) + RangeBoundary::FromConstant(0), full_range) .ConstantValue() == 1); EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(-1), - RangeBoundary::FromConstant(0), size) + RangeBoundary::FromConstant(0), full_range) .ConstantValue() == 0); EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(0), - RangeBoundary::FromConstant(1), size) + RangeBoundary::FromConstant(1), full_range) .ConstantValue() == 0); EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(0), - RangeBoundary::FromConstant(-1), size) + RangeBoundary::FromConstant(-1), full_range) .ConstantValue() == -1); EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(1), - RangeBoundary::FromConstant(0), size) + RangeBoundary::FromConstant(0), full_range) .ConstantValue() == 0); EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(-1), - RangeBoundary::FromConstant(0), size) + RangeBoundary::FromConstant(0), full_range) .ConstantValue() == -1); // Constants vs. kMinInt64 / kMaxInt64. EXPECT(RangeBoundary::JoinMin(RangeBoundary(kMinInt64), - RangeBoundary::FromConstant(-1), size) - .IsMinimumOrBelow(size)); + RangeBoundary::FromConstant(-1), full_range) + .IsLessOrEqual(full_range.min())); EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(-1), - RangeBoundary(kMinInt64), size) - .IsMinimumOrBelow(size)); + RangeBoundary(kMinInt64), full_range) + .IsLessOrEqual(full_range.min())); EXPECT(RangeBoundary::JoinMin(RangeBoundary::FromConstant(1), - RangeBoundary(kMinInt64), size) - .IsMinimumOrBelow(size)); + RangeBoundary(kMinInt64), full_range) + .IsLessOrEqual(full_range.min())); EXPECT(RangeBoundary::JoinMin(RangeBoundary(kMinInt64), - RangeBoundary::FromConstant(1), size) - .IsMinimumOrBelow(size)); + RangeBoundary::FromConstant(1), full_range) + .IsLessOrEqual(full_range.min())); EXPECT(RangeBoundary::JoinMax(RangeBoundary(kMaxInt64), - RangeBoundary::FromConstant(-1), size) - .IsMaximumOrAbove(size)); + RangeBoundary::FromConstant(-1), full_range) + .IsGreaterOrEqual(full_range.max())); EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(-1), - RangeBoundary(kMaxInt64), size) - .IsMaximumOrAbove(size)); + RangeBoundary(kMaxInt64), full_range) + .IsGreaterOrEqual(full_range.max())); EXPECT(RangeBoundary::JoinMax(RangeBoundary::FromConstant(1), - RangeBoundary(kMaxInt64), size) - .IsMaximumOrAbove(size)); + RangeBoundary(kMaxInt64), full_range) + .IsGreaterOrEqual(full_range.max())); EXPECT(RangeBoundary::JoinMax(RangeBoundary(kMaxInt64), - RangeBoundary::FromConstant(1), size) - .IsMaximumOrAbove(size)); + RangeBoundary::FromConstant(1), full_range) + .IsGreaterOrEqual(full_range.max())); } #if defined(DART_PRECOMPILER) && defined(TARGET_ARCH_IS_64_BIT)