Chromium Code Reviews| Index: src/hydrogen-instructions.cc |
| diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc |
| index 52eada41f5df8213abaaa369fcd8aa1f9d549ea5..342f4836c310fef65434ed5212ea230c95e772d0 100644 |
| --- a/src/hydrogen-instructions.cc |
| +++ b/src/hydrogen-instructions.cc |
| @@ -160,6 +160,117 @@ void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) { |
| } |
| +// This method is recursive but it is guaranteed to terminate because |
| +// RedefinedOperand() always dominates "this". |
| +bool HValue::IsRelationTrue(NumericRelation relation, |
| + HValue* other, |
| + int offset, |
| + int scale) { |
| + if (this == other) { |
| + return NumericRelation::Eq().Implies(relation); |
| + } |
| + |
| + // Test the direct relation. |
| + if (IsRelationTrueInternal(relation, other, offset, scale)) return true; |
| + |
| + // If scale is 0 try the reversed relation.. |
|
Jakob Kummerow
2013/03/14 12:50:09
nit: s/.././
Massi
2013/03/14 15:07:18
Done.
|
| + if (scale == 0 && |
| + // TODO(mmassi): do we need the full, recursive IsRelationTrue? |
| + other->IsRelationTrueInternal(relation.Reversed(), this, -offset)) { |
| + return true; |
| + } |
| + |
| + // Try decomposition. |
| + HValue* my_base = NULL; |
| + int my_offset = 0; |
| + int my_scale = 0; |
| + if (TryDecompose(&my_base, &my_offset, &my_scale) && my_scale == 0 && |
| + my_base->IsRelationTrue(relation, other, offset + my_offset, scale)) { |
| + return true; |
| + } |
| + |
| + // Pass the request to the redefined value. |
| + HValue* redefined = RedefinedOperand(); |
| + return redefined != NULL && redefined->IsRelationTrue(relation, other, |
| + offset, scale); |
| +} |
| + |
| + |
| +bool HValue::TryGuaranteeRange(HValue* upper_bound) { |
| + RangeEvaluationContext context = RangeEvaluationContext(this, upper_bound); |
| + TryGuaranteeRangeRecursive(&context); |
| + bool result = context.is_range_satisfied(); |
| + if (result) { |
| + context.lower_check_guarantee()->SetResponsibilityForRange(DIRECTION_LOWER); |
| + context.upper_check_guarantee()->SetResponsibilityForRange(DIRECTION_UPPER); |
| + } |
| + return result; |
| +} |
| + |
| + |
| +void HValue::TryGuaranteeRangeRecursive(RangeEvaluationContext* context) { |
| + // Check if we already know that this value satisfies the lower bound. |
| + if (!context->is_lower_bound_satisfied()) { |
| + if (IsRelationTrueInternal(NumericRelation::Ge(), context->lower_bound(), |
| + context->offset(), context->scale())) { |
| + context->set_lower_check_guarantee(this); |
| + } |
| + } |
| + |
| + // Check if we already know that this value satisfies the upper bound. |
| + if (!context->is_upper_bound_satisfied()) { |
| + if (IsRelationTrueInternal(NumericRelation::Lt(), context->upper_bound(), |
| + context->offset(), context->scale()) || |
| + (context->scale() == 0 && |
| + context->upper_bound()->IsRelationTrue(NumericRelation::Gt(), |
| + this, -context->offset()))) { |
| + context->set_upper_check_guarantee(this); |
| + } |
| + } |
| + |
| + if (context->is_range_satisfied()) return; |
| + |
| + // See if our RedefinedOperand() satisfies the constraints. |
| + if (RedefinedOperand() != NULL) { |
| + RedefinedOperand()->TryGuaranteeRangeRecursive(context); |
| + } |
| + if (context->is_range_satisfied()) return; |
| + |
| + // See if the constraints can be satisfied by decomposition. |
| + HValue* base = NULL; |
| + int offset = context->offset(); |
| + int scale = context->scale(); |
| + if (TryDecompose(&base, &offset, &scale)) { |
| + context->swap_candidate(&base, &offset, &scale); |
| + context->candidate()->TryGuaranteeRangeRecursive(context); |
| + context->swap_candidate(&base, &offset, &scale); |
| + } |
| + if (context->is_range_satisfied()) return; |
| + |
| + // Try to modify this to satisfy the constraint. |
| + |
| + TryGuaranteeRangeChanging(context); |
| +} |
| + |
| + |
| +RangeEvaluationContext::RangeEvaluationContext(HValue* value, HValue* upper) |
| + : lower_bound_(upper->block()->graph()->GetConstant0()), |
| + lower_check_guarantee_(NULL), |
| + candidate_(value), |
| + upper_bound_(upper), |
| + upper_check_guarantee_(NULL), |
| + offset_(0), |
| + scale_(0) { |
| +} |
| + |
| + |
| +HValue* RangeEvaluationContext::ConvertGuarantee(HValue* guarantee) { |
| + return guarantee->IsBoundsCheckBaseIndexInformation() |
| + ? HBoundsCheckBaseIndexInformation::cast(guarantee)->bounds_check() |
| + : guarantee; |
| +} |
| + |
| + |
| static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { |
| if (result > kMaxInt) { |
| *overflow = true; |
| @@ -885,25 +996,123 @@ void HBinaryCall::PrintDataTo(StringStream* stream) { |
| } |
| +void HBoundsCheck::TryGuaranteeRangeChanging(RangeEvaluationContext* context) { |
| + if (context->candidate()->ActualValue() != base()->ActualValue() || |
| + context->scale() < scale()) { |
| + return; |
| + } |
| + |
| + // TODO(mmassi) |
| + // Instead of checking for "same basic block" we should check for |
| + // "dominates and postdominates". |
| + if (context->upper_bound() == length() && |
| + context->is_lower_bound_satisfied() && |
| + context->lower_check_guarantee() != this && |
| + context->lower_check_guarantee()->block() != block() && |
| + offset() < context->offset() && |
| + index_can_increase() && |
| + !context->is_upper_bound_satisfied()) { |
| + offset_ = context->offset(); |
| + SetResponsibilityForRange(DIRECTION_UPPER); |
| + context->set_upper_check_guarantee(this); |
| + } else if (context->is_upper_bound_satisfied() && |
| + context->upper_check_guarantee() != this && |
| + context->upper_check_guarantee()->block() != block() && |
| + offset() > context->offset() && |
| + index_can_decrease() && |
| + !context->is_lower_bound_satisfied()) { |
| + offset_ = context->offset(); |
| + SetResponsibilityForRange(DIRECTION_LOWER); |
| + context->set_lower_check_guarantee(this); |
| + } |
| +} |
| + |
| + |
| +void HBoundsCheck::ApplyIndexChange() { |
| + if (skip_check()) return; |
| + |
| + HValue* index_base = NULL; |
| + int index_offset = 0; |
| + int index_scale = 0; |
| + bool index_is_decomposable = index()->TryDecompose( |
| + &index_base, &index_offset, &index_scale); |
| + if (index_is_decomposable) { |
| + ASSERT(index_base == base()); |
| + if (index_offset == offset() && index_scale == scale()) return; |
| + } else { |
| + return; |
| + } |
| + |
| + ReplaceAllUsesWith(index()); |
| + |
| + HValue* current_index = index_base; |
| + int actual_offset = index_offset + offset(); |
| + int actual_scale = index_scale + scale(); |
| + |
| + if (actual_offset != 0) { |
| + HConstant* add_offset = new(block()->graph()->zone()) HConstant( |
| + actual_offset, index()->representation()); |
| + add_offset->InsertBefore(this); |
| + HAdd* add = new(block()->graph()->zone()) HAdd( |
| + block()->graph()->GetInvalidContext(), current_index, add_offset); |
| + add->InsertBefore(this); |
| + add->AssumeRepresentation(index()->representation()); |
| + current_index = add; |
| + } |
| + |
| + if (actual_scale != 0) { |
| + HConstant* sar_scale = new(block()->graph()->zone()) HConstant( |
| + actual_scale, index()->representation()); |
| + sar_scale->InsertBefore(this); |
| + HSar* sar = new(block()->graph()->zone()) HSar( |
| + block()->graph()->GetInvalidContext(), current_index, sar_scale); |
| + sar->InsertBefore(this); |
| + sar->AssumeRepresentation(index()->representation()); |
| + current_index = sar; |
| + } |
| + |
| + SetOperandAt(0, current_index); |
| + |
| + base_ = NULL; |
| + offset_ = 0; |
| + scale_ = 0; |
| + responsibility_direction_ = DIRECTION_NONE; |
| +} |
| + |
| + |
| void HBoundsCheck::AddInformativeDefinitions() { |
| // TODO(mmassi): Executing this code during AddInformativeDefinitions |
| // is a hack. Move it to some other HPhase. |
| - if (index()->IsRelationTrue(NumericRelation::Ge(), |
| - block()->graph()->GetConstant0()) && |
| - index()->IsRelationTrue(NumericRelation::Lt(), length())) { |
| - set_skip_check(true); |
| + if (FLAG_new_abcd) { |
| + if (index()->TryGuaranteeRange(length())) { |
| + set_skip_check(true); |
| + } |
| + if (DetectCompoundIndex()) { |
| + HBoundsCheckBaseIndexInformation* base_index_info = |
| + new(block()->graph()->zone()) |
| + HBoundsCheckBaseIndexInformation(this); |
| + base_index_info->InsertAfter(this); |
| + } |
| + } else { |
| + if (index()->IsRelationTrue(NumericRelation::Ge(), |
| + block()->graph()->GetConstant0()) && |
| + index()->IsRelationTrue(NumericRelation::Lt(), length())) { |
| + set_skip_check(true); |
| + } |
| } |
| } |
| bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation, |
| - HValue* related_value) { |
| + HValue* related_value, |
| + int offset, |
| + int scale) { |
| if (related_value == length()) { |
| // A HBoundsCheck is smaller than the length it compared against. |
| - return NumericRelation::Lt().Implies(relation); |
| + return NumericRelation::Lt().CompoundImplies(relation, 0, 0, offset, scale); |
| } else if (related_value == block()->graph()->GetConstant0()) { |
| // A HBoundsCheck is greater than or equal to zero. |
| - return NumericRelation::Ge().Implies(relation); |
| + return NumericRelation::Ge().CompoundImplies(relation, 0, 0, offset, scale); |
| } else { |
| return false; |
| } |
| @@ -914,6 +1123,15 @@ void HBoundsCheck::PrintDataTo(StringStream* stream) { |
| index()->PrintNameTo(stream); |
| stream->Add(" "); |
| length()->PrintNameTo(stream); |
| + if (base() != NULL && (offset() != 0 || scale() != 0)) { |
| + stream->Add(" base: (("); |
| + if (base() != index()) { |
| + index()->PrintNameTo(stream); |
| + } else { |
| + stream->Add("index"); |
| + } |
| + stream->Add(" + %d) >> %d)", offset(), scale()); |
| + } |
| if (skip_check()) { |
| stream->Add(" [DISABLED]"); |
| } |
| @@ -941,6 +1159,33 @@ void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) { |
| } |
| +bool HBoundsCheckBaseIndexInformation::IsRelationTrueInternal( |
| + NumericRelation relation, |
| + HValue* related_value, |
| + int offset, |
| + int scale) { |
| + if (related_value == bounds_check()->length()) { |
| + return NumericRelation::Lt().CompoundImplies( |
| + relation, |
| + bounds_check()->offset(), bounds_check()->scale(), offset, scale); |
| + } else if (related_value == block()->graph()->GetConstant0()) { |
| + return NumericRelation::Ge().CompoundImplies( |
| + relation, |
| + bounds_check()->offset(), bounds_check()->scale(), offset, scale); |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| + |
| +void HBoundsCheckBaseIndexInformation::PrintDataTo(StringStream* stream) { |
| + stream->Add("base: "); |
| + base_index()->PrintNameTo(stream); |
| + stream->Add(", check: "); |
| + base_index()->PrintNameTo(stream); |
| +} |
| + |
| + |
| void HCallConstantFunction::PrintDataTo(StringStream* stream) { |
| if (IsApplyFunction()) { |
| stream->Add("optimized apply "); |
| @@ -1604,7 +1849,10 @@ void HPhi::AddInformativeDefinitions() { |
| } |
| -bool HPhi::IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
| +bool HPhi::IsRelationTrueInternal(NumericRelation relation, |
| + HValue* other, |
| + int offset, |
| + int scale) { |
| if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false; |
| SetFlag(kNumericConstraintEvaluationInProgress); |
| @@ -1613,7 +1861,7 @@ bool HPhi::IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
| // Skip OSR entry blocks |
| if (OperandAt(i)->block()->is_osr_entry()) continue; |
| - if (!OperandAt(i)->IsRelationTrue(relation, other)) { |
| + if (!OperandAt(i)->IsRelationTrue(relation, other, offset, scale)) { |
| result = false; |
| break; |
| } |