| 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 f9ae03664a1851ce62094763615ae290a39b243f..135cca0fa5720087728b48db7fa6b9b01a0454cf 100644
|
| --- a/runtime/vm/flow_graph_range_analysis.h
|
| +++ b/runtime/vm/flow_graph_range_analysis.h
|
| @@ -84,9 +84,33 @@ class RangeBoundary : public ValueObject {
|
| return FromConstant(kMax);
|
| }
|
|
|
| - // Calculate the minimum of a and b within the given range.
|
| - static RangeBoundary Min(RangeBoundary a, RangeBoundary b, RangeSize size);
|
| - static RangeBoundary Max(RangeBoundary a, RangeBoundary b, RangeSize size);
|
| + // Given two boundaries a and b, select one of them as c so that
|
| + //
|
| + // inf {[a, ...) ^ [b, ...)} >= inf {c}
|
| + //
|
| + static RangeBoundary IntersectionMin(RangeBoundary a, RangeBoundary b);
|
| +
|
| + // Given two boundaries a and b, select one of them as c so that
|
| + //
|
| + // sup {(..., a] ^ (..., b]} <= sup {c}
|
| + //
|
| + static RangeBoundary IntersectionMax(RangeBoundary a, RangeBoundary b);
|
| +
|
| + // Given two boundaries a and b compute boundary c such that
|
| + //
|
| + // inf {[a, ...) U [b, ...)} >= inf {c}
|
| + //
|
| + // Try to select c such that it is as close to inf {[a, ...) U [b, ...)}
|
| + // as possible.
|
| + static RangeBoundary JoinMin(RangeBoundary a, RangeBoundary b);
|
| +
|
| + // Given two boundaries a and b compute boundary c such that
|
| + //
|
| + // sup {(..., a] U (..., b]} <= sup {c}
|
| + //
|
| + // Try to select c such that it is as close to sup {(..., a] U (..., b]}
|
| + // as possible.
|
| + static RangeBoundary JoinMax(RangeBoundary a, RangeBoundary b);
|
|
|
| // Returns true when this is a constant that is outside of Smi range.
|
| bool OverflowedSmi() const {
|
| @@ -119,7 +143,6 @@ class RangeBoundary : public ValueObject {
|
| return *this;
|
| }
|
|
|
| -
|
| bool IsSmiMinimumOrBelow() const {
|
| return IsNegativeInfinity() ||
|
| (IsConstant() && (ConstantValue() <= Smi::kMinValue));
|
| @@ -222,6 +245,14 @@ class RangeBoundary : public ValueObject {
|
|
|
| bool Equals(const RangeBoundary& other) const;
|
|
|
| + int64_t SmiUpperBound() const {
|
| + return UpperBound().Clamp(kRangeBoundarySmi).ConstantValue();
|
| + }
|
| +
|
| + int64_t SmiLowerBound() const {
|
| + return LowerBound().Clamp(kRangeBoundarySmi).ConstantValue();
|
| + }
|
| +
|
| private:
|
| RangeBoundary(Kind kind, int64_t value, int64_t offset)
|
| : kind_(kind), value_(value), offset_(offset) { }
|
| @@ -234,23 +265,59 @@ class RangeBoundary : public ValueObject {
|
|
|
| class Range : public ZoneAllocated {
|
| public:
|
| - Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { }
|
| + Range() : min_(), max_() { }
|
| + Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) {
|
| + ASSERT(min_.IsUnknown() == max_.IsUnknown());
|
| + }
|
|
|
| - static Range* Unknown() {
|
| - return new Range(RangeBoundary::MinConstant(),
|
| - RangeBoundary::MaxConstant());
|
| + Range(const Range& other)
|
| + : ZoneAllocated(),
|
| + min_(other.min_),
|
| + max_(other.max_) {
|
| }
|
|
|
| - static Range* UnknownSmi() {
|
| - return new Range(RangeBoundary::MinSmi(),
|
| - RangeBoundary::MaxSmi());
|
| + Range& operator=(const Range& other) {
|
| + min_ = other.min_;
|
| + max_ = other.max_;
|
| + return *this;
|
| + }
|
| +
|
| + static bool IsUnknown(const Range* other) {
|
| + if (other == NULL) {
|
| + return true;
|
| + }
|
| + return other->min().IsUnknown();
|
| + }
|
| +
|
| + 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());
|
| + }
|
| }
|
|
|
| void PrintTo(BufferFormatter* f) const;
|
| static const char* ToCString(const Range* range);
|
|
|
| + bool Equals(const Range* other) {
|
| + ASSERT(min_.IsUnknown() == max_.IsUnknown());
|
| + if (other == NULL) {
|
| + return min_.IsUnknown();
|
| + }
|
| + return min_.Equals(other->min_) &&
|
| + max_.Equals(other->max_);
|
| + }
|
| +
|
| const RangeBoundary& min() const { return min_; }
|
| const RangeBoundary& max() const { return max_; }
|
| + void set_min(const RangeBoundary& value) {
|
| + min_ = value;
|
| + }
|
| + void set_max(const RangeBoundary& value) {
|
| + max_ = value;
|
| + }
|
|
|
| static RangeBoundary ConstantMinSmi(const Range* range) {
|
| if (range == NULL) {
|
| @@ -301,6 +368,11 @@ class Range : public ZoneAllocated {
|
| return !min_.IsInfinity() && !max_.IsInfinity();
|
| }
|
|
|
| + Range Intersect(const Range* other) const {
|
| + return Range(RangeBoundary::IntersectionMin(min(), other->min()),
|
| + RangeBoundary::IntersectionMax(max(), other->max()));
|
| + }
|
| +
|
| // Clamp this to be within size.
|
| void Clamp(RangeBoundary::RangeSize size);
|
|
|
| @@ -345,10 +417,11 @@ class Range : public ZoneAllocated {
|
| // Return the maximum absolute value included in range.
|
| static int64_t ConstantAbsMax(const Range* range);
|
|
|
| - static Range* BinaryOp(const Token::Kind op,
|
| - const Range* left_range,
|
| - const Range* right_range,
|
| - Definition* left_defn);
|
| + static void BinaryOp(const Token::Kind op,
|
| + const Range* left_range,
|
| + const Range* right_range,
|
| + Definition* left_defn,
|
| + Range* result);
|
|
|
| private:
|
| RangeBoundary min_;
|
| @@ -361,13 +434,26 @@ class RangeAnalysis : public ValueObject {
|
| public:
|
| explicit RangeAnalysis(FlowGraph* flow_graph)
|
| : flow_graph_(flow_graph),
|
| - marked_defns_(NULL) { }
|
| + smi_range_(Range::Full(RangeBoundary::kRangeBoundarySmi)) { }
|
|
|
| // 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 definitions that have smi
|
| + // as a reaching type.
|
| + const Range* GetRange(Value* value) const;
|
| +
|
| private:
|
| + enum JoinOperator {
|
| + NONE,
|
| + WIDEN,
|
| + NARROW
|
| + };
|
| + static char OpPrefix(JoinOperator op);
|
| +
|
| // Collect all values that were proven to be smi in smi_values_ array and all
|
| // CheckSmi instructions in smi_check_ array.
|
| void CollectValues();
|
| @@ -384,14 +470,13 @@ class RangeAnalysis : public ValueObject {
|
|
|
| // Create a constraint for defn, insert it after given instruction and
|
| // rename all uses that are dominated by it.
|
| - ConstraintInstr* InsertConstraintFor(Definition* defn,
|
| + ConstraintInstr* InsertConstraintFor(Value* use,
|
| + Definition* defn,
|
| Range* constraint,
|
| Instruction* after);
|
|
|
| - void ConstrainValueAfterBranch(Definition* defn, Value* use);
|
| - void ConstrainValueAfterCheckArrayBound(Definition* defn,
|
| - CheckArrayBoundInstr* check,
|
| - intptr_t use_index);
|
| + void ConstrainValueAfterBranch(Value* use, Definition* defn);
|
| + void ConstrainValueAfterCheckArrayBound(Value* use, Definition* defn);
|
|
|
| // Replace uses of the definition def that are dominated by instruction dom
|
| // with uses of other definition.
|
| @@ -400,62 +485,50 @@ class RangeAnalysis : public ValueObject {
|
| Definition* other);
|
|
|
|
|
| - // Walk the dominator tree and infer ranges for smi values.
|
| + // Infer ranges for integer (smi or mint) definitions.
|
| void InferRanges();
|
| - void InferRangesRecursive(BlockEntryInstr* block);
|
| -
|
| - enum Direction {
|
| - kUnknown,
|
| - kPositive,
|
| - kNegative,
|
| - kBoth
|
| - };
|
| -
|
| - Range* InferInductionVariableRange(JoinEntryInstr* loop_header,
|
| - PhiInstr* var);
|
|
|
| - void ResetWorklist();
|
| - void MarkDefinition(Definition* defn);
|
| + // Collect integer definition in the reverse postorder.
|
| + void CollectDefinitions(BlockEntryInstr* block, BitVector* set);
|
|
|
| - static Direction ToDirection(Value* val);
|
| + // Recompute ranges of all definitions until they stop changing.
|
| + // Apply the given JoinOperator when computing Phi ranges.
|
| + void Iterate(JoinOperator op, intptr_t max_iterations);
|
| + bool InferRange(JoinOperator op, Definition* defn, intptr_t iteration);
|
|
|
| - static Direction Invert(Direction direction) {
|
| - return (direction == kPositive) ? kNegative : kPositive;
|
| - }
|
| + // Based on computed ranges find and eliminate redundant CheckArrayBound
|
| + // instructions.
|
| + void EliminateRedundantBoundsChecks();
|
|
|
| - static void UpdateDirection(Direction* direction,
|
| - Direction new_direction) {
|
| - if (*direction != new_direction) {
|
| - if (*direction != kUnknown) new_direction = kBoth;
|
| - *direction = new_direction;
|
| - }
|
| - }
|
| + // Find unsatisfiable constraints and mark corresponding blocks unreachable.
|
| + void MarkUnreachableBlocks();
|
|
|
| // Remove artificial Constraint instructions and replace them with actual
|
| // unconstrained definitions.
|
| void RemoveConstraints();
|
|
|
| - Range* ConstraintRange(Token::Kind op, Definition* boundary);
|
| + Range* ConstraintSmiRange(Token::Kind op, Definition* boundary);
|
|
|
| Isolate* isolate() const { return flow_graph_->isolate(); }
|
|
|
| FlowGraph* flow_graph_;
|
|
|
| + // Range object representing full Smi range.
|
| + Range smi_range_;
|
| +
|
| // Value that are known to be smi or mint.
|
| GrowableArray<Definition*> values_;
|
| - // All CheckSmi instructions.
|
| - GrowableArray<CheckSmiInstr*> smi_checks_;
|
| +
|
| + // All CheckArrayBound instructions.
|
| + GrowableArray<CheckArrayBoundInstr*> bounds_checks_;
|
|
|
| // All Constraints inserted during InsertConstraints phase. They are treated
|
| // as smi values.
|
| GrowableArray<ConstraintInstr*> constraints_;
|
|
|
| - // Bitvector for a quick filtering of known smi or mint values.
|
| - BitVector* definitions_;
|
| -
|
| - // Worklist for induction variables analysis.
|
| - GrowableArray<Definition*> worklist_;
|
| - BitVector* marked_defns_;
|
| + // List of integer (smi or mint) definitions including constraints sorted
|
| + // in the reverse postorder.
|
| + GrowableArray<Definition*> definitions_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(RangeAnalysis);
|
| };
|
|
|