Bug 900437 - IonMonkey: Optimize x/x on x86/x64, which also fixes a tricky lowering case that broke the backtracking allocator. r=bhackett
authorDan Gohman <sunfish@google.com>
Tue, 06 Aug 2013 10:00:55 -0700
changeset 141574 3ec1dff8c4606c05b99adbcbc92822084e48d37a
parent 141573 8c7abf28722416ee96289401047a285cc25b1a6b
child 141575 45f5051ec758735e4ee38229ed0b5cc69f49d331
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbhackett
bugs900437
milestone26.0a1
Bug 900437 - IonMonkey: Optimize x/x on x86/x64, which also fixes a tricky lowering case that broke the backtracking allocator. r=bhackett
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/shared/CodeGenerator-x86-shared.h
js/src/ion/shared/LIR-x86-shared.h
js/src/ion/shared/Lowering-x86-shared.cpp
js/src/ion/x64/LOpcodes-x64.h
js/src/ion/x86/LOpcodes-x86.h
js/src/jit-test/tests/ion/bug900437.js
--- 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();