Index: src/hydrogen-range-analysis.cc |
diff --git a/src/hydrogen-range-analysis.cc b/src/hydrogen-range-analysis.cc |
index 76fd5f35f285c9889fe7a4f5fadff3e7ecf8e13c..9d58fc89f0b79030e07246ca39c9376e7e24e6b4 100644 |
--- a/src/hydrogen-range-analysis.cc |
+++ b/src/hydrogen-range-analysis.cc |
@@ -78,7 +78,29 @@ void HRangeAnalysisPhase::Run() { |
// Go through all instructions of the current block. |
for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
- InferRange(it.Current()); |
+ HValue* value = it.Current(); |
+ InferRange(value); |
+ |
+ // Compute the bailout-on-minus-zero flag. |
+ if (value->IsChange()) { |
+ HChange* instr = HChange::cast(value); |
+ // Propagate flags for negative zero checks upwards from conversions |
+ // int32-to-tagged and int32-to-double. |
+ Representation from = instr->value()->representation(); |
+ ASSERT(from.Equals(instr->from())); |
+ if (from.IsSmiOrInteger32()) { |
+ ASSERT(instr->to().IsTagged() || |
+ instr->to().IsDouble() || |
+ instr->to().IsSmiOrInteger32()); |
+ PropagateMinusZeroChecks(instr->value()); |
+ } |
+ } else if (value->IsCompareMinusZeroAndBranch()) { |
+ HCompareMinusZeroAndBranch* instr = |
+ HCompareMinusZeroAndBranch::cast(value); |
+ if (instr->value()->representation().IsSmiOrInteger32()) { |
+ PropagateMinusZeroChecks(instr->value()); |
+ } |
+ } |
} |
// Continue analysis in all dominated blocks. |
@@ -197,4 +219,79 @@ void HRangeAnalysisPhase::AddRange(HValue* value, Range* range) { |
} |
+void HRangeAnalysisPhase::PropagateMinusZeroChecks(HValue* value) { |
+ ASSERT(worklist_.is_empty()); |
+ ASSERT(in_worklist_.IsEmpty()); |
+ |
+ AddToWorklist(value); |
+ while (!worklist_.is_empty()) { |
+ value = worklist_.RemoveLast(); |
+ |
+ if (value->IsPhi()) { |
+ // For phis, we must propagate the check to all of its inputs. |
+ HPhi* phi = HPhi::cast(value); |
+ for (int i = 0; i < phi->OperandCount(); ++i) { |
+ AddToWorklist(phi->OperandAt(i)); |
+ } |
+ } else if (value->IsUnaryMathOperation()) { |
+ HUnaryMathOperation* instr = HUnaryMathOperation::cast(value); |
+ if (instr->representation().IsSmiOrInteger32() && |
+ !instr->value()->representation().Equals(instr->representation())) { |
+ if (instr->value()->range() == NULL || |
+ instr->value()->range()->CanBeMinusZero()) { |
+ instr->SetFlag(HValue::kBailoutOnMinusZero); |
+ } |
+ } |
+ if (instr->RequiredInputRepresentation(0).IsSmiOrInteger32() && |
+ instr->representation().Equals( |
+ instr->RequiredInputRepresentation(0))) { |
+ AddToWorklist(instr->value()); |
+ } |
+ } else if (value->IsChange()) { |
+ HChange* instr = HChange::cast(value); |
+ if (!instr->from().IsSmiOrInteger32() && |
+ !instr->CanTruncateToInt32() && |
+ (instr->value()->range() == NULL || |
+ instr->value()->range()->CanBeMinusZero())) { |
+ instr->SetFlag(HValue::kBailoutOnMinusZero); |
+ } |
+ } else if (value->IsForceRepresentation()) { |
+ HForceRepresentation* instr = HForceRepresentation::cast(value); |
+ AddToWorklist(instr->value()); |
+ } else if (value->IsMod()) { |
+ HMod* instr = HMod::cast(value); |
+ if (instr->range() == NULL || instr->range()->CanBeMinusZero()) { |
+ instr->SetFlag(HValue::kBailoutOnMinusZero); |
+ AddToWorklist(instr->left()); |
+ } |
+ } else if (value->IsDiv() || value->IsMul()) { |
+ HBinaryOperation* instr = HBinaryOperation::cast(value); |
+ if (instr->range() == NULL || instr->range()->CanBeMinusZero()) { |
+ instr->SetFlag(HValue::kBailoutOnMinusZero); |
+ } |
+ AddToWorklist(instr->right()); |
+ AddToWorklist(instr->left()); |
+ } else if (value->IsMathFloorOfDiv()) { |
+ HMathFloorOfDiv* instr = HMathFloorOfDiv::cast(value); |
+ instr->SetFlag(HValue::kBailoutOnMinusZero); |
+ } else if (value->IsAdd() || value->IsSub()) { |
+ HBinaryOperation* instr = HBinaryOperation::cast(value); |
+ if (instr->range() == NULL || instr->range()->CanBeMinusZero()) { |
+ // Propagate to the left argument. If the left argument cannot be -0, |
+ // then the result of the add/sub operation cannot be either. |
+ AddToWorklist(instr->left()); |
+ } |
+ } else if (value->IsMathMinMax()) { |
+ HMathMinMax* instr = HMathMinMax::cast(value); |
+ AddToWorklist(instr->right()); |
+ AddToWorklist(instr->left()); |
+ } |
+ } |
+ |
+ in_worklist_.Clear(); |
+ ASSERT(in_worklist_.IsEmpty()); |
+ ASSERT(worklist_.is_empty()); |
+} |
+ |
+ |
} } // namespace v8::internal |