зеркало из https://github.com/mozilla/gecko-dev.git
Bug 869473 - Optimize DivI with a power of two divisor when the numerator is not negative. r=sunfish
This commit is contained in:
Родитель
8648eb6908
Коммит
bdd0312131
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче