Index: src/hydrogen-instructions.cc |
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc |
index 20e41bc79a72f80b4a41f326cf0cc6e345711992..2aab3696519f242d40280aedfe199da82e68c63e 100644 |
--- a/src/hydrogen-instructions.cc |
+++ b/src/hydrogen-instructions.cc |
@@ -167,6 +167,116 @@ 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. |
+ if (scale == 0 && |
+ // TODO(mmassi): do we need the full, recursive IsRelationTrue? |
+ other->IsRelationTrueInternal(relation.Reversed(), this, -offset)) { |
+ return true; |
+ } |
+ |
+ // Try decomposition (but do not accept scaled compounds). |
+ DecompositionResult decomposition; |
+ if (TryDecompose(&decomposition) && |
+ decomposition.scale() == 0 && |
+ decomposition.base()->IsRelationTrue(relation, other, |
+ offset + decomposition.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_bound_guarantee()->SetResponsibilityForRange(DIRECTION_LOWER); |
+ context.upper_bound_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->lower_bound_guarantee() == NULL) { |
+ if (IsRelationTrueInternal(NumericRelation::Ge(), context->lower_bound(), |
+ context->offset(), context->scale())) { |
+ context->set_lower_bound_guarantee(this); |
+ } |
+ } |
+ |
+ // Check if we already know that this value satisfies the upper bound. |
+ if (context->upper_bound_guarantee() == NULL) { |
+ 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_bound_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. |
+ DecompositionResult decomposition; |
+ if (TryDecompose(&decomposition)) { |
+ context->swap_candidate(&decomposition); |
+ context->candidate()->TryGuaranteeRangeRecursive(context); |
+ context->swap_candidate(&decomposition); |
+ } |
+ 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_bound_guarantee_(NULL), |
+ candidate_(value), |
+ upper_bound_(upper), |
+ upper_bound_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; |
@@ -888,25 +998,115 @@ 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->lower_bound_guarantee() != NULL && |
+ context->lower_bound_guarantee() != this && |
+ context->lower_bound_guarantee()->block() != block() && |
+ offset() < context->offset() && |
+ index_can_increase() && |
+ context->upper_bound_guarantee() == NULL) { |
+ offset_ = context->offset(); |
+ SetResponsibilityForRange(DIRECTION_UPPER); |
+ context->set_upper_bound_guarantee(this); |
+ } else if (context->upper_bound_guarantee() != NULL && |
+ context->upper_bound_guarantee() != this && |
+ context->upper_bound_guarantee()->block() != block() && |
+ offset() > context->offset() && |
+ index_can_decrease() && |
+ context->lower_bound_guarantee() == NULL) { |
+ offset_ = context->offset(); |
+ SetResponsibilityForRange(DIRECTION_LOWER); |
+ context->set_lower_bound_guarantee(this); |
+ } |
+} |
+ |
+ |
+void HBoundsCheck::ApplyIndexChange() { |
+ if (skip_check()) return; |
+ |
+ DecompositionResult decomposition; |
+ bool index_is_decomposable = index()->TryDecompose(&decomposition); |
+ if (index_is_decomposable) { |
+ ASSERT(decomposition.base() == base()); |
+ if (decomposition.offset() == offset() && |
+ decomposition.scale() == scale()) return; |
+ } else { |
+ return; |
+ } |
+ |
+ ReplaceAllUsesWith(index()); |
+ |
+ HValue* current_index = decomposition.base(); |
+ int actual_offset = decomposition.offset() + offset(); |
+ int actual_scale = decomposition.scale() + scale(); |
+ |
+ if (actual_offset != 0) { |
+ HConstant* add_offset = new(block()->graph()->zone()) HConstant( |
+ actual_offset, index()->representation()); |
+ add_offset->InsertBefore(this); |
+ HInstruction* add = HAdd::New(block()->graph()->zone(), |
+ 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); |
+ HInstruction* sar = HSar::New(block()->graph()->zone(), |
+ 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_array_bounds_checks_elimination) { |
+ 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); |
+ } |
} |
} |
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; |
} |
@@ -917,6 +1117,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]"); |
} |
@@ -946,6 +1155,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 "); |
@@ -1611,7 +1847,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); |
@@ -1620,7 +1859,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; |
} |