9c181ec6d5
Refactor all remaning cases where the current zone is used through new(Isolate*) and remove this interface. Removing this interface is needed to move towards multiple threads per isolate, and also makes the caller more aware of the scope of the zone used, reducing the risk of use-after-free. Make the current thread and the stack zone created around native/runtime entries directly available in their body, saving an indirection (and optimized away if unused). R=iposva@google.com Review URL: https://codereview.chromium.org//982873004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44541 260f80e4-7a28-3924-810f-c04153c831b5
667 lines
20 KiB
C++
667 lines
20 KiB
C++
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
|
|
#define VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
|
|
|
|
#include "vm/flow_graph.h"
|
|
#include "vm/intermediate_language.h"
|
|
|
|
namespace dart {
|
|
|
|
class RangeBoundary : public ValueObject {
|
|
public:
|
|
enum Kind {
|
|
kUnknown,
|
|
kNegativeInfinity,
|
|
kPositiveInfinity,
|
|
kSymbol,
|
|
kConstant,
|
|
};
|
|
|
|
enum RangeSize {
|
|
kRangeBoundarySmi,
|
|
kRangeBoundaryInt32,
|
|
kRangeBoundaryInt64,
|
|
};
|
|
|
|
RangeBoundary() : kind_(kUnknown), value_(0), offset_(0) { }
|
|
|
|
RangeBoundary(const RangeBoundary& other)
|
|
: ValueObject(),
|
|
kind_(other.kind_),
|
|
value_(other.value_),
|
|
offset_(other.offset_) { }
|
|
|
|
explicit RangeBoundary(int64_t val)
|
|
: kind_(kConstant), value_(val), offset_(0) { }
|
|
|
|
RangeBoundary& operator=(const RangeBoundary& other) {
|
|
kind_ = other.kind_;
|
|
value_ = other.value_;
|
|
offset_ = other.offset_;
|
|
return *this;
|
|
}
|
|
|
|
static const int64_t kMin = kMinInt64;
|
|
static const int64_t kMax = kMaxInt64;
|
|
|
|
// Construct a RangeBoundary for a constant value.
|
|
static RangeBoundary FromConstant(int64_t val) {
|
|
return RangeBoundary(val);
|
|
}
|
|
|
|
// Construct a RangeBoundary for -inf.
|
|
static RangeBoundary NegativeInfinity() {
|
|
return RangeBoundary(kNegativeInfinity, 0, 0);
|
|
}
|
|
|
|
// Construct a RangeBoundary for +inf.
|
|
static RangeBoundary PositiveInfinity() {
|
|
return RangeBoundary(kPositiveInfinity, 0, 0);
|
|
}
|
|
|
|
// Construct a RangeBoundary from a definition and offset.
|
|
static RangeBoundary FromDefinition(Definition* defn, int64_t offs = 0);
|
|
|
|
// Construct a RangeBoundary for the constant MinSmi value.
|
|
static RangeBoundary MinSmi() {
|
|
return FromConstant(Smi::kMinValue);
|
|
}
|
|
|
|
// Construct a RangeBoundary for the constant MaxSmi value.
|
|
static RangeBoundary MaxSmi() {
|
|
return FromConstant(Smi::kMaxValue);
|
|
}
|
|
|
|
// Construct a RangeBoundary for the constant kMin value.
|
|
static RangeBoundary MinConstant() {
|
|
return FromConstant(kMin);
|
|
}
|
|
|
|
// Construct a RangeBoundary for the constant kMax value.
|
|
static RangeBoundary MaxConstant() {
|
|
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}
|
|
//
|
|
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,
|
|
RangeBoundary::RangeSize size);
|
|
|
|
// 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,
|
|
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();
|
|
}
|
|
|
|
// -/+ infinity are clamped to MinConstant/MaxConstant of the given type.
|
|
RangeBoundary Clamp(RangeSize size) const {
|
|
if (IsNegativeInfinity()) {
|
|
return RangeBoundary::MinConstant(size);
|
|
}
|
|
|
|
if (IsPositiveInfinity()) {
|
|
return RangeBoundary::MaxConstant(size);
|
|
}
|
|
|
|
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() >= 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 IsMinimumOrBelow(RangeSize size) const {
|
|
return IsNegativeInfinity() ||
|
|
(IsConstant() &&
|
|
(ConstantValue() <= RangeBoundary::MinConstant(size).ConstantValue()));
|
|
}
|
|
|
|
bool IsMaximumOrAbove(RangeSize size) const {
|
|
return IsPositiveInfinity() ||
|
|
(IsConstant() &&
|
|
(ConstantValue() >= RangeBoundary::MaxConstant(size).ConstantValue()));
|
|
}
|
|
|
|
intptr_t kind() const {
|
|
return kind_;
|
|
}
|
|
|
|
// Kind tests.
|
|
bool IsUnknown() const { return kind_ == kUnknown; }
|
|
bool IsConstant() const { return kind_ == kConstant; }
|
|
bool IsSymbol() const { return kind_ == kSymbol; }
|
|
bool IsNegativeInfinity() const { return kind_ == kNegativeInfinity; }
|
|
bool IsPositiveInfinity() const { return kind_ == kPositiveInfinity; }
|
|
bool IsInfinity() const {
|
|
return IsNegativeInfinity() || IsPositiveInfinity();
|
|
}
|
|
bool IsConstantOrInfinity() const {
|
|
return IsConstant() || IsInfinity();
|
|
}
|
|
|
|
// Returns the value of a kConstant RangeBoundary.
|
|
int64_t ConstantValue() const;
|
|
|
|
// Returns the Definition associated with a kSymbol RangeBoundary.
|
|
Definition* symbol() const {
|
|
ASSERT(IsSymbol());
|
|
return reinterpret_cast<Definition*>(value_);
|
|
}
|
|
|
|
// Offset from symbol.
|
|
int64_t offset() const {
|
|
return offset_;
|
|
}
|
|
|
|
// Computes the LowerBound of this. Three cases:
|
|
// IsInfinity() -> NegativeInfinity().
|
|
// IsConstant() -> value().
|
|
// IsSymbol() -> lower bound computed from definition + offset.
|
|
RangeBoundary LowerBound() const;
|
|
|
|
// Computes the UpperBound of this. Three cases:
|
|
// IsInfinity() -> PositiveInfinity().
|
|
// IsConstant() -> value().
|
|
// IsSymbol() -> upper bound computed from definition + offset.
|
|
RangeBoundary UpperBound() const;
|
|
|
|
void PrintTo(BufferFormatter* f) const;
|
|
const char* ToCString() const;
|
|
|
|
static RangeBoundary Add(const RangeBoundary& a,
|
|
const RangeBoundary& b,
|
|
const RangeBoundary& overflow);
|
|
|
|
static RangeBoundary Sub(const RangeBoundary& a,
|
|
const RangeBoundary& b,
|
|
const RangeBoundary& overflow);
|
|
|
|
static RangeBoundary Shl(const RangeBoundary& value_boundary,
|
|
int64_t shift_count,
|
|
const RangeBoundary& overflow);
|
|
|
|
static RangeBoundary Shr(const RangeBoundary& value_boundary,
|
|
int64_t shift_count) {
|
|
ASSERT(value_boundary.IsConstant());
|
|
ASSERT(shift_count >= 0);
|
|
int64_t value = static_cast<int64_t>(value_boundary.ConstantValue());
|
|
int64_t result = value >> shift_count;
|
|
return RangeBoundary(result);
|
|
}
|
|
|
|
// Attempts to calculate a + b when:
|
|
// a is a symbol and b is a constant OR
|
|
// a is a constant and b is a symbol
|
|
// returns true if it succeeds, output is in result.
|
|
static bool SymbolicAdd(const RangeBoundary& a,
|
|
const RangeBoundary& b,
|
|
RangeBoundary* result);
|
|
|
|
// Attempts to calculate a - b when:
|
|
// a is a symbol and b is a constant
|
|
// returns true if it succeeds, output is in result.
|
|
static bool SymbolicSub(const RangeBoundary& a,
|
|
const RangeBoundary& b,
|
|
RangeBoundary* result);
|
|
|
|
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(kRangeBoundarySmi);
|
|
}
|
|
|
|
int64_t SmiLowerBound() const {
|
|
return LowerBound(kRangeBoundarySmi);
|
|
}
|
|
|
|
private:
|
|
RangeBoundary(Kind kind, int64_t value, int64_t offset)
|
|
: kind_(kind), value_(value), offset_(offset) { }
|
|
|
|
Kind kind_;
|
|
int64_t value_;
|
|
int64_t offset_;
|
|
};
|
|
|
|
|
|
class Range : public ZoneAllocated {
|
|
public:
|
|
Range() : min_(), max_() { }
|
|
Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) {
|
|
ASSERT(min_.IsUnknown() == max_.IsUnknown());
|
|
}
|
|
|
|
Range(const Range& other)
|
|
: ZoneAllocated(),
|
|
min_(other.min_),
|
|
max_(other.max_) {
|
|
}
|
|
|
|
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) {
|
|
return Range(RangeBoundary::MinConstant(size),
|
|
RangeBoundary::MaxConstant(size));
|
|
}
|
|
|
|
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) {
|
|
return ConstantMin(range, RangeBoundary::kRangeBoundarySmi);
|
|
}
|
|
|
|
static RangeBoundary ConstantMaxSmi(const Range* range) {
|
|
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(size);
|
|
}
|
|
return range->min().LowerBound().Clamp(size);
|
|
}
|
|
|
|
static RangeBoundary ConstantMax(const Range* range,
|
|
RangeBoundary::RangeSize size) {
|
|
if (range == NULL) {
|
|
return RangeBoundary::MaxConstant(size);
|
|
}
|
|
return range->max().UpperBound().Clamp(size);
|
|
}
|
|
|
|
|
|
// [0, +inf]
|
|
bool IsPositive() const;
|
|
|
|
// [-inf, val].
|
|
bool OnlyLessThanOrEqualTo(int64_t val) const;
|
|
|
|
// [val, +inf].
|
|
bool OnlyGreaterThanOrEqualTo(int64_t val) const;
|
|
|
|
// Inclusive.
|
|
bool IsWithin(int64_t min_int, int64_t max_int) const;
|
|
|
|
// Inclusive.
|
|
bool Overlaps(int64_t min_int, int64_t max_int) const;
|
|
|
|
bool IsUnsatisfiable() const;
|
|
|
|
bool IsFinite() const {
|
|
return !min_.IsInfinity() && !max_.IsInfinity();
|
|
}
|
|
|
|
Range Intersect(const Range* other) const {
|
|
return Range(RangeBoundary::IntersectionMin(min(), other->min()),
|
|
RangeBoundary::IntersectionMax(max(), other->max()));
|
|
}
|
|
|
|
bool Fits(RangeBoundary::RangeSize size) const {
|
|
return !min().LowerBound().Overflowed(size) &&
|
|
!max().UpperBound().Overflowed(size);
|
|
}
|
|
|
|
// Clamp this to be within size.
|
|
void Clamp(RangeBoundary::RangeSize size);
|
|
|
|
static void Add(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max,
|
|
Definition* left_defn);
|
|
|
|
static void Sub(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max,
|
|
Definition* left_defn);
|
|
|
|
static void Mul(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max);
|
|
static void Shr(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max);
|
|
|
|
static void Shl(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max);
|
|
|
|
static void And(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max);
|
|
|
|
static void BitwiseOp(const Range* left_range,
|
|
const Range* right_range,
|
|
RangeBoundary* min,
|
|
RangeBoundary* max);
|
|
|
|
// Both the a and b ranges are >= 0.
|
|
static bool OnlyPositiveOrZero(const Range& a, const Range& b);
|
|
|
|
// Both the a and b ranges are <= 0.
|
|
static bool OnlyNegativeOrZero(const Range& a, const Range& b);
|
|
|
|
// Return the maximum absolute value included in range.
|
|
static int64_t ConstantAbsMax(const Range* range);
|
|
|
|
// Return the minimum absolute value included in range.
|
|
static int64_t ConstantAbsMin(const Range* range);
|
|
|
|
static void BinaryOp(const Token::Kind op,
|
|
const Range* left_range,
|
|
const Range* right_range,
|
|
Definition* left_defn,
|
|
Range* result);
|
|
|
|
private:
|
|
RangeBoundary min_;
|
|
RangeBoundary max_;
|
|
};
|
|
|
|
|
|
class RangeUtils : public AllStatic {
|
|
public:
|
|
static bool Fits(Range* range, RangeBoundary::RangeSize size) {
|
|
return !Range::IsUnknown(range) && range->Fits(size);
|
|
}
|
|
|
|
static bool IsWithin(Range* range, int64_t min, int64_t max) {
|
|
return !Range::IsUnknown(range) && range->IsWithin(min, max);
|
|
}
|
|
|
|
static bool IsPositive(Range* range) {
|
|
return !Range::IsUnknown(range) && range->IsPositive();
|
|
}
|
|
};
|
|
|
|
|
|
// Range analysis for integer values.
|
|
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)) { }
|
|
|
|
// 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.
|
|
// For Int typed definitions we use full Int64 range as a safe approximation
|
|
// even though they might contain Bigint values because we only support
|
|
// 64-bit operations in the optimized code - which means that Bigint will
|
|
// cause deoptimization.
|
|
const Range* GetSmiRange(Value* value) const;
|
|
const Range* GetIntRange(Value* value) const;
|
|
|
|
static bool IsIntegerDefinition(Definition* defn) {
|
|
return defn->Type()->IsInt();
|
|
}
|
|
|
|
void AssignRangesRecursively(Definition* defn);
|
|
|
|
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();
|
|
|
|
// Iterate over smi values and constrain them at branch successors.
|
|
// Additionally constraint values after CheckSmi instructions.
|
|
void InsertConstraints();
|
|
|
|
// Iterate over uses of the given definition and discover branches that
|
|
// constrain it. Insert appropriate Constraint instructions at true
|
|
// and false successor and rename all dominated uses to refer to a
|
|
// Constraint instead of this definition.
|
|
void InsertConstraintsFor(Definition* defn);
|
|
|
|
// Create a constraint for defn, insert it after given instruction and
|
|
// rename all uses that are dominated by it.
|
|
ConstraintInstr* InsertConstraintFor(Value* use,
|
|
Definition* defn,
|
|
Range* constraint,
|
|
Instruction* after);
|
|
|
|
bool 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.
|
|
void RenameDominatedUses(Definition* def,
|
|
Instruction* dom,
|
|
Definition* other);
|
|
|
|
|
|
// Infer ranges for integer (smi or mint) definitions.
|
|
void InferRanges();
|
|
|
|
// Collect integer definition in the reverse postorder.
|
|
void CollectDefinitions(BitVector* set);
|
|
|
|
// 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);
|
|
|
|
// Based on computed ranges find and eliminate redundant CheckArrayBound
|
|
// instructions.
|
|
void EliminateRedundantBoundsChecks();
|
|
|
|
// Find unsatisfiable constraints and mark corresponding blocks unreachable.
|
|
void MarkUnreachableBlocks();
|
|
|
|
// Convert mint operations that stay within int32 range into Int32 operations.
|
|
void NarrowMintToInt32();
|
|
|
|
void DiscoverSimpleInductionVariables();
|
|
|
|
// Remove artificial Constraint instructions and replace them with actual
|
|
// unconstrained definitions.
|
|
void RemoveConstraints();
|
|
|
|
Range* ConstraintSmiRange(Token::Kind op, Definition* boundary);
|
|
|
|
Zone* zone() const { return flow_graph_->zone(); }
|
|
|
|
FlowGraph* flow_graph_;
|
|
|
|
// Range object representing full Smi range.
|
|
Range smi_range_;
|
|
|
|
Range int64_range_;
|
|
|
|
// 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_;
|
|
|
|
// All Constraints inserted during InsertConstraints phase. They are treated
|
|
// as smi values.
|
|
GrowableArray<ConstraintInstr*> constraints_;
|
|
|
|
// List of integer (smi or mint) definitions including constraints sorted
|
|
// in the reverse postorder.
|
|
GrowableArray<Definition*> definitions_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(RangeAnalysis);
|
|
};
|
|
|
|
|
|
// Replaces Mint IL instructions with Uint32 IL instructions
|
|
// when possible. Uses output of RangeAnalysis.
|
|
class IntegerInstructionSelector : public ValueObject {
|
|
public:
|
|
explicit IntegerInstructionSelector(FlowGraph* flow_graph);
|
|
|
|
void Select();
|
|
|
|
private:
|
|
bool IsPotentialUint32Definition(Definition* def);
|
|
void FindPotentialUint32Definitions();
|
|
bool IsUint32NarrowingDefinition(Definition* def);
|
|
void FindUint32NarrowingDefinitions();
|
|
bool AllUsesAreUint32Narrowing(Value* list_head);
|
|
bool CanBecomeUint32(Definition* def);
|
|
void Propagate();
|
|
Definition* ConstructReplacementFor(Definition* def);
|
|
void ReplaceInstructions();
|
|
|
|
Zone* zone() const { return zone_; }
|
|
|
|
GrowableArray<Definition*> potential_uint32_defs_;
|
|
BitVector* selected_uint32_defs_;
|
|
|
|
FlowGraph* flow_graph_;
|
|
Zone* zone_;
|
|
};
|
|
|
|
|
|
} // namespace dart
|
|
|
|
#endif // VM_FLOW_GRAPH_RANGE_ANALYSIS_H_
|