Bug 869473 - Optimize DivI with a power of two divisor when the numerator is not negative. r=sunfish

This commit is contained in:
Douglas Crosher 2013-12-05 07:34:29 +11:00
Родитель 8648eb6908
Коммит bdd0312131
7 изменённых файлов: 76 добавлений и 9 удалений

Просмотреть файл

@ -331,3 +331,30 @@ for (let i = 0; i < 31; i++) {
}
assertEq(f(INT32_MIN), (INT32_MIN * 2)|0);
assertEq(f(INT32_MAX), (INT32_MAX * 2)|0);
// Signed integer division by a power of two - with a non-negative numerator!
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/1)|0; } return f;"));
for (let i = 0; i < 31; i++) {
assertEq(f(Math.pow(2,i)), Math.pow(2,i));
assertEq(f(Math.pow(2,i+1)-1), Math.pow(2,i+1)-1);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/2)|0; } return f;"));
for (let i = 0; i < 31; i++) {
assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/2)|0);
assertEq(f(Math.pow(2,i+1)-1), ((Math.pow(2,i+1)-1)/2)|0);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/4)|0; } return f;"));
for (let i = 0; i < 31; i++) {
assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/4)|0);
assertEq(f(Math.pow(2,i+1)-1), ((Math.pow(2,i+1)-1)/4)|0);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((i|0)/1073741824)|0; } return f;"));
for (let i = 0; i < 31; i++) {
assertEq(f(Math.pow(2,i)), (Math.pow(2,i)/Math.pow(2,30))|0);
assertEq(f(Math.pow(2,i+1)-1), ((Math.pow(2,i+1)-1)/Math.pow(2,30))|0);
}
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; i=(i&2147483647)|0; return ((((i|0)/1)|0)+i)|0; } return f;"));
for (let i = 0; i < 31; i++) {
assertEq(f(Math.pow(2,i)), (Math.pow(2,i) * 2)|0);
assertEq(f(Math.pow(2,i+1) - 1), ((Math.pow(2,i+1) - 1) * 2)|0);
}

Просмотреть файл

@ -4095,6 +4095,7 @@ class MDiv : public MBinaryArithInstruction
bool canBeNegativeZero_;
bool canBeNegativeOverflow_;
bool canBeDivideByZero_;
bool canBeNegativeDividend_;
bool unsigned_;
MDiv(MDefinition *left, MDefinition *right, MIRType type)
@ -4102,6 +4103,7 @@ class MDiv : public MBinaryArithInstruction
canBeNegativeZero_(true),
canBeNegativeOverflow_(true),
canBeDivideByZero_(true),
canBeNegativeDividend_(true),
unsigned_(false)
{
if (type != MIRType_Value)
@ -4150,6 +4152,10 @@ class MDiv : public MBinaryArithInstruction
return canBeDivideByZero_;
}
bool canBeNegativeDividend() const {
return canBeNegativeDividend_;
}
bool isUnsigned() const {
return unsigned_;
}
@ -4159,6 +4165,7 @@ class MDiv : public MBinaryArithInstruction
void computeRange();
bool fallible() const;
bool truncate();
void collectRangeInfoPreTrunc();
};
class MMod : public MBinaryArithInstruction

Просмотреть файл

@ -2496,6 +2496,14 @@ MLoadElementHole::collectRangeInfoPreTrunc()
needsNegativeIntCheck_ = false;
}
void
MDiv::collectRangeInfoPreTrunc()
{
Range lhsRange(lhs());
if (lhsRange.isFiniteNonNegative())
canBeNegativeDividend_ = false;
}
void
MMod::collectRangeInfoPreTrunc()
{

Просмотреть файл

@ -654,18 +654,23 @@ CodeGeneratorARM::visitDivPowTwoI(LDivPowTwoI *ins)
int32_t shift = ins->shift();
if (shift != 0) {
if (!ins->mir()->isTruncated()) {
MDiv *mir = ins->mir();
if (!mir->isTruncated()) {
// If the remainder is != 0, bailout since this must be a double.
masm.as_mov(ScratchRegister, lsl(lhs, 32 - shift), SetCond);
if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
return false;
}
if (!mir->canBeNegativeDividend()) {
// Numerator is unsigned, so needs no adjusting. Do the shift.
masm.as_mov(output, asr(lhs, shift));
return true;
}
// Adjust the value so that shifting produces a correctly rounded result
// when the numerator is negative. See 10-1 "Signed Division by a Known
// Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
// Note that we wouldn't need to do this adjustment if we could use
// Range Analysis to find cases when the value is never negative.
if (shift > 1) {
masm.as_mov(ScratchRegister, asr(lhs, 31));
masm.as_add(ScratchRegister, lhs, lsr(ScratchRegister, 32 - shift));

Просмотреть файл

@ -853,7 +853,6 @@ bool
CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
{
Register lhs = ToRegister(ins->numerator());
Register lhsCopy = ToRegister(ins->numeratorCopy());
mozilla::DebugOnly<Register> output = ToRegister(ins->output());
int32_t shift = ins->shift();
@ -862,19 +861,25 @@ CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
JS_ASSERT(lhs == output);
if (shift != 0) {
if (!ins->mir()->isTruncated()) {
MDiv *mir = ins->mir();
if (!mir->isTruncated()) {
// If the remainder is != 0, bailout since this must be a double.
masm.testl(lhs, Imm32(UINT32_MAX >> (32 - shift)));
if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
return false;
}
if (!mir->canBeNegativeDividend()) {
// Numerator is unsigned, so needs no adjusting. Do the shift.
masm.sarl(Imm32(shift), lhs);
return true;
}
// Adjust the value so that shifting produces a correctly rounded result
// when the numerator is negative. See 10-1 "Signed Division by a Known
// Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
// Note that we wouldn't need to do this adjustment if we could use
// Range Analysis to find cases when the value is never negative. We
// wouldn't even need the lhsCopy either in that case.
Register lhsCopy = ToRegister(ins->numeratorCopy());
JS_ASSERT(lhsCopy != lhs);
if (shift > 1)
masm.sarl(Imm32(31), lhs);
masm.shrl(Imm32(32 - shift), lhs);

Просмотреть файл

@ -58,6 +58,12 @@ class LDivPowTwoI : public LBinaryMath<0>
setOperand(1, lhsCopy);
}
LDivPowTwoI(const LAllocation &lhs, int32_t shift)
: shift_(shift)
{
setOperand(0, lhs);
}
const LAllocation *numerator() {
return getOperand(0);
}

Просмотреть файл

@ -144,7 +144,16 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *div)
// constants can be optimized by a reciprocal multiplication technique.
int32_t shift = FloorLog2(rhs);
if (rhs > 0 && 1 << shift == rhs) {
LDivPowTwoI *lir = new LDivPowTwoI(useRegisterAtStart(div->lhs()), useRegister(div->lhs()), shift);
LAllocation lhs = useRegisterAtStart(div->lhs());
LDivPowTwoI *lir;
if (!div->canBeNegativeDividend()) {
// Numerator is unsigned, so does not need adjusting.
lir = new LDivPowTwoI(lhs, shift);
} else {
// Numerator is signed, and needs adjusting, and an extra
// lhs copy register is needed.
lir = new LDivPowTwoI(lhs, useRegister(div->lhs()), shift);
}
if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
return false;
return defineReuseInput(lir, div, 0);