Bug 900437 - IonMonkey: Optimize x/x on x86/x64, which also fixes a tricky lowering case that broke the backtracking allocator. r=bhackett
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -755,16 +755,37 @@ CodeGeneratorX86Shared::visitDivPowTwoI(
// Do the shift.
masm.sarl(Imm32(shift), lhs);
}
return true;
}
bool
+CodeGeneratorX86Shared::visitDivSelfI(LDivSelfI *ins)
+{
+ Register op = ToRegister(ins->op());
+ Register output = ToRegister(ins->output());
+ MDiv *mir = ins->mir();
+
+ JS_ASSERT(mir->canBeDivideByZero());
+
+ masm.testl(op, op);
+ if (mir->isTruncated()) {
+ masm.emitSet(Assembler::NonZero, output);
+ } else {
+ if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+ return false;
+ masm.mov(Imm32(1), output);
+ }
+
+ return true;
+}
+
+bool
CodeGeneratorX86Shared::visitDivI(LDivI *ins)
{
Register remainder = ToRegister(ins->remainder());
Register lhs = ToRegister(ins->lhs());
Register rhs = ToRegister(ins->rhs());
Register output = ToRegister(ins->output());
MDiv *mir = ins->mir();
--- a/js/src/ion/shared/CodeGenerator-x86-shared.h
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.h
@@ -83,16 +83,17 @@ class CodeGeneratorX86Shared : public Co
virtual bool visitAbsD(LAbsD *ins);
virtual bool visitSqrtD(LSqrtD *ins);
virtual bool visitPowHalfD(LPowHalfD *ins);
virtual bool visitAddI(LAddI *ins);
virtual bool visitSubI(LSubI *ins);
virtual bool visitMulI(LMulI *ins);
virtual bool visitDivI(LDivI *ins);
virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
+ virtual bool visitDivSelfI(LDivSelfI *ins);
virtual bool visitModI(LModI *ins);
virtual bool visitModPowTwoI(LModPowTwoI *ins);
virtual bool visitBitNotI(LBitNotI *ins);
virtual bool visitBitOpI(LBitOpI *ins);
virtual bool visitShiftI(LShiftI *ins);
virtual bool visitUrshD(LUrshD *ins);
virtual bool visitTestIAndBranch(LTestIAndBranch *test);
virtual bool visitTestDAndBranch(LTestDAndBranch *test);
--- a/js/src/ion/shared/LIR-x86-shared.h
+++ b/js/src/ion/shared/LIR-x86-shared.h
@@ -67,16 +67,35 @@ class LDivPowTwoI : public LBinaryMath<0
int32_t shift() const {
return shift_;
}
MDiv *mir() const {
return mir_->toDiv();
}
};
+// Division of a number by itself. Returns 1 unless the number is zero.
+class LDivSelfI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(DivSelfI)
+
+ LDivSelfI(const LAllocation &op) {
+ setOperand(0, op);
+ }
+
+ const LAllocation *op() {
+ return getOperand(0);
+ }
+
+ MDiv *mir() const {
+ return mir_->toDiv();
+ }
+};
+
class LModI : public LBinaryMath<1>
{
public:
LIR_HEADER(ModI)
LModI(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
setOperand(0, lhs);
setOperand(1, rhs);
--- a/js/src/ion/shared/Lowering-x86-shared.cpp
+++ b/js/src/ion/shared/Lowering-x86-shared.cpp
@@ -158,16 +158,33 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
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);
}
}
+ // Optimize x/x. This is quaint, but it also protects the LDivI code below.
+ // Since LDivI requires lhs to be in %eax, and since the register allocator
+ // can't put a virtual register in two physical registers at the same time,
+ // this puts rhs in %eax too, and since rhs isn't marked usedAtStart, it
+ // would conflict with the %eax output register. (rhs could be marked
+ // usedAtStart but for the fact that LDivI clobbers %edx early and rhs could
+ // happen to be in %edx).
+ if (div->lhs() == div->rhs()) {
+ if (!div->canBeDivideByZero())
+ return define(new LInteger(1), div);
+
+ LDivSelfI *lir = new LDivSelfI(useRegisterAtStart(div->lhs()));
+ if (div->fallible() && !assignSnapshot(lir))
+ return false;
+ return define(lir, div);
+ }
+
LDivI *lir = new LDivI(useFixed(div->lhs(), eax), useRegister(div->rhs()), tempFixed(edx));
if (div->fallible() && !assignSnapshot(lir))
return false;
return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
}
bool
LIRGeneratorX86Shared::lowerModI(MMod *mod)
--- a/js/src/ion/x64/LOpcodes-x64.h
+++ b/js/src/ion/x64/LOpcodes-x64.h
@@ -8,16 +8,17 @@
#define ion_x64_LOpcodes_x64_h
#define LIR_CPU_OPCODE_LIST(_) \
_(Box) \
_(Unbox) \
_(UnboxDouble) \
_(DivI) \
_(DivPowTwoI) \
+ _(DivSelfI) \
_(ModI) \
_(ModPowTwoI) \
_(PowHalfD) \
_(UInt32ToDouble) \
_(AsmJSLoadFuncPtr) \
_(UDivOrMod)
#endif /* ion_x64_LOpcodes_x64_h */
--- a/js/src/ion/x86/LOpcodes-x86.h
+++ b/js/src/ion/x86/LOpcodes-x86.h
@@ -9,16 +9,17 @@
#define LIR_CPU_OPCODE_LIST(_) \
_(Unbox) \
_(UnboxDouble) \
_(Box) \
_(BoxDouble) \
_(DivI) \
_(DivPowTwoI) \
+ _(DivSelfI) \
_(ModI) \
_(ModPowTwoI) \
_(PowHalfD) \
_(UInt32ToDouble) \
_(AsmJSLoadFuncPtr) \
_(UDivOrMod)
#endif /* ion_x86_LOpcodes_x86_h */
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug900437.js
@@ -0,0 +1,6 @@
+function test() {
+ var x = 0.0;
+ for (var i = 0; i < 100; i++)
+ -("") >> (x / x);
+}
+test();