Replace the recursion in PropagateMinusZeroChecks() with a loop and a worklist.

Also refactor the related code in preparation for fixing the
range analysis.

BUG=v8:3204
LOG=y
R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/190713002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19737 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-03-10 05:52:03 +00:00
parent 6503dfb72b
commit c981914d4c
4 changed files with 78 additions and 159 deletions

View File

@ -3703,99 +3703,6 @@ void HAllocate::PrintDataTo(StringStream* stream) {
} }
HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
BitVector* visited) {
visited->Add(id());
if (representation().IsSmiOrInteger32() &&
!value()->representation().Equals(representation())) {
if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
}
if (RequiredInputRepresentation(0).IsSmiOrInteger32() &&
representation().Equals(RequiredInputRepresentation(0))) {
return value();
}
return NULL;
}
HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
if (from().IsSmiOrInteger32()) return NULL;
if (CanTruncateToInt32()) return NULL;
if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
ASSERT(!from().IsSmiOrInteger32() || !to().IsSmiOrInteger32());
return NULL;
}
HValue* HForceRepresentation::EnsureAndPropagateNotMinusZero(
BitVector* visited) {
visited->Add(id());
return value();
}
HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
if (range() == NULL || range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
return left();
}
return NULL;
}
HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
if (range() == NULL || range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
return NULL;
}
HValue* HMathFloorOfDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
SetFlag(kBailoutOnMinusZero);
return NULL;
}
HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
if (range() == NULL || range()->CanBeMinusZero()) {
SetFlag(kBailoutOnMinusZero);
}
return NULL;
}
HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
// Propagate to the left argument. If the left argument cannot be -0, then
// the result of the add operation cannot be either.
if (range() == NULL || range()->CanBeMinusZero()) {
return left();
}
return NULL;
}
HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
// Propagate to the left argument. If the left argument cannot be -0, then
// the result of the sub operation cannot be either.
if (range() == NULL || range()->CanBeMinusZero()) {
return left();
}
return NULL;
}
bool HStoreKeyed::NeedsCanonicalization() { bool HStoreKeyed::NeedsCanonicalization() {
// If value is an integer or smi or comes from the result of a keyed load or // If value is an integer or smi or comes from the result of a keyed load or
// constant then it is either be a non-hole value or in the case of a constant // constant then it is either be a non-hole value or in the case of a constant

View File

@ -739,21 +739,6 @@ class HValue : public ZoneObject {
return representation_.IsHeapObject() || type_.IsHeapObject(); return representation_.IsHeapObject() || type_.IsHeapObject();
} }
// An operation needs to override this function iff:
// 1) it can produce an int32 output.
// 2) the true value of its output can potentially be minus zero.
// The implementation must set a flag so that it bails out in the case where
// it would otherwise output what should be a minus zero as an int32 zero.
// If the operation also exists in a form that takes int32 and outputs int32
// then the operation should return its input value so that we can propagate
// back. There are three operations that need to propagate back to more than
// one input. They are phi and binary div and mul. They always return NULL
// and expect the caller to take care of things.
virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) {
visited->Add(id());
return NULL;
}
// There are HInstructions that do not really change a value, they // There are HInstructions that do not really change a value, they
// only add pieces of information to it (like bounds checks, map checks, // only add pieces of information to it (like bounds checks, map checks,
// smi checks...). // smi checks...).
@ -1719,9 +1704,6 @@ class HForceRepresentation V8_FINAL : public HTemplateInstruction<1> {
HValue* value() { return OperandAt(0); } HValue* value() { return OperandAt(0); }
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
return representation(); // Same as the output representation. return representation(); // Same as the output representation.
} }
@ -1767,8 +1749,6 @@ class HChange V8_FINAL : public HUnaryOperation {
return CheckUsesForFlag(kAllowUndefinedAsNaN); return CheckUsesForFlag(kAllowUndefinedAsNaN);
} }
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual HType CalculateInferredType() V8_OVERRIDE; virtual HType CalculateInferredType() V8_OVERRIDE;
virtual HValue* Canonicalize() V8_OVERRIDE; virtual HValue* Canonicalize() V8_OVERRIDE;
@ -2631,9 +2611,6 @@ class HUnaryMathOperation V8_FINAL : public HTemplateInstruction<2> {
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE { virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
if (index == 0) { if (index == 0) {
return Representation::Tagged(); return Representation::Tagged();
@ -4111,9 +4088,6 @@ class HMathFloorOfDiv V8_FINAL : public HBinaryOperation {
HValue*, HValue*,
HValue*); HValue*);
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
protected: protected:
@ -4714,9 +4688,6 @@ class HAdd V8_FINAL : public HArithmeticBinaryOperation {
return !representation().IsTagged() && !representation().IsExternal(); return !representation().IsTagged() && !representation().IsExternal();
} }
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual HValue* Canonicalize() V8_OVERRIDE; virtual HValue* Canonicalize() V8_OVERRIDE;
virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE { virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
@ -4773,9 +4744,6 @@ class HSub V8_FINAL : public HArithmeticBinaryOperation {
HValue* left, HValue* left,
HValue* right); HValue* right);
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual HValue* Canonicalize() V8_OVERRIDE; virtual HValue* Canonicalize() V8_OVERRIDE;
virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE { virtual bool TryDecompose(DecompositionResult* decomposition) V8_OVERRIDE {
@ -4822,9 +4790,6 @@ class HMul V8_FINAL : public HArithmeticBinaryOperation {
return mul; return mul;
} }
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual HValue* Canonicalize() V8_OVERRIDE; virtual HValue* Canonicalize() V8_OVERRIDE;
// Only commutative if it is certain that not two objects are multiplicated. // Only commutative if it is certain that not two objects are multiplicated.
@ -4862,9 +4827,6 @@ class HMod V8_FINAL : public HArithmeticBinaryOperation {
HValue* left, HValue* left,
HValue* right); HValue* right);
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual HValue* Canonicalize() V8_OVERRIDE; virtual HValue* Canonicalize() V8_OVERRIDE;
virtual void UpdateRepresentation(Representation new_rep, virtual void UpdateRepresentation(Representation new_rep,
@ -4898,9 +4860,6 @@ class HDiv V8_FINAL : public HArithmeticBinaryOperation {
HValue* left, HValue* left,
HValue* right); HValue* right);
virtual HValue* EnsureAndPropagateNotMinusZero(
BitVector* visited) V8_OVERRIDE;
virtual HValue* Canonicalize() V8_OVERRIDE; virtual HValue* Canonicalize() V8_OVERRIDE;
virtual void UpdateRepresentation(Representation new_rep, virtual void UpdateRepresentation(Representation new_rep,

View File

@ -45,17 +45,13 @@ void HComputeMinusZeroChecksPhase::Run() {
ASSERT(change->to().IsTagged() || ASSERT(change->to().IsTagged() ||
change->to().IsDouble() || change->to().IsDouble() ||
change->to().IsSmiOrInteger32()); change->to().IsSmiOrInteger32());
ASSERT(visited_.IsEmpty());
PropagateMinusZeroChecks(change->value()); PropagateMinusZeroChecks(change->value());
visited_.Clear();
} }
} else if (current->IsCompareMinusZeroAndBranch()) { } else if (current->IsCompareMinusZeroAndBranch()) {
HCompareMinusZeroAndBranch* check = HCompareMinusZeroAndBranch* check =
HCompareMinusZeroAndBranch::cast(current); HCompareMinusZeroAndBranch::cast(current);
if (check->value()->representation().IsSmiOrInteger32()) { if (check->value()->representation().IsSmiOrInteger32()) {
ASSERT(visited_.IsEmpty());
PropagateMinusZeroChecks(check->value()); PropagateMinusZeroChecks(check->value());
visited_.Clear();
} }
} }
} }
@ -64,28 +60,77 @@ void HComputeMinusZeroChecksPhase::Run() {
void HComputeMinusZeroChecksPhase::PropagateMinusZeroChecks(HValue* value) { void HComputeMinusZeroChecksPhase::PropagateMinusZeroChecks(HValue* value) {
for (HValue* current = value; ASSERT(worklist_.is_empty());
current != NULL && !visited_.Contains(current->id()); ASSERT(in_worklist_.IsEmpty());
current = current->EnsureAndPropagateNotMinusZero(&visited_)) {
// For phis, we must propagate the check to all of its inputs.
if (current->IsPhi()) {
visited_.Add(current->id());
HPhi* phi = HPhi::cast(current);
for (int i = 0; i < phi->OperandCount(); ++i) {
PropagateMinusZeroChecks(phi->OperandAt(i));
}
break;
}
// For multiplication, division, and Math.min/max(), we must propagate AddToWorklist(value);
// to the left and the right side. while (!worklist_.is_empty()) {
if (current->IsMul() || current->IsDiv() || current->IsMathMinMax()) { value = worklist_.RemoveLast();
HBinaryOperation* operation = HBinaryOperation::cast(current);
operation->EnsureAndPropagateNotMinusZero(&visited_); if (value->IsPhi()) {
PropagateMinusZeroChecks(operation->left()); // For phis, we must propagate the check to all of its inputs.
PropagateMinusZeroChecks(operation->right()); 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 } } // namespace v8::internal

View File

@ -38,14 +38,22 @@ class HComputeMinusZeroChecksPhase : public HPhase {
public: public:
explicit HComputeMinusZeroChecksPhase(HGraph* graph) explicit HComputeMinusZeroChecksPhase(HGraph* graph)
: HPhase("H_Compute minus zero checks", graph), : HPhase("H_Compute minus zero checks", graph),
visited_(graph->GetMaximumValueID(), zone()) { } in_worklist_(graph->GetMaximumValueID(), zone()),
worklist_(32, zone()) {}
void Run(); void Run();
private: private:
void AddToWorklist(HValue* value) {
if (value->CheckFlag(HValue::kBailoutOnMinusZero)) return;
if (in_worklist_.Contains(value->id())) return;
in_worklist_.Add(value->id());
worklist_.Add(value, zone());
}
void PropagateMinusZeroChecks(HValue* value); void PropagateMinusZeroChecks(HValue* value);
BitVector visited_; BitVector in_worklist_;
ZoneList<HValue*> worklist_;
DISALLOW_COPY_AND_ASSIGN(HComputeMinusZeroChecksPhase); DISALLOW_COPY_AND_ASSIGN(HComputeMinusZeroChecksPhase);
}; };