mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 889451 - Implement range analysis for or, xor, not, ursh, abs, min, and max, and better range analysis for shifts and mul. r=nbp
This commit is contained in:
parent
e6afc1fc30
commit
50849cbe27
@ -2639,6 +2639,7 @@ class MBitNot
|
||||
return AliasSet::Store(AliasSet::Any);
|
||||
return AliasSet::None();
|
||||
}
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MTypeOf
|
||||
@ -2784,6 +2785,7 @@ class MBitOr : public MBinaryBitwiseInstruction
|
||||
MDefinition *foldIfEqual() {
|
||||
return getOperand(0); // x | x => x
|
||||
}
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MBitXor : public MBinaryBitwiseInstruction
|
||||
@ -2806,6 +2808,7 @@ class MBitXor : public MBinaryBitwiseInstruction
|
||||
MDefinition *foldIfEqual() {
|
||||
return this;
|
||||
}
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MShiftInstruction
|
||||
@ -2912,6 +2915,8 @@ class MUrsh : public MShiftInstruction
|
||||
bool fallible() {
|
||||
return canOverflow();
|
||||
}
|
||||
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MBinaryArithInstruction
|
||||
@ -3017,6 +3022,7 @@ class MMinMax
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
void computeRange();
|
||||
};
|
||||
|
||||
class MAbs
|
||||
@ -3305,7 +3311,6 @@ class MAdd : public MBinaryArithInstruction
|
||||
}
|
||||
return add;
|
||||
}
|
||||
void analyzeTruncateBackward();
|
||||
|
||||
double getIdentity() {
|
||||
return 0;
|
||||
|
@ -457,6 +457,51 @@ Range::and_(const Range *lhs, const Range *rhs)
|
||||
return new Range(lower, upper);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::or_(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
int64_t lower = INT32_MIN;
|
||||
int64_t upper = INT32_MAX;
|
||||
|
||||
// If the sign bits are the same, the result has the same sign.
|
||||
if (lhs->lower_ >= 0 && rhs->lower_ >= 0)
|
||||
lower = 0;
|
||||
else if (lhs->upper_ < 0 || rhs->upper_ < 0)
|
||||
upper = -1;
|
||||
|
||||
return new Range(lower, upper);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::xor_(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
int64_t lower = INT32_MIN;
|
||||
int64_t upper = INT32_MAX;
|
||||
|
||||
// If the sign bits are identical, the result is non-negative.
|
||||
if (lhs->lower_ >= 0 && rhs->lower_ >= 0)
|
||||
lower = 0;
|
||||
else if (lhs->upper_ < 0 && rhs->upper_ < 0)
|
||||
lower = 0;
|
||||
|
||||
return new Range(lower, upper);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::not_(const Range *op)
|
||||
{
|
||||
int64_t lower = INT32_MIN;
|
||||
int64_t upper = INT32_MAX;
|
||||
|
||||
// Not inverts all bits, including the sign bit.
|
||||
if (op->lower_ >= 0)
|
||||
upper = -1;
|
||||
else if (op->upper_ < 0)
|
||||
lower = 0;
|
||||
|
||||
return new Range(lower, upper);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::mul(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
@ -475,16 +520,25 @@ Range::mul(const Range *lhs, const Range *rhs)
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::shl(const Range *lhs, int32_t c)
|
||||
Range::lsh(const Range *lhs, int32_t c)
|
||||
{
|
||||
int32_t shift = c & 0x1f;
|
||||
|
||||
// If the shift doesn't loose bits or shift bits into the sign bit, we
|
||||
// can simply compute the correct range by shifting.
|
||||
if (((uint32_t)lhs->lower_ << shift << 1 >> shift >> 1) == lhs->lower_ &&
|
||||
((uint32_t)lhs->upper_ << shift << 1 >> shift >> 1) == lhs->upper_)
|
||||
{
|
||||
return new Range(
|
||||
(int64_t)lhs->lower_ << shift,
|
||||
(int64_t)lhs->upper_ << shift);
|
||||
}
|
||||
|
||||
return new Range(INT32_MIN, INT32_MAX);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::shr(const Range *lhs, int32_t c)
|
||||
Range::rsh(const Range *lhs, int32_t c)
|
||||
{
|
||||
int32_t shift = c & 0x1f;
|
||||
return new Range(
|
||||
@ -492,6 +546,92 @@ Range::shr(const Range *lhs, int32_t c)
|
||||
(int64_t)lhs->upper_ >> shift);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::ursh(const Range *lhs, int32_t c)
|
||||
{
|
||||
int32_t shift = c & 0x1f;
|
||||
|
||||
// If the value is always non-negative or always negative, we can simply
|
||||
// compute the correct range by shifting.
|
||||
if ((lhs->lower_ >= 0 && !lhs->isUpperInfinite()) ||
|
||||
(lhs->upper_ < 0 && !lhs->isLowerInfinite()))
|
||||
{
|
||||
return new Range(
|
||||
(int64_t)((uint32_t)lhs->lower_ >> shift),
|
||||
(int64_t)((uint32_t)lhs->upper_ >> shift));
|
||||
}
|
||||
|
||||
// Otherwise return the most general range after the shift.
|
||||
return new Range(0, (int64_t)(UINT32_MAX >> shift));
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::lsh(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
return new Range(INT32_MIN, INT32_MAX);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::rsh(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
return new Range(Min(lhs->lower(), 0), Max(lhs->upper(), 0));
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::ursh(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
return new Range(0, (lhs->lower() >= 0 && !lhs->isUpperInfinite()) ? lhs->upper() : UINT32_MAX);
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::abs(const Range *op)
|
||||
{
|
||||
// Get the lower and upper values of the operand, and adjust them
|
||||
// for infinities. Range's constructor treats any value beyond the
|
||||
// int32_t range as infinity.
|
||||
int64_t l = (int64_t)op->lower() - op->isLowerInfinite();
|
||||
int64_t u = (int64_t)op->upper() + op->isUpperInfinite();
|
||||
|
||||
return new Range(Max(Max(int64_t(0), l), -u),
|
||||
Max(Abs(l), Abs(u)),
|
||||
op->isDecimal(),
|
||||
op->exponent());
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::min(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
// Get the lower and upper values of the operand, and adjust them
|
||||
// for infinities. Range's constructor treats any value beyond the
|
||||
// int32_t range as infinity.
|
||||
int64_t leftLower = (int64_t)lhs->lower() - lhs->isLowerInfinite();
|
||||
int64_t leftUpper = (int64_t)lhs->upper() + lhs->isUpperInfinite();
|
||||
int64_t rightLower = (int64_t)rhs->lower() - rhs->isLowerInfinite();
|
||||
int64_t rightUpper = (int64_t)rhs->upper() + rhs->isUpperInfinite();
|
||||
|
||||
return new Range(Min(leftLower, rightLower),
|
||||
Min(leftUpper, rightUpper),
|
||||
lhs->isDecimal() || rhs->isDecimal(),
|
||||
Max(lhs->exponent(), rhs->exponent()));
|
||||
}
|
||||
|
||||
Range *
|
||||
Range::max(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
// Get the lower and upper values of the operand, and adjust them
|
||||
// for infinities. Range's constructor treats any value beyond the
|
||||
// int32_t range as infinity.
|
||||
int64_t leftLower = (int64_t)lhs->lower() - lhs->isLowerInfinite();
|
||||
int64_t leftUpper = (int64_t)lhs->upper() + lhs->isUpperInfinite();
|
||||
int64_t rightLower = (int64_t)rhs->lower() - rhs->isLowerInfinite();
|
||||
int64_t rightUpper = (int64_t)rhs->upper() + rhs->isUpperInfinite();
|
||||
|
||||
return new Range(Max(leftLower, rightLower),
|
||||
Max(leftUpper, rightUpper),
|
||||
lhs->isDecimal() || rhs->isDecimal(),
|
||||
Max(lhs->exponent(), rhs->exponent()));
|
||||
}
|
||||
|
||||
bool
|
||||
Range::negativeZeroMul(const Range *lhs, const Range *rhs)
|
||||
{
|
||||
@ -650,28 +790,75 @@ MBitAnd::computeRange()
|
||||
setRange(Range::and_(&left, &right));
|
||||
}
|
||||
|
||||
void
|
||||
MBitOr::computeRange()
|
||||
{
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
setRange(Range::or_(&left, &right));
|
||||
}
|
||||
|
||||
void
|
||||
MBitXor::computeRange()
|
||||
{
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
setRange(Range::xor_(&left, &right));
|
||||
}
|
||||
|
||||
void
|
||||
MBitNot::computeRange()
|
||||
{
|
||||
Range op(getOperand(0));
|
||||
setRange(Range::not_(&op));
|
||||
}
|
||||
|
||||
void
|
||||
MLsh::computeRange()
|
||||
{
|
||||
MDefinition *right = getOperand(1);
|
||||
if (!right->isConstant())
|
||||
return;
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
|
||||
int32_t c = right->toConstant()->value().toInt32();
|
||||
Range other(getOperand(0));
|
||||
setRange(Range::shl(&other, c));
|
||||
MDefinition *rhs = getOperand(1);
|
||||
if (!rhs->isConstant()) {
|
||||
setRange(Range::lsh(&left, &right));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t c = rhs->toConstant()->value().toInt32();
|
||||
setRange(Range::lsh(&left, c));
|
||||
}
|
||||
|
||||
void
|
||||
MRsh::computeRange()
|
||||
{
|
||||
MDefinition *right = getOperand(1);
|
||||
if (!right->isConstant())
|
||||
return;
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
|
||||
int32_t c = right->toConstant()->value().toInt32();
|
||||
Range other(getOperand(0));
|
||||
setRange(Range::shr(&other, c));
|
||||
MDefinition *rhs = getOperand(1);
|
||||
if (!rhs->isConstant()) {
|
||||
setRange(Range::rsh(&left, &right));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t c = rhs->toConstant()->value().toInt32();
|
||||
setRange(Range::rsh(&left, c));
|
||||
}
|
||||
|
||||
void
|
||||
MUrsh::computeRange()
|
||||
{
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
|
||||
MDefinition *rhs = getOperand(1);
|
||||
if (!rhs->isConstant()) {
|
||||
setRange(Range::ursh(&left, &right));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t c = rhs->toConstant()->value().toInt32();
|
||||
setRange(Range::ursh(&left, c));
|
||||
}
|
||||
|
||||
void
|
||||
@ -681,17 +868,18 @@ MAbs::computeRange()
|
||||
return;
|
||||
|
||||
Range other(getOperand(0));
|
||||
setRange(Range::abs(&other));
|
||||
}
|
||||
|
||||
int64_t max = 0;
|
||||
if (other.isInt32())
|
||||
max = Max(Abs<int64_t>(other.lower()), Abs<int64_t>(other.upper()));
|
||||
else
|
||||
max = RANGE_INF_MAX;
|
||||
void
|
||||
MMinMax::computeRange()
|
||||
{
|
||||
if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double)
|
||||
return;
|
||||
|
||||
Range *range = new Range(0, max,
|
||||
other.isDecimal(),
|
||||
other.exponent());
|
||||
setRange(range);
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
setRange(isMax() ? Range::max(&left, &right) : Range::min(&left, &right));
|
||||
}
|
||||
|
||||
void
|
||||
@ -719,7 +907,7 @@ MSub::computeRange()
|
||||
void
|
||||
MMul::computeRange()
|
||||
{
|
||||
if ((specialization() != MIRType_Int32 && specialization() != MIRType_Double) || isTruncated())
|
||||
if (specialization() != MIRType_Int32 && specialization() != MIRType_Double)
|
||||
return;
|
||||
Range left(getOperand(0));
|
||||
Range right(getOperand(1));
|
||||
@ -1537,7 +1725,7 @@ RangeAnalysis::truncate()
|
||||
}
|
||||
|
||||
// Set truncated flag if range analysis ensure that it has no
|
||||
// rounding errors and no freactional part.
|
||||
// rounding errors and no fractional part.
|
||||
const Range *r = iter->range();
|
||||
if (!r || r->hasRoundingErrors())
|
||||
continue;
|
||||
|
@ -215,8 +215,18 @@ class Range : public TempObject {
|
||||
static Range * sub(const Range *lhs, const Range *rhs);
|
||||
static Range * mul(const Range *lhs, const Range *rhs);
|
||||
static Range * and_(const Range *lhs, const Range *rhs);
|
||||
static Range * shl(const Range *lhs, int32_t c);
|
||||
static Range * shr(const Range *lhs, int32_t c);
|
||||
static Range * or_(const Range *lhs, const Range *rhs);
|
||||
static Range * xor_(const Range *lhs, const Range *rhs);
|
||||
static Range * not_(const Range *op);
|
||||
static Range * lsh(const Range *lhs, int32_t c);
|
||||
static Range * rsh(const Range *lhs, int32_t c);
|
||||
static Range * ursh(const Range *lhs, int32_t c);
|
||||
static Range * lsh(const Range *lhs, const Range *rhs);
|
||||
static Range * rsh(const Range *lhs, const Range *rhs);
|
||||
static Range * ursh(const Range *lhs, const Range *rhs);
|
||||
static Range * abs(const Range *op);
|
||||
static Range * min(const Range *lhs, const Range *rhs);
|
||||
static Range * max(const Range *lhs, const Range *rhs);
|
||||
|
||||
static bool negativeZeroMul(const Range *lhs, const Range *rhs);
|
||||
|
||||
|
18
js/src/jit-test/tests/ion/bug889451.js
Normal file
18
js/src/jit-test/tests/ion/bug889451.js
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
js> (((-1 >>> 1) + 1) * Math.pow(2, 52 - 30) + 1) & 1
|
||||
0
|
||||
js> (((-1 >> 1) + 1) * Math.pow(2, 52 - 30) + 1) & 1
|
||||
1
|
||||
*/
|
||||
|
||||
function f(x) {
|
||||
if (x >= 0) {
|
||||
// if it does not fail, try with lower power of 2.
|
||||
return (((x >>> 1) + 1) * 4194304 /* 2 ** (52 - 30) */ + 1) & 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
assertEq(f(-1 >>> 1), 1);
|
||||
assertEq(f(-1 >>> 0), 0);
|
||||
assertEq(f(-1 >>> 0), 0);
|
Loading…
Reference in New Issue
Block a user