Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1228)

Unified Diff: runtime/vm/intermediate_language.h

Issue 10960014: Implement range analysis for smi values. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cleanup Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/intermediate_language.h
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index f47d6e3b90e42ee873f3f74efc4a681f60ff1bb0..91d86ba7892f18ba327cf0c3b740167026314ac8 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -25,6 +25,7 @@ class FlowGraphCompiler;
class FlowGraphVisitor;
class Instruction;
class LocalVariable;
+class Range;
// TODO(srdjan): Add _ByteArrayBase, get:length.
@@ -80,6 +81,8 @@ class Value : public ZoneAllocated {
void AddToInputUseList();
void AddToEnvUseList();
+ void RemoveFromInputUseList();
+
Value* Copy() { return new Value(definition_); }
RawAbstractType* CompileType() const;
@@ -252,6 +255,7 @@ class EmbeddedArray<T, 0> {
M(UnboxDouble) \
M(BoxDouble) \
M(CheckArrayBound) \
+ M(Constraint) \
#define FORWARD_DECLARATION(type) class type##Instr;
@@ -278,7 +282,8 @@ class Instruction : public ZoneAllocated {
#undef DECLARE_TAG
Instruction()
- : deopt_id_(Isolate::Current()->GetNextDeoptId()),
+ : range_(NULL),
+ deopt_id_(Isolate::Current()->GetNextDeoptId()),
lifetime_position_(-1),
previous_(NULL),
next_(NULL),
@@ -435,6 +440,12 @@ FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
return next() == NULL;
}
+ virtual bool InferRange() {
+ return false;
+ }
+
+ virtual Range* range();
+
// Returns deoptimization id that corresponds to the deoptimization target
// that input operands conversions inserted for this instruction can jump
// to.
@@ -491,6 +502,8 @@ FOR_EACH_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
return deopt_id_;
}
+ Range* range_;
Florian Schneider 2012/09/21 08:56:44 It seems that range_ can be made a member of Defin
Kevin Millikin (Google) 2012/09/21 08:59:33 Does it buy us anything to make this a pointer ins
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Done.
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Pointer allows use also to express _|_ state which
+
private:
friend class Definition; // Needed for InsertBefore, InsertAfter.
@@ -723,6 +736,10 @@ class BlockEntryInstr : public Instruction {
loop_info_ = loop_info;
}
+ virtual BlockEntryInstr* GetBlock() const {
+ return const_cast<BlockEntryInstr*>(this);
+ }
+
protected:
explicit BlockEntryInstr(intptr_t try_index)
: try_index_(try_index),
@@ -929,6 +946,37 @@ class JoinEntryInstr : public BlockEntryInstr {
};
+class PhiIterator : public ValueObject {
+ public:
+ explicit PhiIterator(JoinEntryInstr* join)
+ : phis_(join->phis()), index_(-1) {
+ Advance();
+ }
+
+ void Advance() {
Kevin Millikin (Google) 2012/09/21 08:59:33 Simpler: void Advance() { ++index_; while (!D
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 This is how it looked initially. I just wanted to
+ if (Done()) return;
Florian Schneider 2012/09/21 08:56:44 I'd rather write ASSERT(!Done());
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Done.
+
+ intptr_t i = index_ + 1;
+ while ((i < phis_->length()) && ((*phis_)[i] == NULL)) {
+ i++;
+ }
+ index_ = i;
+ }
+
+ bool Done() const {
+ return (phis_ == NULL) || (index_ >= phis_->length());
+ }
+
+ PhiInstr* Current() const {
+ return (*phis_)[index_];
+ }
+
+ private:
+ ZoneGrowableArray<PhiInstr*>* phis_;
+ intptr_t index_;
+};
+
+
class TargetEntryInstr : public BlockEntryInstr {
public:
explicit TargetEntryInstr(intptr_t try_index)
@@ -1106,7 +1154,8 @@ class PhiInstr : public Definition {
: block_(block),
inputs_(num_inputs),
is_alive_(false),
- representation_(kTagged) {
+ representation_(kTagged),
+ has_unranged_inputs_(true) {
for (intptr_t i = 0; i < num_inputs; ++i) {
inputs_.Add(NULL);
}
@@ -1165,6 +1214,10 @@ class PhiInstr : public Definition {
virtual void PrintTo(BufferFormatter* f) const;
virtual void PrintToVisualizer(BufferFormatter* f) const;
+ virtual bool InferRange();
+
+ virtual Range* range() { return range_; }
+
private:
friend class JoinEntryInstr; // Direct access to inputs_ array.
@@ -1173,6 +1226,8 @@ class PhiInstr : public Definition {
bool is_alive_;
Representation representation_;
+ bool has_unranged_inputs_;
Florian Schneider 2012/09/21 08:56:44 Maybe rename to has_inputs_without_range_.
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Done.
+
DISALLOW_COPY_AND_ASSIGN(PhiInstr);
};
@@ -1530,9 +1585,257 @@ class TemplateDefinition : public Definition {
};
+class RangeBoundary : public ValueObject {
+ public:
+ enum Kind { kUnknown, kSymbol, kConstant };
+
+ RangeBoundary() : kind_(kUnknown), value_(0), offs_(0) { }
Kevin Millikin (Google) 2012/09/21 08:59:33 Please burn two characters to spell out 'offset'.
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Done.
+
+ static RangeBoundary FromConstant(intptr_t val) {
+ return RangeBoundary(kConstant, val, 0);
+ }
+
+ static RangeBoundary FromDefinition(Definition* defn, intptr_t offs = 0) {
+ return RangeBoundary(kSymbol, reinterpret_cast<intptr_t>(defn), offs);
+ }
+
+ static RangeBoundary MinSmi() {
+ return FromConstant(Smi::kMinValue);
+ }
+
+ static RangeBoundary MaxSmi() {
+ return FromConstant(Smi::kMaxValue);
+ }
+
+ static RangeBoundary OverflowedMinSmi() {
+ return FromConstant(Smi::kMinValue - 1);
+ }
+
+ static RangeBoundary OverflowedMaxSmi() {
+ return FromConstant(Smi::kMaxValue + 1);
+ }
+
+ static RangeBoundary Min(RangeBoundary a, RangeBoundary b) {
+ const intptr_t min_a = a.LowerBound().value();
+ const intptr_t min_b = b.LowerBound().value();
+
+ return RangeBoundary::FromConstant((min_a < min_b) ? min_a : min_b);
Kevin Millikin (Google) 2012/09/21 08:59:33 You can spell this Utils::Minimum(min_a, min_b)
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Done.
+ }
+
+ static RangeBoundary Max(RangeBoundary a, RangeBoundary b) {
+ const intptr_t max_a = a.UpperBound().value();
+ const intptr_t max_b = b.UpperBound().value();
+
+ return RangeBoundary::FromConstant((max_a > max_b) ? max_a : max_b);
+ }
+
+ bool Overflowed() const {
+ return !Smi::IsValid(value());
+ }
+
+ RangeBoundary Clamp() const {
+ if (IsConstant()) {
+ if (value() < Smi::kMinValue) return MinSmi();
+ if (value() > Smi::kMaxValue) return MaxSmi();
+ }
+ return *this;
+ }
+
+ bool Equals(const RangeBoundary& other) const {
+ return (kind_ == other.kind_) && (value_ == other.value_);
Florian Schneider 2012/09/21 08:56:44 && (offs_ == other.offs_)
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Nice catch!
+ }
+
+ bool IsUnknown() const { return kind_ == kUnknown; }
+ bool IsConstant() const { return kind_ == kConstant; }
+ bool IsSymbol() const { return kind_ == kSymbol; }
+
+ intptr_t value() const {
+ ASSERT(IsConstant());
+ return value_;
+ }
+
+ Definition* symbol() const {
+ ASSERT(IsSymbol());
+ return reinterpret_cast<Definition*>(value_);
+ }
+
+ RangeBoundary LowerBound() const;
+ RangeBoundary UpperBound() const;
+
+ static RangeBoundary WidenMin(const RangeBoundary& old_min,
+ const RangeBoundary& new_min) {
+ if (new_min.LowerBound().value() < old_min.LowerBound().value()) {
+ return MinSmi();
+ }
+ return new_min;
+ }
+
+ static RangeBoundary WidenMax(const RangeBoundary& old_max,
+ const RangeBoundary& new_max) {
+ if (new_max.UpperBound().value() > old_max.UpperBound().value()) {
+ return MaxSmi();
+ }
+ return new_max;
+ }
+
+ void PrintTo(BufferFormatter* f) const;
+
+ static RangeBoundary Add(const RangeBoundary& a,
+ const RangeBoundary& b,
+ const RangeBoundary& overflow) {
+ ASSERT(a.IsConstant() && b.IsConstant());
+
+ intptr_t result = a.value() + b.value();
+ if (!Smi::IsValid64(result)) {
Florian Schneider 2012/09/21 08:56:44 I think this should be Smi::IsValid(intptr_t value
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Yes. 64 is a leftover of an experiment.
+ return overflow;
+ }
+ return RangeBoundary::FromConstant(result);
+ }
+
+ static RangeBoundary Sub(const RangeBoundary& a,
+ const RangeBoundary& b,
+ const RangeBoundary& overflow) {
+ ASSERT(a.IsConstant() && b.IsConstant());
+
+ intptr_t result = a.value() - b.value();
+ if (!Smi::IsValid64(result)) {
Florian Schneider 2012/09/21 08:56:44 Use Smi::IsValid(intptr_t value) here too.
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Done.
+ return overflow;
+ }
+ return RangeBoundary::FromConstant(result);
+ }
+
+ private:
+ RangeBoundary(Kind kind, intptr_t value, intptr_t offs)
+ : kind_(kind), value_(value), offs_(offs) { }
+
+ Kind kind_;
+ intptr_t value_;
+ intptr_t offs_;
+};
+
+
+class Range : public ZoneAllocated {
+ public:
+ Range(RangeBoundary min, RangeBoundary max) : min_(min), max_(max) { }
+
+ static Range* Unknown() {
+ return new Range(RangeBoundary::MinSmi(), RangeBoundary::MaxSmi());
+ }
+
+ void PrintTo(BufferFormatter* f) const;
+
+ const RangeBoundary& min() { return min_; }
+ const RangeBoundary& max() { return max_; }
+
+ bool Equals(Range* other) {
+ return min_.Equals(other->min_) && max_.Equals(other->max_);
+ }
+
+ static bool Update(Range** range_slot,
+ const RangeBoundary& min,
+ const RangeBoundary& max) {
+ if (*range_slot == NULL) {
+ *range_slot = new Range(min, max);
+ return true;
+ }
+
+ Range* range = *range_slot;
+ if (range->min_.Equals(min) && range->max_.Equals(max)) {
+ return false;
+ }
+
+ range->min_ = min;
+ range->max_ = max;
+
+ return true;
+ }
+
+ static RangeBoundary ConstantMin(Range* range) {
+ if (range == NULL) return RangeBoundary::MinSmi();
+ return range->min().LowerBound();
+ }
+
+ static RangeBoundary ConstantMax(Range* range) {
+ if (range == NULL) return RangeBoundary::MaxSmi();
+ return range->max().UpperBound();
+ }
+
+ private:
+ RangeBoundary min_;
+ RangeBoundary max_;
+};
+
+
+class ConstraintInstr : public TemplateDefinition<2> {
+ public:
+ ConstraintInstr(Value* value, Range* constraint)
+ : constraint_(constraint) {
+ inputs_[0] = value;
+ inputs_[1] = NULL; // Dependency.
+ }
+
+ DECLARE_INSTRUCTION(Constraint)
+
+ virtual RawAbstractType* CompileType() const {
+ return Type::SmiType();
+ }
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual bool HasSideEffect() const { return false; }
+
+ virtual intptr_t ResultCid() const { return kSmiCid; }
+
+ virtual bool AttributesEqual(Definition* other) const {
+ UNREACHABLE();
+ return false;
+ }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ Value* value() const { return inputs_[0]; }
+ Range* constraint() const { return constraint_; }
+
+ virtual bool InferRange();
+
+ virtual Range* range() {
+ return range_;
+ }
+
+ void AddDependency(Definition* defn) {
+ Value* val = new Value(defn);
+ val->set_use_index(1);
+ val->set_instruction(this);
+ val->AddToInputUseList();
+ set_dependency(val);
+ }
+
+ void RemoveDependency() {
+ if (dependency() != NULL) {
+ dependency()->RemoveFromInputUseList();
+ set_dependency(NULL);
+ }
+ }
+
+ private:
+ Value* dependency() {
+ return inputs_[1];
+ }
+
+ void set_dependency(Value* value) {
+ inputs_[1] = value;
+ }
+
+ Range* constraint_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConstraintInstr);
+};
+
+
class ConstantInstr : public TemplateDefinition<0> {
public:
- explicit ConstantInstr(const Object& value) : value_(value) { }
+ explicit ConstantInstr(const Object& value)
+ : value_(value) { }
DECLARE_INSTRUCTION(Constant)
virtual RawAbstractType* CompileType() const;
@@ -1550,6 +1853,16 @@ class ConstantInstr : public TemplateDefinition<0> {
virtual bool AttributesEqual(Instruction* other) const;
virtual bool AffectedBySideEffect() const { return false; }
+ virtual Range* range() {
Kevin Millikin (Google) 2012/09/21 08:59:33 This is disconcerting. Simpler just to treat smi
Vyacheslav Egorov (Google) 2012/09/21 20:08:07 Initially I wanted to make range() assert when you
+ ASSERT(value_.IsSmi());
+ if (range_ == NULL) {
+ intptr_t value = Smi::Cast(value_).Value();
+ range_ = new Range(RangeBoundary::FromConstant(value),
+ RangeBoundary::FromConstant(value));
+ }
+ return range_;
+ }
+
private:
const Object& value_;
@@ -1855,7 +2168,8 @@ class PolymorphicInstanceCallInstr : public TemplateDefinition<0> {
class ComparisonInstr : public TemplateDefinition<2> {
public:
- ComparisonInstr(Token::Kind kind, Value* left, Value* right) : kind_(kind) {
+ ComparisonInstr(Token::Kind kind, Value* left, Value* right)
+ : kind_(kind) {
ASSERT(left != NULL);
ASSERT(right != NULL);
inputs_[0] = left;
@@ -3151,7 +3465,8 @@ class BinarySmiOpInstr : public TemplateDefinition<2> {
Value* left,
Value* right)
: op_kind_(op_kind),
- instance_call_(instance_call) {
+ instance_call_(instance_call),
+ overflow_(true) {
ASSERT(left != NULL);
ASSERT(right != NULL);
inputs_[0] = left;
@@ -3181,9 +3496,19 @@ class BinarySmiOpInstr : public TemplateDefinition<2> {
virtual intptr_t ResultCid() const;
+ void set_overflow(bool overflow) {
+ overflow_ = overflow;
+ }
+
+ void PrintTo(BufferFormatter* f) const;
+
+ virtual bool InferRange();
+ virtual Range* range() { return range_; }
+
private:
const Token::Kind op_kind_;
InstanceCallInstr* instance_call_;
+ bool overflow_;
DISALLOW_COPY_AND_ASSIGN(BinarySmiOpInstr);
};

Powered by Google App Engine
This is Rietveld 408576698