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 18487cc1281ab6d58b98657ca775564cef059c68..84fb30866666d204d4b1afc49bf106e283c9c0dc 100644 |
--- a/runtime/vm/flow_graph_range_analysis.cc |
+++ b/runtime/vm/flow_graph_range_analysis.cc |
@@ -245,8 +245,7 @@ void RangeAnalysis::CollectValues() { |
if (join != NULL) { |
for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { |
PhiInstr* current = phi_it.Current(); |
- if ((current->Type()->ToCid() == kSmiCid) || |
- (current->representation() == kUnboxedInt32)) { |
+ if (current->Type()->IsInt()) { |
values_.Add(current); |
} |
} |
@@ -517,6 +516,28 @@ const Range* RangeAnalysis::GetSmiRange(Value* value) const { |
} |
+const Range* RangeAnalysis::GetIntRange(Value* value) const { |
+ Definition* defn = value->definition(); |
+ const Range* range = defn->range(); |
+ |
+ if ((range == NULL) && !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. |
+ // It is safe to return Int64 range as this is the widest possible range |
+ // supported by our unboxing operations - if this definition produces |
+ // Bigint outside of Int64 we will deoptimize whenever we actually try |
+ // to unbox it. |
+ // Note: that we can't return NULL 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); |
@@ -639,6 +660,21 @@ char RangeAnalysis::OpPrefix(JoinOperator op) { |
} |
+static RangeBoundary::RangeSize RangeSizeForPhi(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; |
+ } else { |
+ UNREACHABLE(); |
+ return RangeBoundary::kRangeBoundaryInt64; |
+ } |
+} |
+ |
+ |
bool RangeAnalysis::InferRange(JoinOperator op, |
Definition* defn, |
intptr_t iteration) { |
@@ -647,11 +683,7 @@ bool RangeAnalysis::InferRange(JoinOperator op, |
if (!Range::IsUnknown(&range)) { |
if (!Range::IsUnknown(defn->range()) && defn->IsPhi()) { |
- // 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; |
+ const RangeBoundary::RangeSize size = RangeSizeForPhi(defn); |
if (op == WIDEN) { |
range = Range(WidenMin(defn->range(), &range, size), |
WidenMax(defn->range(), &range, size)); |
@@ -755,7 +787,7 @@ void RangeAnalysis::InferRanges() { |
// Perform an iteration of range inference just propagating ranges |
// through the graph as-is without applying widening or narrowing. |
// This helps to improve precision of initial bounds. |
- Iterate(NONE, 1); |
+ Iterate(NONE, 2); |
Florian Schneider
2014/11/10 16:10:47
Maybe a comment why 2 iterations help.
|
// Perform fix-point iteration of range inference applying widening |
// operator to phis to ensure fast convergence. |
@@ -2592,6 +2624,8 @@ void Definition::InferRange(RangeAnalysis* analysis, Range* range) { |
*range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
} else if (IsInt32Definition()) { |
*range = Range::Full(RangeBoundary::kRangeBoundaryInt32); |
+ } else if (Type()->IsInt()) { |
+ *range = Range::Full(RangeBoundary::kRangeBoundaryInt64); |
} else { |
// Only Smi and Mint supported. |
UNREACHABLE(); |
@@ -2692,16 +2726,31 @@ static RangeBoundary EnsureAcyclicSymbol(BlockEntryInstr* phi_block, |
} |
+static const Range* GetInputRange(RangeAnalysis* analysis, |
+ RangeBoundary::RangeSize size, |
+ Value* input) { |
+ switch (size) { |
+ case RangeBoundary::kRangeBoundarySmi: |
+ return analysis->GetSmiRange(input); |
+ case RangeBoundary::kRangeBoundaryInt32: |
+ return input->definition()->range(); |
+ case RangeBoundary::kRangeBoundaryInt64: |
+ return analysis->GetIntRange(input); |
+ default: |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+} |
+ |
+ |
void PhiInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
- ASSERT((Type()->ToCid() == kSmiCid) || (representation() == kUnboxedInt32)); |
- const RangeBoundary::RangeSize size = (Type()->ToCid() == kSmiCid) ? |
- RangeBoundary::kRangeBoundarySmi : RangeBoundary::kRangeBoundaryInt32; |
+ const RangeBoundary::RangeSize size = RangeSizeForPhi(this); |
for (intptr_t i = 0; i < InputCount(); i++) { |
Value* input = InputAt(i); |
- const Range* input_range = (size == RangeBoundary::kRangeBoundarySmi) ? |
- analysis->GetSmiRange(input) : input->definition()->range(); |
Join(range, |
- input->definition(), input_range, size); |
+ input->definition(), |
+ GetInputRange(analysis, size, input), |
+ size); |
} |
BlockEntryInstr* phi_block = GetBlock(); |
@@ -2795,20 +2844,12 @@ void LoadIndexedInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
RangeBoundary::FromConstant(65535)); |
break; |
case kTypedDataInt32ArrayCid: |
- if (Typed32BitIsSmi()) { |
Florian Schneider
2014/11/10 16:10:47
Is Typed32BitIsSmi() still used anywhere?
|
- *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
- } else { |
- *range = Range(RangeBoundary::FromConstant(kMinInt32), |
- RangeBoundary::FromConstant(kMaxInt32)); |
- } |
+ *range = Range(RangeBoundary::FromConstant(kMinInt32), |
+ RangeBoundary::FromConstant(kMaxInt32)); |
break; |
case kTypedDataUint32ArrayCid: |
- if (Typed32BitIsSmi()) { |
- *range = Range::Full(RangeBoundary::kRangeBoundarySmi); |
- } else { |
- *range = Range(RangeBoundary::FromConstant(0), |
- RangeBoundary::FromConstant(kMaxUint32)); |
- } |
+ *range = Range(RangeBoundary::FromConstant(0), |
+ RangeBoundary::FromConstant(kMaxUint32)); |
break; |
case kOneByteStringCid: |
*range = Range(RangeBoundary::FromConstant(0), |
@@ -2915,14 +2956,13 @@ void BoxIntegerInstr::InferRange(RangeAnalysis* analysis, Range* range) { |
void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
- if (value()->definition()->Type()->ToCid() == kSmiCid) { |
+ if (value()->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(); |
+ } else if (RangeAnalysis::IsIntegerDefinition(value()->definition())) { |
+ const Range* value_range = analysis->GetIntRange(value()); |
if (!Range::IsUnknown(value_range)) { |
*range = *value_range; |
} |
@@ -2934,6 +2974,30 @@ void UnboxInt32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
} |
+void UnboxUint32Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
+ const Range* value_range = NULL; |
+ |
+ if (value()->Type()->ToCid() == kSmiCid) { |
+ value_range = analysis->GetSmiRange(value()); |
+ } else if (RangeAnalysis::IsIntegerDefinition(value()->definition())) { |
+ value_range = analysis->GetIntRange(value()); |
+ } else { |
+ *range = Range(RangeBoundary::FromConstant(0), |
+ RangeBoundary::FromConstant(kMaxUint32)); |
+ return; |
+ } |
+ |
+ if (!Range::IsUnknown(value_range)) { |
+ if (value_range->IsPositive()) { |
+ *range = *value_range; |
+ } else { |
+ *range = Range(RangeBoundary::FromConstant(0), |
+ RangeBoundary::FromConstant(kMaxUint32)); |
+ } |
+ } |
+} |
+ |
+ |
void UnboxInt64Instr::InferRange(RangeAnalysis* analysis, Range* range) { |
const Range* value_range = value()->definition()->range(); |
if (value_range != NULL) { |