Bug 809472: Add truncate analysis for MMul, r=mjrosenb

This commit is contained in:
Hannes Verschore 2012-11-08 14:35:26 +01:00
parent 6b2b2ee5c8
commit 4ecc61cba4
5 changed files with 78 additions and 4 deletions

View File

@ -958,9 +958,20 @@ MMul::analyzeEdgeCasesBackward()
canBeNegativeZero_ = NeedNegativeZeroCheck(this);
}
bool
MMul::updateForReplacement(MDefinition *ins)
void
MMul::analyzeTruncateBackward()
{
if (!isPossibleTruncated())
setPossibleTruncated(js::ion::EdgeCaseAnalysis::AllUsesTruncate(this));
}
bool
MMul::updateForReplacement(MDefinition *ins_)
{
JS_ASSERT(ins_->isMul());
MMul *ins = ins_->toMul();
if (isPossibleTruncated())
setPossibleTruncated(ins->isPossibleTruncated());
return true;
}

View File

@ -2498,11 +2498,24 @@ class MSub : public MBinaryArithInstruction
class MMul : public MBinaryArithInstruction
{
// Annotation the result could be a negative zero
// and we need to guard this during execution.
bool canBeNegativeZero_;
// Annotation the result of this Mul is only used in int32 domain
// and we could possible truncate the result.
bool possibleTruncate_;
// Annotation the Mul can truncate. This is only set after range analysis,
// because the result could be in the imprecise double range.
// In that case the truncated result isn't correct.
bool implicitTruncate_;
MMul(MDefinition *left, MDefinition *right, MIRType type)
: MBinaryArithInstruction(left, right),
canBeNegativeZero_(true)
canBeNegativeZero_(true),
possibleTruncate_(false),
implicitTruncate_(false)
{
if (type != MIRType_Value)
specialization_ = type;
@ -2521,13 +2534,14 @@ class MMul : public MBinaryArithInstruction
MDefinition *foldsTo(bool useValueNumbers);
void analyzeEdgeCasesForward();
void analyzeEdgeCasesBackward();
void analyzeTruncateBackward();
double getIdentity() {
return 1;
}
bool canOverflow() {
return !range()->isFinite();
return !implicitTruncate_ && !range()->isFinite();
}
bool canBeNegativeZero() {
@ -2546,8 +2560,18 @@ class MMul : public MBinaryArithInstruction
return false;
Range *left = getOperand(0)->range();
Range *right = getOperand(1)->range();
if (isPossibleTruncated())
implicitTruncate_ = !Range::precisionLossMul(left, right);
return range()->update(Range::mul(left, right));
}
bool isPossibleTruncated() const {
return possibleTruncate_;
}
void setPossibleTruncated(bool truncate) {
possibleTruncate_ = truncate;
}
};
class MDiv : public MBinaryArithInstruction

View File

@ -417,6 +417,24 @@ Range::shr(const Range *lhs, int32 c)
return ret;
}
bool
Range::precisionLossMul(const Range *lhs, const Range *rhs)
{
int64_t loss = 1LL<<53; // result must be lower than 2^53
int64_t a = (int64_t)lhs->lower_ * (int64_t)rhs->lower_;
int64_t b = (int64_t)lhs->lower_ * (int64_t)rhs->upper_;
int64_t c = (int64_t)lhs->upper_ * (int64_t)rhs->lower_;
int64_t d = (int64_t)lhs->upper_ * (int64_t)rhs->upper_;
int64_t lower = Min( Min(a, b), Min(c, d) );
int64_t upper = Max( Max(a, b), Max(c, d) );
if (lower < 0)
lower = -lower;
if (upper < 0)
upper = -upper;
return lower > loss || upper > loss;
}
bool
Range::update(const Range *other)
{

View File

@ -126,6 +126,8 @@ class Range {
static Range shl(const Range *lhs, int32 c);
static Range shr(const Range *lhs, int32 c);
static bool precisionLossMul(const Range *lhs, const Range *rhs);
inline void makeLowerInfinite() {
lower_infinite_ = true;
lower_ = JSVAL_INT_MIN;

View File

@ -0,0 +1,19 @@
function test1(x) {
return (x*((2<<23)-1))|0
}
function test2(x) {
return (x*((2<<22)-1))|0
}
function test3(x) {
return (x*((2<<21)-1))|0
}
function test4(x) {
var b = x + x + 3
return (b*b) | 0
}
//MAX_INT
var x = 0x7ffffffe;
assertEq(test1(x), 2113929216);
assertEq(test2(x), 2130706434);
assertEq(test3(x), 2139095042);
assertEq(test4(x), 0);