Index: runtime/vm/flow_graph_range_analysis.h |
diff --git a/runtime/vm/flow_graph_range_analysis.h b/runtime/vm/flow_graph_range_analysis.h |
index 168595b9b65a501c2e60bd56745fcbc9e5bb84ae..d81538550f3faef723338099720a92430ddd07e3 100644 |
--- a/runtime/vm/flow_graph_range_analysis.h |
+++ b/runtime/vm/flow_graph_range_analysis.h |
@@ -22,6 +22,7 @@ class RangeBoundary : public ValueObject { |
enum RangeSize { |
kRangeBoundarySmi, |
+ kRangeBoundaryInt32, |
kRangeBoundaryInt64, |
}; |
@@ -74,7 +75,7 @@ class RangeBoundary : public ValueObject { |
return FromConstant(Smi::kMaxValue); |
} |
- // Construct a RangeBoundary for the constant kMin value. |
+ // Construct a RangeBoundary for the constant kMin value. |
static RangeBoundary MinConstant() { |
return FromConstant(kMin); |
} |
@@ -84,6 +85,34 @@ class RangeBoundary : public ValueObject { |
return FromConstant(kMax); |
} |
+ // Construct a RangeBoundary for the constant kMin value. |
+ static RangeBoundary MinConstant(RangeSize size) { |
+ switch (size) { |
+ case kRangeBoundarySmi: |
+ return FromConstant(Smi::kMinValue); |
+ case kRangeBoundaryInt32: |
+ return FromConstant(kMinInt32); |
+ case kRangeBoundaryInt64: |
+ return FromConstant(kMinInt64); |
+ } |
+ UNREACHABLE(); |
+ return FromConstant(kMinInt64); |
+ } |
+ |
+ static RangeBoundary MaxConstant(RangeSize size) { |
+ switch (size) { |
+ case kRangeBoundarySmi: |
+ return FromConstant(Smi::kMaxValue); |
+ case kRangeBoundaryInt32: |
+ return FromConstant(kMaxInt32); |
+ case kRangeBoundaryInt64: |
+ return FromConstant(kMaxInt64); |
+ } |
+ UNREACHABLE(); |
+ return FromConstant(kMaxInt64); |
+ } |
+ |
+ |
// Given two boundaries a and b, select one of them as c so that |
// |
// inf {[a, ...) ^ [b, ...)} >= inf {c} |
@@ -102,7 +131,9 @@ class RangeBoundary : public ValueObject { |
// |
// Try to select c such that it is as close to inf {[a, ...) U [b, ...)} |
// as possible. |
- static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b); |
+ static RangeBoundary JoinMin(RangeBoundary a, |
+ RangeBoundary b, |
+ RangeBoundary::RangeSize size); |
// Given two boundaries a and b compute boundary c such that |
// |
@@ -110,13 +141,20 @@ class RangeBoundary : public ValueObject { |
// |
// Try to select c such that it is as close to sup {(..., a] U (..., b]} |
// as possible. |
- static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b); |
+ static RangeBoundary JoinMax(RangeBoundary a, |
+ RangeBoundary b, |
+ RangeBoundary::RangeSize size); |
// Returns true when this is a constant that is outside of Smi range. |
bool OverflowedSmi() const { |
return (IsConstant() && !Smi::IsValid(ConstantValue())) || IsInfinity(); |
} |
+ bool Overflowed(RangeBoundary::RangeSize size) const { |
+ ASSERT(IsConstantOrInfinity()); |
+ return !Equals(Clamp(size)); |
+ } |
+ |
// Returns true if this outside mint range. |
bool OverflowedMint() const { |
return IsInfinity(); |
@@ -125,40 +163,40 @@ class RangeBoundary : public ValueObject { |
// -/+ infinity are clamped to MinConstant/MaxConstant of the given type. |
RangeBoundary Clamp(RangeSize size) const { |
if (IsNegativeInfinity()) { |
- return (size == kRangeBoundaryInt64) ? MinConstant() : MinSmi(); |
+ return RangeBoundary::MinConstant(size); |
} |
+ |
if (IsPositiveInfinity()) { |
- return (size == kRangeBoundaryInt64) ? MaxConstant() : MaxSmi(); |
+ return RangeBoundary::MaxConstant(size); |
} |
- if ((size == kRangeBoundarySmi) && IsConstant()) { |
- if (ConstantValue() <= Smi::kMinValue) { |
- return MinSmi(); |
+ |
+ if (IsConstant()) { |
+ const RangeBoundary range_min = RangeBoundary::MinConstant(size); |
+ const RangeBoundary range_max = RangeBoundary::MaxConstant(size); |
+ |
+ if (ConstantValue() <= range_min.ConstantValue()) { |
+ return range_min; |
} |
- if (ConstantValue() >= Smi::kMaxValue) { |
- return MaxSmi(); |
+ 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 IsSmiMinimumOrBelow() const { |
+ bool IsMinimumOrBelow(RangeSize size) const { |
return IsNegativeInfinity() || |
- (IsConstant() && (ConstantValue() <= Smi::kMinValue)); |
+ (IsConstant() && |
+ (ConstantValue() <= RangeBoundary::MinConstant(size).ConstantValue())); |
} |
- bool IsSmiMaximumOrAbove() const { |
+ bool IsMaximumOrAbove(RangeSize size) const { |
return IsPositiveInfinity() || |
- (IsConstant() && (ConstantValue() >= Smi::kMaxValue)); |
- } |
- |
- bool IsMinimumOrBelow() const { |
- return IsNegativeInfinity() || (IsConstant() && (ConstantValue() == kMin)); |
- } |
- |
- bool IsMaximumOrAbove() const { |
- return IsPositiveInfinity() || (IsConstant() && (ConstantValue() == kMax)); |
+ (IsConstant() && |
+ (ConstantValue() >= RangeBoundary::MaxConstant(size).ConstantValue())); |
} |
intptr_t kind() const { |
@@ -245,12 +283,20 @@ class RangeBoundary : public ValueObject { |
bool Equals(const RangeBoundary& other) const; |
+ int64_t UpperBound(RangeSize size) const { |
+ return UpperBound().Clamp(size).ConstantValue(); |
+ } |
+ |
+ int64_t LowerBound(RangeSize size) const { |
+ return LowerBound().Clamp(size).ConstantValue(); |
+ } |
+ |
int64_t SmiUpperBound() const { |
- return UpperBound().Clamp(kRangeBoundarySmi).ConstantValue(); |
+ return UpperBound(kRangeBoundarySmi); |
} |
int64_t SmiLowerBound() const { |
- return LowerBound().Clamp(kRangeBoundarySmi).ConstantValue(); |
+ return LowerBound(kRangeBoundarySmi); |
} |
private: |
@@ -290,12 +336,8 @@ class Range : public ZoneAllocated { |
} |
static Range Full(RangeBoundary::RangeSize size) { |
- if (size == RangeBoundary::kRangeBoundarySmi) { |
- return Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi()); |
- } else { |
- ASSERT(size == RangeBoundary::kRangeBoundaryInt64); |
- return Range(RangeBoundary::MinConstant(), RangeBoundary::MaxConstant()); |
- } |
+ return Range(RangeBoundary::MinConstant(size), |
+ RangeBoundary::MaxConstant(size)); |
} |
void PrintTo(BufferFormatter* f) const; |
@@ -320,33 +362,38 @@ class Range : public ZoneAllocated { |
} |
static RangeBoundary ConstantMinSmi(const Range* range) { |
- if (range == NULL) { |
- return RangeBoundary::MinSmi(); |
- } |
- return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundarySmi); |
+ return ConstantMin(range, RangeBoundary::kRangeBoundarySmi); |
} |
static RangeBoundary ConstantMaxSmi(const Range* range) { |
- if (range == NULL) { |
- return RangeBoundary::MaxSmi(); |
- } |
- return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundarySmi); |
+ return ConstantMax(range, RangeBoundary::kRangeBoundarySmi); |
} |
static RangeBoundary ConstantMin(const Range* range) { |
+ return ConstantMin(range, RangeBoundary::kRangeBoundaryInt64); |
+ } |
+ |
+ static RangeBoundary ConstantMax(const Range* range) { |
+ return ConstantMax(range, RangeBoundary::kRangeBoundaryInt64); |
+ } |
+ |
+ static RangeBoundary ConstantMin(const Range* range, |
+ RangeBoundary::RangeSize size) { |
if (range == NULL) { |
- return RangeBoundary::MinConstant(); |
+ return RangeBoundary::MinConstant(size); |
} |
- return range->min().LowerBound().Clamp(RangeBoundary::kRangeBoundaryInt64); |
+ return range->min().LowerBound().Clamp(size); |
} |
- static RangeBoundary ConstantMax(const Range* range) { |
+ static RangeBoundary ConstantMax(const Range* range, |
+ RangeBoundary::RangeSize size) { |
if (range == NULL) { |
- return RangeBoundary::MaxConstant(); |
+ return RangeBoundary::MaxConstant(size); |
} |
- return range->max().UpperBound().Clamp(RangeBoundary::kRangeBoundaryInt64); |
+ return range->max().UpperBound().Clamp(size); |
} |
+ |
// [0, +inf] |
bool IsPositive() const; |
@@ -373,6 +420,15 @@ class Range : public ZoneAllocated { |
RangeBoundary::IntersectionMax(max(), other->max())); |
} |
+ bool Fits(RangeBoundary::RangeSize size) const { |
+ return !min().LowerBound().Overflowed(size) && |
+ !max().UpperBound().Overflowed(size); |
+ } |
+ |
+ static bool Fits(Range* range, RangeBoundary::RangeSize size) { |
+ return !IsUnknown(range) && range->Fits(size); |
+ } |
srdjan
2014/08/27 16:17:13
I think it is confusing to have a non-static and s
Vyacheslav Egorov (Google)
2014/08/28 20:48:37
Agreed. Moved into a separate AllStatic helper cla
|
+ |
// Clamp this to be within size. |
void Clamp(RangeBoundary::RangeSize size); |
@@ -503,6 +559,9 @@ class RangeAnalysis : public ValueObject { |
// Find unsatisfiable constraints and mark corresponding blocks unreachable. |
void MarkUnreachableBlocks(); |
+ // Convert mint operations that stay within int32 range into Int32 operations. |
+ void NarrowMintToInt32(); |
+ |
// Remove artificial Constraint instructions and replace them with actual |
// unconstrained definitions. |
void RemoveConstraints(); |
@@ -519,6 +578,10 @@ class RangeAnalysis : public ValueObject { |
// Value that are known to be smi or mint. |
GrowableArray<Definition*> values_; |
+ GrowableArray<BinaryMintOpInstr*> binary_mint_ops_; |
+ |
+ GrowableArray<ShiftMintOpInstr*> shift_mint_ops_; |
+ |
// All CheckArrayBound instructions. |
GrowableArray<CheckArrayBoundInstr*> bounds_checks_; |