Index: src/hydrogen-instructions.cc |
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc |
index 52eada41f5df8213abaaa369fcd8aa1f9d549ea5..34a59848579e7ee995ebe72688f238280b4bf510 100644 |
--- a/src/hydrogen-instructions.cc |
+++ b/src/hydrogen-instructions.cc |
@@ -160,6 +160,122 @@ void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) { |
} |
+bool HValue::TryGuaranteeRange(HValue* upper_bound) { |
+ RangeEvaluationContext context = RangeEvaluationContext(this, upper_bound); |
+ TryGuaranteeRangeRecursive(&context); |
+ return context.RangeSatisfied(); |
+} |
+ |
+ |
+void HValue::TryGuaranteeRangeRecursive(RangeEvaluationContext* context) { |
+ |
+ if (FLAG_log_abcd) { |
+ PrintF(" +++ TryGuaranteeRangeRecursive("); |
+ SimplyPrint(); |
+ PrintF(") {[LOWER "); |
+ if (context->lower_check_satisfied()) { |
+ context->lower_check_guarantee()->SimplyPrint(); |
+ } else { |
+ PrintF("NULL"); |
+ } |
+ PrintF("] "); |
+ context->lower_bound()->SimplyPrint(); |
+ PrintF(" <= ((x + %d) >> %d) ", context->offset(), context->scale()); |
+ context->upper_bound()->SimplyPrint(); |
+ PrintF(" [UPPER "); |
+ if (context->upper_check_satisfied()) { |
+ context->upper_check_guarantee()->SimplyPrint(); |
+ } else { |
+ PrintF("NULL"); |
+ } |
+ PrintF("]}\n"); |
+ } |
+ |
+ |
+ // Try to satisfy the lower bound on this value |
Jakob Kummerow
2013/03/11 11:55:02
better comment:
// Check if we already know that t
|
+ if (!context->lower_check_satisfied()) { |
+ if (IsRelationTrueInternal(NumericRelation::Ge(), context->lower_bound(), |
+ context->offset(), context->scale())) { |
+ |
+ if (FLAG_log_abcd) |
+ PrintF(" ___ TryGuaranteeRangeRecursive(LOWER TRUE)\n"); |
+ |
+ context->set_lower_check_guarantee(this); |
+ } |
+ } |
+ |
+ // Try to satisfy the upper bound on this value |
Jakob Kummerow
2013/03/11 11:55:02
better comment:
// Check if we already know that t
|
+ if (!context->upper_check_satisfied()) { |
+ if (IsRelationTrueInternal(NumericRelation::Lt(), context->upper_bound(), |
+ context->offset(), context->scale()) || |
+ (context->scale() == 0 && |
+ context->upper_bound()->IsRelationTrue(NumericRelation::Gt(), |
+ this, -context->offset()))) { |
+ |
+ if (FLAG_log_abcd) |
+ PrintF(" ___ TryGuaranteeRangeRecursive(UPPER TRUE)\n"); |
+ |
+ context->set_upper_check_guarantee(this); |
+ } |
+ } |
+ |
+ if (context->RangeSatisfied()) return; |
+ |
+ // See if our RedefinedOperand() satisfies the constraints. |
+ if (RedefinedOperand() != NULL) { |
+ RedefinedOperand()->TryGuaranteeRangeRecursive(context); |
+ } |
+ if (context->RangeSatisfied()) return; |
+ |
+ // See if the constraints can be satisfied by decomposition. |
Jakob Kummerow
2013/03/11 11:55:02
Why does this need to happen in the recursive call
Massi
2013/03/13 15:58:14
Because every definition of this value could be de
Jakob Kummerow
2013/03/14 12:50:08
OK, I see.
|
+ HValue* base = NULL; |
+ int offset = context->offset(); |
+ int scale = context->scale(); |
+ if (context->origin()->TryDecompose(&base, &offset, &scale)) { |
+ context->swap_origin(base, offset, scale); |
+ |
+ if (FLAG_log_abcd) |
+ PrintF(" ___ TryGuaranteeRangeRecursive(DECOMPOSE START)\n"); |
+ |
+ context->origin()->TryGuaranteeRangeRecursive(context); |
+ |
+ if (FLAG_log_abcd) |
+ PrintF(" ___ TryGuaranteeRangeRecursive(DECOMPOSE END [%s])\n", |
+ context->RangeSatisfied() ? "!" : "x"); |
+ |
+ context->swap_origin(base, offset, scale); |
+ } |
+ if (context->RangeSatisfied()) return; |
+ |
+ // Try to modify this to satisfy the constraint. |
+ TryGuaranteeRangeInner(context); |
+ |
+ if (FLAG_log_abcd) { |
+ PrintF(" >>> TryGuaranteeRangeRecursive("); |
+ SimplyPrint(); |
+ PrintF("): %s\n", context->RangeSatisfied() ? "TRUE" : "FALSE"); |
+ } |
+} |
+ |
+ |
+HValue::RangeEvaluationContext::RangeEvaluationContext( |
+ HValue* value, HValue* upper) |
Jakob Kummerow
2013/03/11 11:55:02
for method/function declarations (as opposed to ca
|
+ : lower_bound_(upper->block()->graph()->GetConstant0()), |
+ lower_check_guarantee_(NULL), |
+ origin_(value), |
+ upper_bound_(upper), |
+ upper_check_guarantee_(NULL), |
+ offset_(0), scale_(0) { |
Jakob Kummerow
2013/03/11 11:55:02
let's give each initializer its own line.
|
+} |
+ |
+ |
+HValue* HValue::RangeEvaluationContext::ConvertGuarantee(HValue* guarantee) { |
Jakob Kummerow
2013/03/11 11:55:02
This method is simple enough to live in the .h fil
Massi
2013/03/13 15:58:14
But it needs to access HBoundsCheckBaseIndexInform
|
+ return guarantee->IsBoundsCheckBaseIndexInformation() |
+ ? HBoundsCheckBaseIndexInformation::cast(guarantee)->bounds_check() |
+ : guarantee; |
+} |
+ |
+ |
static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { |
if (result > kMaxInt) { |
*overflow = true; |
@@ -782,6 +898,17 @@ void HInstruction::Verify() { |
cur = cur->previous(); |
} |
// Must reach other operand in the same block! |
+ |
+ if (cur != other_operand) { |
+ PrintF("\n !!! !!! !!! !!! !!! ASSERT([BLOCK %d]", |
+ other_operand->block()->block_id()); |
+ other_operand->SimplyPrint(); |
+ PrintF(" used in index %d does not dominate [BLOCK %d]", |
+ i, block()->block_id()); |
+ SimplyPrint(); |
+ PrintF(")\n"); |
+ } |
+ |
ASSERT(cur == other_operand); |
} |
} else { |
@@ -885,25 +1012,188 @@ void HBinaryCall::PrintDataTo(StringStream* stream) { |
} |
+void HBoundsCheck::TryGuaranteeRangeInner(RangeEvaluationContext* context) { |
+ if (FLAG_log_abcd) { |
+ PrintF(" +++ HBoundsCheck::TryGuaranteeRangeInner("); |
+ SimplyPrint(); |
+ PrintF(" [LOWER "); |
+ if (context->lower_check_satisfied()) { |
+ context->lower_check_guarantee()->SimplyPrint(); |
+ } else { |
+ PrintF("NULL"); |
+ } |
+ PrintF("] [UPPER "); |
+ if (context->upper_check_satisfied()) { |
+ context->upper_check_guarantee()->SimplyPrint(); |
+ } else { |
+ PrintF("NULL"); |
+ } |
+ PrintF("])\n"); |
+ } |
+ |
+ if (context->origin()->ActualValue() == base()->ActualValue() && |
Jakob Kummerow
2013/03/11 11:55:02
nit: you can avoid one level of nested conditions
|
+ context->scale() >= scale()) { |
+ if (index_has_not_been_changed()) { |
+ if (offset() < context->offset()) { |
+ change_direction_ = 1; |
Jakob Kummerow
2013/03/11 11:55:02
It doesn't seem right that we're always setting ch
|
+ } else if (offset() > context->offset()) { |
+ change_direction_ = -1; |
+ } |
+ } |
+ |
+ if (context->upper_bound() == length() && |
+ context->lower_check_satisfied() && |
+ context->lower_check_guarantee() != this && |
+ index_can_increase() && |
+ !context->upper_check_satisfied()) { |
+ if (offset() < context->offset()) { |
Jakob Kummerow
2013/03/11 11:55:02
Since this condition doesn't have an else-branch,
|
+ |
+ if (FLAG_log_abcd) |
+ PrintF(" ___ HBoundsCheck::TryGuaranteeRangeInner(%s%d CHANGE UPPER(base %s%d[%s%d][%d]), offset %d (was %d), scale %d)\n", |
+ representation().Mnemonic(), id(), |
+ base()->representation().Mnemonic(), base()->id(), |
+ base()->ActualValue()->representation().Mnemonic(), base()->ActualValue()->id(), |
+ change_direction_, context->offset(), offset(), scale()); |
+ |
+ offset_ = context->offset(); |
+ change_direction_ = 1; |
Jakob Kummerow
2013/03/11 11:55:02
To make it more obvious that this is closely relat
|
+ context->set_upper_check_guarantee(this); |
+ } |
+ } else if (context->upper_check_satisfied() && |
+ context->upper_check_guarantee() != this && |
+ index_can_decrease() && |
+ !context->lower_check_satisfied()) { |
+ if (offset() > context->offset()) { |
+ |
+ if (FLAG_log_abcd) |
+ PrintF(" ___ HBoundsCheck::TryGuaranteeRangeInner(%s%d CHANGE LOWER(base %s%d[%s%d][%d]), offset %d (was %d), scale %d)\n", |
+ representation().Mnemonic(), id(), |
+ base()->representation().Mnemonic(), base()->id(), |
+ base()->ActualValue()->representation().Mnemonic(), base()->ActualValue()->id(), |
+ change_direction_, context->offset(), offset(), scale()); |
+ |
+ offset_ = context->offset(); |
+ change_direction_ = -1; |
+ context->set_lower_check_guarantee(this); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+void HBoundsCheck::ApplyIndexChange() { |
+ if (HasOriginalIndex() || skip_check()) return; |
Jakob Kummerow
2013/03/11 11:55:02
HasOriginalIndex() potentially performs the "index
|
+ |
+ HValue* base_index = NULL; |
Jakob Kummerow
2013/03/11 11:55:02
I think you mean index_base, index_offset, index_s
|
+ int base_offset = 0; |
+ int base_scale = 0; |
+ if (!index()->TryDecompose(&base_index, &base_offset, &base_scale)) return; |
+ |
+ ReplaceAllUsesWith(index()); |
+ |
+ HValue* current_index = base_index; |
+ int actual_offset = base_offset + offset(); |
+ int actual_scale = base_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; |
+ } |
+ |
+ |
+ if (FLAG_log_abcd) |
+ PrintF("\n !!! !!! !!! HBoundsCheck::ApplyIndexChange(%s%d, index %s%d becomes ((%s%d + %d) >> %d)\n", |
+ representation().Mnemonic(), id(), |
+ index()->representation().Mnemonic(), index()->id(), |
+ current_index->representation().Mnemonic(), current_index->id(), |
+ offset(), scale()); |
+ |
+ SetOperandAt(0, current_index); |
+ |
+ PrintF(" "); |
+ |
+ base_ = NULL; |
Jakob Kummerow
2013/03/11 11:55:02
Is it necessary to do this cleanup?
Massi
2013/03/13 15:58:14
In principle, no, but I don't like leaving meaning
Jakob Kummerow
2013/03/14 12:50:08
I disagree with this reasoning. Resetting those va
|
+ offset_ = 0; |
+ scale_ = 0; |
+ change_direction_ = 0; |
+} |
+ |
+ |
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 (FLAG_log_abcd) { |
+ PrintF("\n +++ >>> >>> >>> HBoundsCheck::AddInformativeDefinitions[BLOCK %d](", |
+ block()->block_id()); |
+ SimplyPrint(); |
+ PrintF(") CHANGE FOR LENGTH %s%d\n", |
+ length()->representation().Mnemonic(), length()->id()); |
+ |
+ if (index()->TryGuaranteeRange(length())) { |
Jakob Kummerow
2013/03/11 11:55:02
This should *not* be inside the if(FLAG_log_abcd)
|
+ set_skip_check(true); |
+ } |
+ } |
+ |
+ if (DetectCompoundIndex()) { |
+ HBoundsCheckBaseIndexInformation* base_index_info = |
+ new(block()->graph()->zone()) |
+ HBoundsCheckBaseIndexInformation(this); |
+ base_index_info->InsertAfter(this); |
+ } |
+ |
+ if (FLAG_log_abcd) { |
+ PrintF(" +++ <<< <<< <<< HBoundsCheck::AddInformativeDefinitions[BLOCK %d](", |
+ block()->block_id()); |
+ SimplyPrint(); |
+ if (base() != index()) { |
+ PrintF("{base %s%d (actually %s%d)}", |
+ base()->representation().Mnemonic(), base()->id(), |
+ base()->ActualValue()->representation().Mnemonic(), base()->ActualValue()->id()); |
+ } |
+ PrintF(") LENGTH %s%d CHANGE %s\n", |
+ length()->representation().Mnemonic(), length()->id(), |
+ skip_check() ? "TRUE" : "FALSE"); |
+ } |
+ |
+ } 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 +1204,15 @@ void HBoundsCheck::PrintDataTo(StringStream* stream) { |
index()->PrintNameTo(stream); |
stream->Add(" "); |
length()->PrintNameTo(stream); |
+ if (base() != NULL && (offset() != 0 || scale() != 0)) { |
+ stream->Add("base: (("); |
Jakob Kummerow
2013/03/11 11:55:02
nit: you probably want to print a space first, i.e
|
+ if (base() != index()) { |
+ index()->PrintNameTo(stream); |
+ } else { |
+ stream->Add("index"); |
+ } |
+ stream->Add(" + %d) >> %d)", offset(), scale()); |
+ } |
if (skip_check()) { |
stream->Add(" [DISABLED]"); |
} |
@@ -941,6 +1240,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 +1930,8 @@ void HPhi::AddInformativeDefinitions() { |
} |
-bool HPhi::IsRelationTrueInternal(NumericRelation relation, HValue* other) { |
+bool HPhi::IsRelationTrueInternal( |
+ NumericRelation relation, HValue* other, int offset, int scale) { |
Jakob Kummerow
2013/03/11 11:55:02
for method/function declarations (as opposed to ca
|
if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false; |
SetFlag(kNumericConstraintEvaluationInProgress); |
@@ -1613,7 +1940,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; |
} |