diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 208ca2115b..c7b4382a8d 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -1690,6 +1690,12 @@ LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { } +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = UseRegister(instr->length()); diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 2d4b82bf16..52eada41f5 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -843,6 +843,27 @@ void HNumericConstraint::PrintDataTo(StringStream* stream) { } +HInductionVariableAnnotation* HInductionVariableAnnotation::AddToGraph( + HPhi* phi, + NumericRelation relation, + int operand_index) { + HInductionVariableAnnotation* result = + new(phi->block()->zone()) HInductionVariableAnnotation(phi, relation, + operand_index); + result->InsertAfter(phi->block()->first()); + return result; +} + + +void HInductionVariableAnnotation::PrintDataTo(StringStream* stream) { + stream->Add("("); + RedefinedOperand()->PrintNameTo(stream); + stream->Add(" %s ", relation().Mnemonic()); + induction_base()->PrintNameTo(stream); + stream->Add(")"); +} + + void HDummyUse::PrintDataTo(StringStream* stream) { value()->PrintNameTo(stream); } @@ -1554,15 +1575,14 @@ Range* HMod::InferRange(Zone* zone) { void HPhi::AddInformativeDefinitions() { if (OperandCount() == 2) { + // If one of the operands is an OSR block give up (this cannot be an + // induction variable). + if (OperandAt(0)->block()->is_osr_entry() || + OperandAt(1)->block()->is_osr_entry()) return; + for (int operand_index = 0; operand_index < 2; operand_index++) { int other_operand_index = (operand_index + 1) % 2; - // Add an idef that "discards" the OSR entry block branch. - if (OperandAt(operand_index)->block()->is_osr_entry()) { - HNumericConstraint::AddToGraph( - this, NumericRelation::Eq(), OperandAt(other_operand_index)); - } - static NumericRelation relations[] = { NumericRelation::Ge(), NumericRelation::Le() @@ -1574,9 +1594,9 @@ void HPhi::AddInformativeDefinitions() { for (int relation_index = 0; relation_index < 2; relation_index++) { if (OperandAt(operand_index)->IsRelationTrue(relations[relation_index], this)) { - HNumericConstraint::AddToGraph(this, - relations[relation_index], - OperandAt(other_operand_index)); + HInductionVariableAnnotation::AddToGraph(this, + relations[relation_index], + other_operand_index); } } } @@ -1584,6 +1604,26 @@ void HPhi::AddInformativeDefinitions() { } +bool HPhi::IsRelationTrueInternal(NumericRelation relation, HValue* other) { + if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false; + + SetFlag(kNumericConstraintEvaluationInProgress); + bool result = true; + for (int i = 0; i < OperandCount(); i++) { + // Skip OSR entry blocks + if (OperandAt(i)->block()->is_osr_entry()) continue; + + if (!OperandAt(i)->IsRelationTrue(relation, other)) { + result = false; + break; + } + } + ClearFlag(kNumericConstraintEvaluationInProgress); + + return result; +} + + Range* HMathMinMax::InferRange(Zone* zone) { if (representation().IsInteger32()) { Range* a = left()->range(); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 64910c8d55..2d763d55f0 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -119,6 +119,7 @@ class LChunkBuilder; V(Goto) \ V(HasCachedArrayIndexAndBranch) \ V(HasInstanceTypeAndBranch) \ + V(InductionVariableAnnotation) \ V(In) \ V(InstanceOf) \ V(InstanceOfKnownGlobal) \ @@ -704,6 +705,9 @@ class HValue: public ZoneObject { // HGraph::ComputeSafeUint32Operations is responsible for setting this // flag. kUint32, + // If a phi is involved in the evaluation of a numeric constraint the + // recursion can cause an endless cycle: we use this flag to exit the loop. + kNumericConstraintEvaluationInProgress, // This flag is set to true after the SetupInformativeDefinitions() pass // has processed this instruction. kIDefsProcessingDone, @@ -2955,6 +2959,8 @@ class HPhi: public HValue { inputs_[index] = value; } + virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other); + private: ZoneList inputs_; int merged_index_; @@ -2967,6 +2973,52 @@ class HPhi: public HValue { }; +class HInductionVariableAnnotation : public HUnaryOperation { + public: + static HInductionVariableAnnotation* AddToGraph(HPhi* phi, + NumericRelation relation, + int operand_index); + + NumericRelation relation() { return relation_; } + HValue* induction_base() { return phi_->OperandAt(operand_index_); } + + virtual int RedefinedOperandIndex() { return 0; } + virtual bool IsPurelyInformativeDefinition() { return true; } + virtual Representation RequiredInputRepresentation(int index) { + return representation(); + } + + virtual void PrintDataTo(StringStream* stream); + + virtual bool IsRelationTrueInternal(NumericRelation other_relation, + HValue* other_related_value) { + if (induction_base() == other_related_value) { + return relation().Implies(other_relation); + } else { + return false; + } + } + + DECLARE_CONCRETE_INSTRUCTION(InductionVariableAnnotation) + + private: + HInductionVariableAnnotation(HPhi* phi, + NumericRelation relation, + 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 + // the operand can change if a new idef of the phi is added between the phi + // and this instruction (inserting an idef updates every use). + HPhi* phi_; + NumericRelation relation_; + int operand_index_; +}; + + class HArgumentsObject: public HTemplateInstruction<0> { public: HArgumentsObject() { diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index a25c154a2b..5d539ed8c0 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1717,6 +1717,12 @@ LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { } +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { return AssignEnvironment(new(zone()) LBoundsCheck( UseRegisterOrConstantAtStart(instr->index()), diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 863457eaae..a6d7f1d683 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -1595,6 +1595,12 @@ LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { } +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = UseRegister(instr->length()); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 4194ad6e25..57de0c8e17 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -1641,6 +1641,12 @@ LInstruction* LChunkBuilder::DoNumericConstraint(HNumericConstraint* instr) { } +LInstruction* LChunkBuilder::DoInductionVariableAnnotation( + HInductionVariableAnnotation* instr) { + return NULL; +} + + LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { LOperand* value = UseRegisterOrConstantAtStart(instr->index()); LOperand* length = Use(instr->length());