}
+LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
+ HBoundsCheckBaseIndexInformation* instr) {
+ UNREACHABLE();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
// The control instruction marking the end of a block that completed
// abruptly (e.g., threw an exception). There is nothing specific to do.
}
+// 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;
}
+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;
}
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]");
}
}
+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 ");
}
-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);
// 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;
}
V(BitNot) \
V(BlockEntry) \
V(BoundsCheck) \
+ V(BoundsCheckBaseIndexInformation) \
V(Branch) \
V(CallConstantFunction) \
V(CallFunction) \
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* other_base, int other_offset, int other_scale = 0) {
+ if (base_ == NULL) {
+ base_ = other_base;
+ offset_ = other_offset;
+ scale_ = other_scale;
+ return true;
+ } else {
+ if (scale_ == 0) {
+ base_ = other_base;
+ offset_ += other_offset;
+ scale_ = other_scale;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
+ swap(&base_, other_base);
+ swap(&offset_, other_offset);
+ swap(&scale_, other_scale);
+ }
+
+ 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;
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
+ };
+ 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) {
// 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;
}
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;
}
: relation_(relation) {
SetOperandAt(0, constrained_value);
SetOperandAt(1, related_value);
- set_representation(constrained_value->representation());
}
NumericRelation relation_;
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_;
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;
}
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
};
+class HBoundsCheckBaseIndexInformation;
+
+
class HBoundsCheck: public HTemplateInstruction<2> {
public:
// Normally HBoundsCheck should be created using the
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()) {
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();
}
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);
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);
+ }
};
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)
virtual HValue* Canonicalize();
- 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;
}
HValue* left,
HValue* right);
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ 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.
+ left()->TryDecompose(decomposition);
+ return true;
+ }
+ }
+ return false;
+ }
+
virtual Range* InferRange(Zone* zone);
DECLARE_CONCRETE_INSTRUCTION(Shr)
HValue* left,
HValue* right);
+ virtual bool TryDecompose(DecompositionResult* decomposition) {
+ 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.
+ left()->TryDecompose(decomposition);
+ return true;
+ }
+ }
+ return false;
+ }
+
virtual Range* InferRange(Zone* zone);
DECLARE_CONCRETE_INSTRUCTION(Sar)
}
+HConstant* HGraph::GetInvalidContext() {
+ return GetConstantInt32(&constant_invalid_context_, 0xFFFFC0C7);
+}
+
+
HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id)
: builder_(builder),
finished_(false),
for (int i = 0; i < block->dominated_blocks()->length(); ++i) {
SetupInformativeDefinitionsRecursively(block->dominated_blocks()->at(i));
}
+
+ for (HInstruction* i = block->first(); i != NULL; i = i->next()) {
+ if (i->IsBoundsCheck()) {
+ HBoundsCheck* check = HBoundsCheck::cast(i);
+ check->ApplyIndexChange();
+ }
+ }
}
HConstant* GetConstantTrue();
HConstant* GetConstantFalse();
HConstant* GetConstantHole();
+ HConstant* GetInvalidContext();
HBasicBlock* CreateBasicBlock();
HArgumentsObject* GetArgumentsObject() const {
SetOncePointer<HConstant> constant_true_;
SetOncePointer<HConstant> constant_false_;
SetOncePointer<HConstant> constant_the_hole_;
+ SetOncePointer<HConstant> constant_invalid_context_;
SetOncePointer<HArgumentsObject> arguments_object_;
SetOncePointer<HBasicBlock> osr_loop_entry_;
}
+LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
+ HBoundsCheckBaseIndexInformation* instr) {
+ UNREACHABLE();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
// The control instruction marking the end of a block that completed
// abruptly (e.g., threw an exception). There is nothing specific to do.
}
+LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
+ HBoundsCheckBaseIndexInformation* instr) {
+ UNREACHABLE();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
// The control instruction marking the end of a block that completed
// abruptly (e.g., threw an exception). There is nothing specific to do.
}
+LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
+ HBoundsCheckBaseIndexInformation* instr) {
+ UNREACHABLE();
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
// The control instruction marking the end of a block that completed
// abruptly (e.g., threw an exception). There is nothing specific to do.
assertEquals(12, result_phi);
+// A test for recursive decomposition
+var data_composition_long = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+var data_composition_short = [0, 1, 2, 3, 4];
+function test_composition(a, base0, check) {
+ var base1 = ((base0 + 2));
+ var base2 = ((base1 + 8) >> 2);
+ var base3 = ((base2 + 6) >> 1);
+ var base4 = ((base3 + 8) >> 1);
+
+ var result = 0;
+ result += a[base0];
+ result += a[base1];
+ result += a[base2];
+ result += a[base3];
+ result += a[base4];
+
+ return result;
+}
+var result_composition = 0;
+result_composition = test_composition(data_composition_long, 2);
+assertEquals(19, result_composition);
+result_composition = test_composition(data_composition_long, 2);
+assertEquals(19, result_composition);
+%OptimizeFunctionOnNextCall(test_composition);
+result_composition = test_composition(data_composition_short, 2);
+assertEquals(NaN, result_composition);
+
+
gc();