зеркало из https://github.com/mozilla/gecko-dev.git
Bug 868535 - IonMonkey: Optimize signed division by constant power of 2. r=nbp
This commit is contained in:
Родитель
0fadbc4834
Коммит
ab5ef8d3a1
|
@ -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) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче