Bug 868535 - IonMonkey: Optimize signed division by constant power of 2. r=nbp

This commit is contained in:
Dan Gohman 2013-05-03 18:58:00 -07:00
Родитель 0fadbc4834
Коммит ab5ef8d3a1
7 изменённых файлов: 93 добавлений и 0 удалений

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

@ -678,6 +678,44 @@ CodeGeneratorX86Shared::visitMulNegativeZeroCheck(MulNegativeZeroCheck *ool)
return true;
}
bool
CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
{
Register lhs = ToRegister(ins->numerator());
Register lhsCopy = ToRegister(ins->numeratorCopy());
Register output = ToRegister(ins->output());
int32_t shift = ins->shift();
// We use defineReuseInput so these should always be the same, which is
// convenient since all of our instructions here are two-address.
JS_ASSERT(lhs == output);
if (shift != 0) {
if (!ins->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;
}
// 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.
if (shift > 1)
masm.sarl(Imm32(31), lhs);
masm.shrl(Imm32(32 - shift), lhs);
masm.addl(lhsCopy, lhs);
// Do the shift.
masm.sarl(Imm32(shift), lhs);
}
return true;
}
bool
CodeGeneratorX86Shared::visitDivI(LDivI *ins)
{

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

@ -84,6 +84,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual bool visitSubI(LSubI *ins);
virtual bool visitMulI(LMulI *ins);
virtual bool visitDivI(LDivI *ins);
virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
virtual bool visitModI(LModI *ins);
virtual bool visitModPowTwoI(LModPowTwoI *ins);
virtual bool visitBitNotI(LBitNotI *ins);

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

@ -43,6 +43,35 @@ class LDivI : public LBinaryMath<1>
}
};
// Signed division by a power-of-two constant.
class LDivPowTwoI : public LBinaryMath<0>
{
const int32_t shift_;
public:
LIR_HEADER(DivPowTwoI)
LDivPowTwoI(const LAllocation &lhs, const LAllocation &lhsCopy, int32_t shift)
: shift_(shift)
{
setOperand(0, lhs);
setOperand(1, lhsCopy);
}
const LAllocation *numerator() {
return getOperand(0);
}
const LAllocation *numeratorCopy() {
return getOperand(1);
}
int32_t shift() const {
return shift_;
}
MDiv *mir() const {
return mir_->toDiv();
}
};
class LModI : public LBinaryMath<1>
{
public:

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

@ -84,6 +84,26 @@ LIRGeneratorX86Shared::lowerMulI(MMul *mul, MDefinition *lhs, MDefinition *rhs)
bool
LIRGeneratorX86Shared::lowerDivI(MDiv *div)
{
// Division instructions are slow. Division by constant denominators can be
// rewritten to use other instructions.
if (div->rhs()->isConstant()) {
int32_t rhs = div->rhs()->toConstant()->value().toInt32();
// Check for division by a positive power of two, which is an easy and
// important case to optimize. Note that other optimizations are also
// possible; division by negative powers of two can be optimized in a
// similar manner as positive powers of two, and division by other
// constants can be optimized by a reciprocal multiplication technique.
int32_t shift;
JS_FLOOR_LOG2(shift, rhs);
if (rhs > 0 && 1 << shift == rhs) {
LDivPowTwoI *lir = new LDivPowTwoI(useRegisterAtStart(div->lhs()), useRegister(div->lhs()), shift);
if (div->fallible() && !assignSnapshot(lir))
return false;
return defineReuseInput(lir, div, 0);
}
}
LDivI *lir = new LDivI(useFixed(div->lhs(), eax), useRegister(div->rhs()), tempFixed(edx));
if (div->fallible() && !assignSnapshot(lir))
return false;

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

@ -484,6 +484,9 @@ class Assembler : public AssemblerX86Shared
void shrq(Imm32 imm, const Register &dest) {
masm.shrq_i8r(imm.value, dest.code());
}
void sarq(Imm32 imm, const Register &dest) {
masm.sarq_i8r(imm.value, dest.code());
}
void orq(Imm32 imm, const Register &dest) {
masm.orq_ir(imm.value, dest.code());
}

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

@ -12,6 +12,7 @@
_(Unbox) \
_(UnboxDouble) \
_(DivI) \
_(DivPowTwoI) \
_(ModI) \
_(ModPowTwoI) \
_(PowHalfD) \

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

@ -13,6 +13,7 @@
_(Box) \
_(BoxDouble) \
_(DivI) \
_(DivPowTwoI) \
_(ModI) \
_(ModPowTwoI) \
_(PowHalfD) \