Index: src/hydrogen-instructions.h |
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h |
index 3e53eca7092293b0d2c5a41766db8d8c50ec60fc..253a97aa5c145bfc307a2435220a41326c950a92 100644 |
--- a/src/hydrogen-instructions.h |
+++ b/src/hydrogen-instructions.h |
@@ -147,6 +147,7 @@ class LChunkBuilder; |
V(MathMinMax) \ |
V(Mod) \ |
V(Mul) \ |
+ V(NumericConstraint) \ |
V(ObjectLiteral) \ |
V(OsrEntry) \ |
V(OuterContext) \ |
@@ -550,6 +551,127 @@ enum GVNFlag { |
#undef COUNT_FLAG |
}; |
+ |
+class NumericRelation { |
+ public: |
+ enum Kind { NONE, EQ, GT, GE, LT, LE, NE }; |
+ static const char* MnemonicFromKind(Kind kind) { |
+ switch (kind) { |
+ case NONE: return "NONE"; |
+ case EQ: return "EQ"; |
+ case GT: return "GT"; |
+ case GE: return "GE"; |
+ case LT: return "LT"; |
+ case LE: return "LE"; |
+ case NE: return "NE"; |
+ } |
+ UNREACHABLE(); |
+ return NULL; |
+ } |
+ const char* Mnemonic() const { return MnemonicFromKind(kind_); } |
+ |
+ static NumericRelation None() { return NumericRelation(NONE); } |
+ static NumericRelation Eq() { return NumericRelation(EQ); } |
+ static NumericRelation Gt() { return NumericRelation(GT); } |
+ static NumericRelation Ge() { return NumericRelation(GE); } |
+ static NumericRelation Lt() { return NumericRelation(LT); } |
+ static NumericRelation Le() { return NumericRelation(LE); } |
+ static NumericRelation Ne() { return NumericRelation(NE); } |
+ |
+ bool IsNone() { return kind_ == NONE; } |
+ |
+ static NumericRelation FromToken(Token::Value token) { |
+ switch (token) { |
+ case Token::EQ: return Eq(); |
+ case Token::EQ_STRICT: return Eq(); |
+ case Token::LT: return Lt(); |
+ case Token::GT: return Gt(); |
+ case Token::LTE: return Le(); |
+ case Token::GTE: return Ge(); |
+ case Token::NE: return Ne(); |
+ case Token::NE_STRICT: return Ne(); |
+ default: return None(); |
+ } |
+ } |
+ |
+ // The semantics of "Reversed" is that if "x rel y" is true then also |
+ // "y rel.Reversed() x" is true, and that rel.Reversed().Reversed() == rel. |
+ NumericRelation Reversed() { |
+ switch (kind_) { |
+ case NONE: return None(); |
+ case EQ: return Eq(); |
+ case GT: return Lt(); |
+ case GE: return Le(); |
+ case LT: return Gt(); |
+ case LE: return Ge(); |
+ case NE: return Ne(); |
+ } |
+ UNREACHABLE(); |
+ return None(); |
+ } |
+ |
+ // The semantics of "Negated" is that if "x rel y" is true then also |
+ // "!(x rel.Negated() y)" is true. |
+ NumericRelation Negated() { |
+ switch (kind_) { |
+ case NONE: return None(); |
+ case EQ: return Ne(); |
+ case GT: return Le(); |
+ case GE: return Lt(); |
+ case LT: return Ge(); |
+ case LE: return Gt(); |
+ case NE: return Eq(); |
+ } |
+ UNREACHABLE(); |
+ return None(); |
+ } |
+ |
+ // The semantics of "Implies" is that if "x rel y" is true |
+ // then also "x other_relation y" is true. |
+ bool Implies(NumericRelation other_relation) { |
+ switch (kind_) { |
+ case NONE: return false; |
+ case EQ: return (other_relation.kind_ == EQ) |
+ || (other_relation.kind_ == GE) |
+ || (other_relation.kind_ == LE); |
+ case GT: return (other_relation.kind_ == GT) |
+ || (other_relation.kind_ == GE) |
+ || (other_relation.kind_ == NE); |
+ case LT: return (other_relation.kind_ == LT) |
+ || (other_relation.kind_ == LE) |
+ || (other_relation.kind_ == NE); |
+ case GE: return (other_relation.kind_ == GE); |
+ case LE: return (other_relation.kind_ == LE); |
+ case NE: return (other_relation.kind_ == NE); |
+ } |
+ UNREACHABLE(); |
+ return false; |
+ } |
+ |
+ // The semantics of "IsExtendable" is that if |
+ // "rel.IsExtendable(direction)" is true then |
+ // "x rel y" implies "(x + direction) rel y" . |
+ bool IsExtendable(int direction) { |
+ switch (kind_) { |
+ case NONE: return false; |
+ case EQ: return false; |
+ case GT: return (direction >= 0); |
+ case GE: return (direction >= 0); |
+ case LT: return (direction <= 0); |
+ case LE: return (direction <= 0); |
+ case NE: return false; |
+ } |
+ UNREACHABLE(); |
+ return false; |
+ } |
+ |
+ private: |
+ explicit NumericRelation(Kind kind) : kind_(kind) {} |
+ |
+ Kind kind_; |
+}; |
+ |
+ |
typedef EnumSet<GVNFlag> GVNFlagSet; |
@@ -713,6 +835,9 @@ class HValue: public ZoneObject { |
UpdateRedefinedUsesInner<Dominates>(); |
} |
+ bool IsInteger32Constant(); |
+ int32_t GetInteger32Constant(); |
+ |
bool IsDefinedAfter(HBasicBlock* other) const; |
// Operands. |
@@ -839,6 +964,24 @@ class HValue: public ZoneObject { |
virtual void Verify() = 0; |
#endif |
+ // This method is recursive but it is guaranteed to terminate because |
+ // RedefinedOperand() always dominates "this". |
+ bool IsRelationTrue(NumericRelation relation, HValue* other) { |
+ if (this == other) { |
+ return NumericRelation::Eq().Implies(relation); |
+ } |
+ |
+ bool result = IsRelationTrueInternal(relation, other) || |
+ other->IsRelationTrueInternal(relation.Reversed(), this); |
+ if (!result) { |
+ HValue* redefined = RedefinedOperand(); |
+ if (redefined != NULL) { |
+ result = redefined->IsRelationTrue(relation, other); |
+ } |
+ } |
+ return result; |
+ } |
+ |
protected: |
// This function must be overridden for instructions with flag kUseGVN, to |
// compare the non-Operand parts of the instruction. |
@@ -901,6 +1044,12 @@ class HValue: public ZoneObject { |
} |
} |
+ // Informative definitions can override this method to state any numeric |
+ // relation they provide on the redefined value. |
+ virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
+ return false; |
+ } |
+ |
static GVNFlagSet AllDependsOnFlagSet() { |
GVNFlagSet result; |
// Create changes mask. |
@@ -1125,6 +1274,50 @@ class HDummyUse: public HTemplateInstruction<1> { |
}; |
+class HNumericConstraint : public HTemplateInstruction<2> { |
+ public: |
+ static HNumericConstraint* AddToGraph(HValue* constrained_value, |
+ NumericRelation relation, |
+ HValue* related_value, |
+ HInstruction* insertion_point = NULL); |
+ |
+ HValue* constrained_value() { return OperandAt(0); } |
+ HValue* related_value() { return OperandAt(1); } |
+ NumericRelation relation() { return relation_; } |
+ |
+ virtual int RedefinedOperandIndex() { return 0; } |
+ |
+ virtual Representation RequiredInputRepresentation(int index) { |
+ return representation(); |
+ } |
+ |
+ virtual void PrintDataTo(StringStream* stream); |
+ |
+ virtual bool IsRelationTrueInternal(NumericRelation other_relation, |
+ HValue* other_related_value) { |
+ if (related_value() == other_related_value) { |
+ return relation().Implies(other_relation); |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
+ DECLARE_CONCRETE_INSTRUCTION(NumericConstraint) |
+ |
+ private: |
+ HNumericConstraint(HValue* constrained_value, |
+ NumericRelation relation, |
+ HValue* related_value) |
+ : relation_(relation) { |
+ SetOperandAt(0, constrained_value); |
+ SetOperandAt(1, related_value); |
+ set_representation(constrained_value->representation()); |
+ } |
+ |
+ NumericRelation relation_; |
+}; |
+ |
+ |
// We insert soft-deoptimize when we hit code with unknown typefeedback, |
// so that we get a chance of re-optimizing with useful typefeedback. |
// HSoftDeoptimize does not end a basic block as opposed to HDeoptimize. |
@@ -2677,6 +2870,8 @@ class HPhi: public HValue { |
int merged_index() const { return merged_index_; } |
+ virtual void AddInformativeDefinitions(); |
+ |
virtual void PrintTo(StringStream* stream); |
#ifdef DEBUG |
@@ -3154,6 +3349,9 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
return Representation::Integer32(); |
} |
+ virtual bool IsRelationTrueInternal(NumericRelation relation, |
+ HValue* related_value); |
+ |
virtual void PrintDataTo(StringStream* stream); |
virtual void InferRepresentation(HInferRepresentation* h_infer); |
@@ -3161,6 +3359,7 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
HValue* length() { return OperandAt(1); } |
virtual int RedefinedOperandIndex() { return 0; } |
+ virtual void AddInformativeDefinitions(); |
DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) |
@@ -3337,6 +3536,8 @@ class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> { |
} |
virtual void PrintDataTo(StringStream* stream); |
+ virtual void AddInformativeDefinitions(); |
+ |
DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch) |
private: |
@@ -3741,6 +3942,23 @@ class HAdd: public HArithmeticBinaryOperation { |
virtual HValue* Canonicalize(); |
+ virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
+ HValue* base = NULL; |
+ int32_t offset = 0; |
+ if (left()->IsInteger32Constant()) { |
+ base = right(); |
+ offset = left()->GetInteger32Constant(); |
+ } else if (right()->IsInteger32Constant()) { |
+ base = left(); |
+ offset = right()->GetInteger32Constant(); |
+ } else { |
+ return false; |
+ } |
+ |
+ return relation.IsExtendable(offset) |
+ ? base->IsRelationTrue(relation, other) : false; |
+ } |
+ |
DECLARE_CONCRETE_INSTRUCTION(Add) |
protected: |
@@ -3766,6 +3984,17 @@ class HSub: public HArithmeticBinaryOperation { |
HValue* left, |
HValue* right); |
+ virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
+ if (right()->IsInteger32Constant()) { |
+ HValue* base = left(); |
+ int32_t offset = right()->GetInteger32Constant(); |
+ return relation.IsExtendable(-offset) |
+ ? base->IsRelationTrue(relation, other) : false; |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
DECLARE_CONCRETE_INSTRUCTION(Sub) |
protected: |