Bug 829277: Limit the number of instructions that the truncation optimization can work on. (r=dvander)

This commit is contained in:
Marty Rosenberg 2013-01-10 18:06:05 -05:00
parent 852f5abcdc
commit 0a9b951217
4 changed files with 45 additions and 27 deletions

View File

@ -61,9 +61,12 @@ EdgeCaseAnalysis::analyzeEarly()
return true;
}
bool
int
EdgeCaseAnalysis::AllUsesTruncate(MInstruction *m)
{
// If all uses truncate, the return value must be at least 1. If anything doesn't truncate
// 0 is explicitly returned.
int ret = 1;
for (MUseIterator use = m->usesBegin(); use != m->usesEnd(); use++) {
// See #809485 why this is allowed
if (use->node()->isResumePoint())
@ -84,12 +87,16 @@ EdgeCaseAnalysis::AllUsesTruncate(MInstruction *m)
continue;
if (def->isBitNot())
continue;
if (def->isAdd() && def->toAdd()->isTruncated())
if (def->isAdd() && def->toAdd()->isTruncated()) {
ret = Max(ret, def->toAdd()->isTruncated() + 1);
continue;
if (def->isSub() && def->toSub()->isTruncated())
}
if (def->isSub() && def->toSub()->isTruncated()) {
ret = Max(ret, def->toSub()->isTruncated() + 1);
continue;
}
// cannot use divide, since |truncate(int32(x/y) + int32(a/b)) != truncate(x/y+a/b)|
return false;
return 0;
}
return true;
return ret;
}

View File

@ -22,7 +22,7 @@ class EdgeCaseAnalysis
EdgeCaseAnalysis(MIRGenerator *mir, MIRGraph &graph);
bool analyzeEarly();
bool analyzeLate();
static bool AllUsesTruncate(MInstruction *m);
static int AllUsesTruncate(MInstruction *m);
};

View File

@ -818,8 +818,8 @@ MDiv::analyzeEdgeCasesBackward()
void
MDiv::analyzeTruncateBackward()
{
if (!isTruncated() && js::ion::EdgeCaseAnalysis::AllUsesTruncate(this))
setTruncated(true);
if (!isTruncated())
setTruncated(js::ion::EdgeCaseAnalysis::AllUsesTruncate(this));
}
bool
@ -829,7 +829,8 @@ MDiv::updateForReplacement(MDefinition *ins_)
MDiv *ins = ins_->toDiv();
// Since EdgeCaseAnalysis is not being run before GVN, its information does
// not need to be merged here.
setTruncated(isTruncated() && ins->isTruncated());
if (isTruncated())
setTruncated(Max(isTruncated(), ins->isTruncated()));
return true;
}
@ -856,8 +857,8 @@ MMod::foldsTo(bool useValueNumbers)
void
MAdd::analyzeTruncateBackward()
{
if (!isTruncated() && js::ion::EdgeCaseAnalysis::AllUsesTruncate(this))
setTruncated(true);
if (!isTruncated())
setTruncated(js::ion::EdgeCaseAnalysis::AllUsesTruncate(this));
}
bool
@ -865,21 +866,29 @@ MAdd::updateForReplacement(MDefinition *ins_)
{
JS_ASSERT(ins_->isAdd());
MAdd *ins = ins_->toAdd();
setTruncated(isTruncated() && ins->isTruncated());
if (isTruncated())
setTruncated(Max(isTruncated(), ins->isTruncated()));
return true;
}
bool
MAdd::fallible()
{
return !isTruncated() && (!range() || !range()->isFinite());
// the add is fallible if range analysis does not say that it is finite, AND
// either the truncation analysis shows that there are non-truncated uses, or
// there are more than 20 operations before it gets truncated. 20 was chosen
// for two reasons. First, it is a nice sane number. Second, the largest int32
// can be (about) 2^31. The smallest integer that cannot be exactly represented
// as a double is 2^53 + 1 by doing something simple, like x = x + x, it takes
// 23 additions toget from 2^31 to 2^53 + 1. 20 is simply a conservative estimate of that.
return (!isTruncated() || isTruncated() > 20) && (!range() || !range()->isFinite());
}
void
MSub::analyzeTruncateBackward()
{
if (!isTruncated() && js::ion::EdgeCaseAnalysis::AllUsesTruncate(this))
setTruncated(true);
if (!isTruncated())
setTruncated(js::ion::EdgeCaseAnalysis::AllUsesTruncate(this));
}
bool
@ -887,14 +896,16 @@ MSub::updateForReplacement(MDefinition *ins_)
{
JS_ASSERT(ins_->isSub());
MSub *ins = ins_->toSub();
setTruncated(isTruncated() && ins->isTruncated());
if (isTruncated())
setTruncated(Max(isTruncated(), ins->isTruncated()));
return true;
}
bool
MSub::fallible()
{
return !isTruncated() && (!range() || !range()->isFinite());
// see comment in MAdd::fallible()
return (!isTruncated() || isTruncated() > 20) && (!range() || !range()->isFinite());
}
MDefinition *

View File

@ -2559,11 +2559,11 @@ class MMathFunction
class MAdd : public MBinaryArithInstruction
{
bool implicitTruncate_;
int implicitTruncate_;
MAdd(MDefinition *left, MDefinition *right)
: MBinaryArithInstruction(left, right),
implicitTruncate_(false)
implicitTruncate_(0)
{
setResultType(MIRType_Value);
}
@ -2575,10 +2575,10 @@ class MAdd : public MBinaryArithInstruction
}
void analyzeTruncateBackward();
bool isTruncated() const {
int isTruncated() const {
return implicitTruncate_;
}
void setTruncated(bool truncate) {
void setTruncated(int truncate) {
implicitTruncate_ = truncate;
}
bool updateForReplacement(MDefinition *ins);
@ -2592,7 +2592,7 @@ class MAdd : public MBinaryArithInstruction
class MSub : public MBinaryArithInstruction
{
bool implicitTruncate_;
int implicitTruncate_;
MSub(MDefinition *left, MDefinition *right)
: MBinaryArithInstruction(left, right),
implicitTruncate_(false)
@ -2607,10 +2607,10 @@ class MSub : public MBinaryArithInstruction
}
void analyzeTruncateBackward();
bool isTruncated() const {
int isTruncated() const {
return implicitTruncate_;
}
void setTruncated(bool truncate) {
void setTruncated(int truncate) {
implicitTruncate_ = truncate;
}
bool updateForReplacement(MDefinition *ins);
@ -2725,7 +2725,7 @@ class MDiv : public MBinaryArithInstruction
bool canBeNegativeZero_;
bool canBeNegativeOverflow_;
bool canBeDivideByZero_;
bool implicitTruncate_;
int implicitTruncate_;
MDiv(MDefinition *left, MDefinition *right, MIRType type)
: MBinaryArithInstruction(left, right),
@ -2759,10 +2759,10 @@ class MDiv : public MBinaryArithInstruction
return 1;
}
bool isTruncated() const {
int isTruncated() const {
return implicitTruncate_;
}
void setTruncated(bool truncate) {
void setTruncated(int truncate) {
implicitTruncate_ = truncate;
}