Bug 1160911 - JIT: precise shift right derived result range for all int32 input ranges. r=sunfish

This commit is contained in:
Douglas Crosher 2015-05-10 15:42:23 +10:00
parent 0c9d568ddd
commit 9f2d52bd7f
2 changed files with 82 additions and 1 deletions

View File

@ -1035,7 +1035,32 @@ Range::rsh(TempAllocator& alloc, const Range* lhs, const Range* rhs)
{
MOZ_ASSERT(lhs->isInt32());
MOZ_ASSERT(rhs->isInt32());
return Range::NewInt32Range(alloc, Min(lhs->lower(), 0), Max(lhs->upper(), 0));
// Canonicalize the shift range to 0 to 31.
int32_t shiftLower = rhs->lower();
int32_t shiftUpper = rhs->upper();
if ((int64_t(shiftUpper) - int64_t(shiftLower)) >= 31) {
shiftLower = 0;
shiftUpper = 31;
} else {
shiftLower &= 0x1f;
shiftUpper &= 0x1f;
if (shiftLower > shiftUpper) {
shiftLower = 0;
shiftUpper = 31;
}
}
MOZ_ASSERT(shiftLower >= 0 && shiftUpper <= 31);
// The lhs bounds are signed, thus the minimum is either the lower bound
// shift by the smallest shift if negative or the lower bound shifted by the
// biggest shift otherwise. And the opposite for the maximum.
int32_t lhsLower = lhs->lower();
int32_t min = lhsLower < 0 ? lhsLower >> shiftLower : lhsLower >> shiftUpper;
int32_t lhsUpper = lhs->upper();
int32_t max = lhsUpper >= 0 ? lhsUpper >> shiftLower : lhsUpper >> shiftUpper;
return Range::NewInt32Range(alloc, min, max);
}
Range*

View File

@ -277,3 +277,59 @@ BEGIN_TEST(testJitRangeAnalysis_StrictCompareBeta)
return true;
}
END_TEST(testJitRangeAnalysis_StrictCompareBeta)
static void
deriveShiftRightRange(int32_t lhsLower, int32_t lhsUpper,
int32_t rhsLower, int32_t rhsUpper,
int32_t* min, int32_t* max)
{
// This is the reference algorithm and should be verifiable by inspection.
int64_t i, j;
*min = INT32_MAX; *max = INT32_MIN;
for (i = lhsLower; i <= lhsUpper; i++) {
for (j = rhsLower; j <= rhsUpper; j++) {
int32_t r = int32_t(i) >> (int32_t(j) & 0x1f);
if (r > *max) *max = r;
if (r < *min) *min = r;
}
}
}
static bool
checkShiftRightRange(int32_t lhsLow, int32_t lhsHigh, int32_t lhsInc,
int32_t rhsLow, int32_t rhsHigh, int32_t rhsInc)
{
MinimalAlloc func;
int64_t lhsLower, lhsUpper, rhsLower, rhsUpper;
for (lhsLower = lhsLow; lhsLower <= lhsHigh; lhsLower += lhsInc) {
for (lhsUpper = lhsLower; lhsUpper <= lhsHigh; lhsUpper += lhsInc) {
Range* lhsRange = Range::NewInt32Range(func.alloc, lhsLower, lhsUpper);
for (rhsLower = rhsLow; rhsLower <= rhsHigh; rhsLower += rhsInc) {
for (rhsUpper = rhsLower; rhsUpper <= rhsHigh; rhsUpper += rhsInc) {
Range* rhsRange = Range::NewInt32Range(func.alloc, rhsLower, rhsUpper);
Range* result = Range::rsh(func.alloc, lhsRange, rhsRange);
int32_t min, max;
deriveShiftRightRange(lhsLower, lhsUpper,
rhsLower, rhsUpper,
&min, &max);
if (!result->isInt32() ||
result->lower() != min ||
result->upper() != max) {
return false;
}
}
}
}
}
return true;
}
BEGIN_TEST(testJitRangeAnalysis_shiftRight)
{
CHECK(checkShiftRightRange(-16, 15, 1, 0, 31, 1));
CHECK(checkShiftRightRange( -8, 7, 1, -64, 63, 1));
return true;
}
END_TEST(testJitRangeAnalysis_shiftRight)