Chromium Code Reviews| Index: src/hydrogen-instructions.h |
| diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h |
| index 2d763d55f0df2eaf0a779ccf7fc1da5898b9bd2d..12608fca45f18e2324d1c3c7136f290a5816de72 100644 |
| --- a/src/hydrogen-instructions.h |
| +++ b/src/hydrogen-instructions.h |
| @@ -75,6 +75,7 @@ class LChunkBuilder; |
| V(BitNot) \ |
| V(BlockEntry) \ |
| V(BoundsCheck) \ |
| + V(BoundsCheckBaseIndexInformation) \ |
| V(Branch) \ |
| V(CallConstantFunction) \ |
| V(CallFunction) \ |
| @@ -666,13 +667,130 @@ class NumericRelation { |
| return false; |
| } |
| + // CompoundImplies returns true when |
| + // "((x + my_offset) >> my_scale) rel y" implies |
| + // "((x + other_offset) >> other_scale) other_relation y". |
| + bool CompoundImplies(NumericRelation other_relation, |
| + int my_offset, |
| + int my_scale, |
| + int other_offset = 0, |
| + int other_scale = 0) { |
| + return Implies(other_relation) && ComponentsImply( |
| + my_offset, my_scale, other_offset, other_scale); |
| + } |
| + |
| private: |
| + // ComponentsImply returns true when |
| + // "((x + my_offset) >> my_scale) rel y" implies |
| + // "((x + other_offset) >> other_scale) rel y". |
| + bool ComponentsImply(int my_offset, |
| + int my_scale, |
| + int other_offset, |
| + int other_scale) { |
| + switch (kind_) { |
| + case NONE: break; // Fall through to UNREACHABLE(). |
| + case EQ: |
| + case NE: return my_offset == other_offset && my_scale == other_scale; |
| + case GT: |
| + case GE: return my_offset <= other_offset && my_scale >= other_scale; |
| + case LT: |
| + case LE: return my_offset >= other_offset && my_scale <= other_scale; |
| + } |
| + UNREACHABLE(); |
| + return false; |
| + } |
| + |
| explicit NumericRelation(Kind kind) : kind_(kind) {} |
| Kind kind_; |
| }; |
| +class DecompositionResult BASE_EMBEDDED { |
| + public: |
| + DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} |
| + |
| + HValue* base() { return base_; } |
| + int offset() { return offset_; } |
| + int scale() { return scale_; } |
| + |
| + bool Apply(HValue* b, int o, int s = 0) { |
|
Jakob Kummerow
2013/03/14 16:16:32
nit: please spell out the names ("base", "offset",
|
| + if (base() == NULL) { |
|
Jakob Kummerow
2013/03/14 16:16:32
nit: s/base()/base_/ [for consistency with "base_
|
| + base_ = b; |
| + offset_ = o; |
| + scale_ = s; |
| + return true; |
| + } else { |
| + if (scale_ == 0) { |
| + base_ = b; |
| + offset_ += o; |
| + scale_ = s; |
| + return true; |
| + } else { |
| + return false; |
| + } |
| + } |
| + } |
| + |
| + void SwapValues(HValue** b, int* o, int* s) { |
|
Jakob Kummerow
2013/03/14 16:16:32
again
|
| + swap(&base_, b); |
| + swap(&offset_, o); |
| + swap(&scale_, s); |
| + } |
| + |
| + private: |
| + template <class T> void swap(T* a, T* b) { |
| + T c(*a); |
| + *a = *b; |
| + *b = c; |
| + } |
| + |
| + HValue* base_; |
| + int offset_; |
| + int scale_; |
| +}; |
| + |
| + |
| +class RangeEvaluationContext BASE_EMBEDDED { |
| + public: |
| + RangeEvaluationContext(HValue* value, HValue* upper); |
| + |
| + HValue* lower_bound() { return lower_bound_; } |
| + HValue* lower_bound_guarantee() { return lower_bound_guarantee_; } |
| + HValue* candidate() { return candidate_; } |
| + HValue* upper_bound() { return upper_bound_; } |
| + HValue* upper_bound_guarantee() { return upper_bound_guarantee_; } |
| + int offset() { return offset_; } |
| + int scale() { return scale_; } |
| + |
| + bool is_range_satisfied() { |
| + return lower_bound_guarantee() != NULL && upper_bound_guarantee() != NULL; |
| + } |
| + |
| + void set_lower_bound_guarantee(HValue* guarantee) { |
| + lower_bound_guarantee_ = ConvertGuarantee(guarantee); |
| + } |
| + void set_upper_bound_guarantee(HValue* guarantee) { |
| + upper_bound_guarantee_ = ConvertGuarantee(guarantee); |
| + } |
| + |
| + void swap_candidate(DecompositionResult* other_candicate) { |
| + other_candicate->SwapValues(&candidate_, &offset_, &scale_); |
| + } |
| + |
| + private: |
| + HValue* ConvertGuarantee(HValue* guarantee); |
| + |
| + HValue* lower_bound_; |
| + HValue* lower_bound_guarantee_; |
| + HValue* candidate_; |
| + HValue* upper_bound_; |
| + HValue* upper_bound_guarantee_; |
| + int offset_; |
| + int scale_; |
| +}; |
| + |
| + |
| typedef EnumSet<GVNFlag> GVNFlagSet; |
| @@ -973,25 +1091,32 @@ 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 IsRelationTrue(NumericRelation relation, |
| + HValue* other, |
| + int offset = 0, |
| + int scale = 0); |
| - bool result = IsRelationTrueInternal(relation, other) || |
| - other->IsRelationTrueInternal(relation.Reversed(), this); |
| - if (!result) { |
| - HValue* redefined = RedefinedOperand(); |
| - if (redefined != NULL) { |
| - result = redefined->IsRelationTrue(relation, other); |
| - } |
| + bool TryGuaranteeRange(HValue* upper_bound); |
| + virtual bool TryDecompose(DecompositionResult* decomposition) { |
| + if (RedefinedOperand() != NULL) { |
| + return RedefinedOperand()->TryDecompose(decomposition); |
| + } else { |
| + return false; |
| } |
| - return result; |
| } |
| protected: |
| + void TryGuaranteeRangeRecursive(RangeEvaluationContext* context); |
| + |
| + enum RangeGuaranteeDirection { |
| + DIRECTION_NONE = 0, |
| + DIRECTION_UPPER = 1, |
| + DIRECTION_LOWER = 2, |
| + DIRECTION_BOTH = DIRECTION_UPPER|DIRECTION_LOWER |
|
Jakob Kummerow
2013/03/14 16:16:32
nit: spaces around '|'
|
| + }; |
| + virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) {} |
| + virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context) {} |
| + |
| // This function must be overridden for instructions with flag kUseGVN, to |
| // compare the non-Operand parts of the instruction. |
| virtual bool DataEquals(HValue* other) { |
| @@ -1055,7 +1180,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) { |
| + // Returns true if it is guaranteed that: |
| + // ((this + offset) >> scale) relation other |
| + virtual bool IsRelationTrueInternal(NumericRelation relation, |
| + HValue* other, |
| + int offset = 0, |
| + int scale = 0) { |
| return false; |
| } |
| @@ -1304,9 +1434,11 @@ class HNumericConstraint : public HTemplateInstruction<2> { |
| virtual void PrintDataTo(StringStream* stream); |
| virtual bool IsRelationTrueInternal(NumericRelation other_relation, |
| - HValue* other_related_value) { |
| + HValue* other_related_value, |
| + int offset = 0, |
| + int scale = 0) { |
| if (related_value() == other_related_value) { |
| - return relation().Implies(other_relation); |
| + return relation().CompoundImplies(other_relation, offset, scale); |
| } else { |
| return false; |
| } |
| @@ -1321,7 +1453,6 @@ class HNumericConstraint : public HTemplateInstruction<2> { |
| : relation_(relation) { |
| SetOperandAt(0, constrained_value); |
| SetOperandAt(1, related_value); |
| - set_representation(constrained_value->representation()); |
| } |
| NumericRelation relation_; |
| @@ -2959,7 +3090,10 @@ class HPhi: public HValue { |
| inputs_[index] = value; |
| } |
| - virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other); |
| + virtual bool IsRelationTrueInternal(NumericRelation relation, |
| + HValue* other, |
| + int offset = 0, |
| + int scale = 0); |
| private: |
| ZoneList<HValue*> inputs_; |
| @@ -2991,9 +3125,11 @@ class HInductionVariableAnnotation : public HUnaryOperation { |
| virtual void PrintDataTo(StringStream* stream); |
| virtual bool IsRelationTrueInternal(NumericRelation other_relation, |
| - HValue* other_related_value) { |
| + HValue* other_related_value, |
| + int offset = 0, |
| + int scale = 0) { |
| if (induction_base() == other_related_value) { |
| - return relation().Implies(other_relation); |
| + return relation().CompoundImplies(other_relation, offset, scale); |
| } else { |
| return false; |
| } |
| @@ -3007,7 +3143,6 @@ class HInductionVariableAnnotation : public HUnaryOperation { |
| int operand_index) |
| : HUnaryOperation(phi), |
| phi_(phi), relation_(relation), operand_index_(operand_index) { |
| - set_representation(phi->representation()); |
| } |
| // We need to store the phi both here and in the instruction operand because |
| @@ -3382,6 +3517,9 @@ enum BoundsCheckKeyMode { |
| }; |
| +class HBoundsCheckBaseIndexInformation; |
| + |
| + |
| class HBoundsCheck: public HTemplateInstruction<2> { |
| public: |
| // Normally HBoundsCheck should be created using the |
| @@ -3393,7 +3531,9 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
| HValue* length, |
| BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY, |
| Representation r = Representation::None()) |
| - : key_mode_(key_mode), skip_check_(false) { |
| + : key_mode_(key_mode), skip_check_(false), |
| + base_(NULL), offset_(0), scale_(0), |
| + responsibility_direction_(DIRECTION_NONE) { |
| SetOperandAt(0, index); |
| SetOperandAt(1, length); |
| if (r.IsNone()) { |
| @@ -3410,6 +3550,33 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
| bool skip_check() { return skip_check_; } |
| void set_skip_check(bool skip_check) { skip_check_ = skip_check; } |
| + HValue* base() { return base_; } |
| + int offset() { return offset_; } |
| + int scale() { return scale_; } |
| + bool index_can_increase() { |
| + return (responsibility_direction_ & DIRECTION_LOWER) == 0; |
| + } |
| + bool index_can_decrease() { |
| + return (responsibility_direction_ & DIRECTION_UPPER) == 0; |
| + } |
| + |
| + void ApplyIndexChange(); |
| + bool DetectCompoundIndex() { |
| + ASSERT(base() == NULL); |
| + |
| + DecompositionResult decomposition; |
| + if (index()->TryDecompose(&decomposition)) { |
| + base_ = decomposition.base(); |
| + offset_ = decomposition.offset(); |
| + scale_ = decomposition.scale(); |
| + return true; |
| + } else { |
| + base_ = index(); |
| + offset_ = 0; |
| + scale_ = 0; |
| + return false; |
| + } |
| + } |
| virtual Representation RequiredInputRepresentation(int arg_index) { |
| return representation(); |
| @@ -3419,7 +3586,9 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
| } |
| virtual bool IsRelationTrueInternal(NumericRelation relation, |
| - HValue* related_value); |
| + HValue* related_value, |
| + int offset = 0, |
| + int scale = 0); |
| virtual void PrintDataTo(StringStream* stream); |
| virtual void InferRepresentation(HInferRepresentation* h_infer); |
| @@ -3434,9 +3603,61 @@ class HBoundsCheck: public HTemplateInstruction<2> { |
| DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) |
| protected: |
| + friend class HBoundsCheckBaseIndexInformation; |
| + |
| + virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) { |
| + responsibility_direction_ = static_cast<RangeGuaranteeDirection>( |
| + responsibility_direction_ | direction); |
| + } |
| + |
| virtual bool DataEquals(HValue* other) { return true; } |
| + virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context); |
| BoundsCheckKeyMode key_mode_; |
| bool skip_check_; |
| + HValue* base_; |
| + int offset_; |
| + int scale_; |
| + RangeGuaranteeDirection responsibility_direction_; |
| +}; |
| + |
| + |
| +class HBoundsCheckBaseIndexInformation: public HTemplateInstruction<2> { |
| + public: |
| + explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) { |
| + DecompositionResult decomposition; |
| + if (check->index()->TryDecompose(&decomposition)) { |
| + SetOperandAt(0, decomposition.base()); |
| + SetOperandAt(1, check); |
| + } else { |
| + UNREACHABLE(); |
| + } |
| + } |
| + |
| + HValue* base_index() { return OperandAt(0); } |
| + HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); } |
| + |
| + DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation) |
| + |
| + virtual Representation RequiredInputRepresentation(int arg_index) { |
| + return representation(); |
| + } |
| + |
| + virtual bool IsRelationTrueInternal(NumericRelation relation, |
| + HValue* related_value, |
| + int offset = 0, |
| + int scale = 0); |
| + virtual void PrintDataTo(StringStream* stream); |
| + |
| + virtual int RedefinedOperandIndex() { return 0; } |
| + virtual bool IsPurelyInformativeDefinition() { return true; } |
| + |
| + protected: |
| + virtual void SetResponsibilityForRange(RangeGuaranteeDirection direction) { |
| + bounds_check()->SetResponsibilityForRange(direction); |
| + } |
| + virtual void TryGuaranteeRangeChanging(RangeEvaluationContext* context) { |
| + bounds_check()->TryGuaranteeRangeChanging(context); |
| + } |
| }; |
| @@ -4012,21 +4233,16 @@ class HAdd: public HArithmeticBinaryOperation { |
| virtual HValue* Canonicalize(); |
| - virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
| - HValue* base = NULL; |
| - int32_t offset = 0; |
| + virtual bool TryDecompose(DecompositionResult* decomposition) { |
| if (left()->IsInteger32Constant()) { |
| - base = right(); |
| - offset = left()->GetInteger32Constant(); |
| + decomposition->Apply(right(), left()->GetInteger32Constant()); |
| + return true; |
| } else if (right()->IsInteger32Constant()) { |
| - base = left(); |
| - offset = right()->GetInteger32Constant(); |
| + decomposition->Apply(left(), right()->GetInteger32Constant()); |
| + return true; |
| } else { |
| return false; |
| } |
| - |
| - return relation.IsExtendable(offset) |
| - ? base->IsRelationTrue(relation, other) : false; |
| } |
| DECLARE_CONCRETE_INSTRUCTION(Add) |
| @@ -4054,12 +4270,10 @@ class HSub: public HArithmeticBinaryOperation { |
| HValue* left, |
| HValue* right); |
| - virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
| + virtual bool TryDecompose(DecompositionResult* decomposition) { |
| if (right()->IsInteger32Constant()) { |
| - HValue* base = left(); |
| - int32_t offset = right()->GetInteger32Constant(); |
| - return relation.IsExtendable(-offset) |
| - ? base->IsRelationTrue(relation, other) : false; |
| + decomposition->Apply(left(), -right()->GetInteger32Constant()); |
| + return true; |
| } else { |
| return false; |
| } |
| @@ -4299,6 +4513,18 @@ class HSar: public HBitwiseBinaryOperation { |
| virtual Range* InferRange(Zone* zone); |
| + virtual bool TryDecompose(DecompositionResult* decomposition) { |
|
Jakob Kummerow
2013/03/14 16:16:32
Shouldn't we make the same change to HShr too?
|
| + if (right()->IsInteger32Constant()) { |
| + if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { |
| + // This is intended to look for HAdd and HSub, to handle compounds |
| + // like ((base = offset) >> scale) with one single decomposition. |
|
Jakob Kummerow
2013/03/14 16:16:32
nit: s/=/+/
|
| + left()->TryDecompose(decomposition); |
| + return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| static HInstruction* NewHSar(Zone* zone, |
| HValue* context, |
| HValue* left, |