Bug 946478 - IonMonkey: Go back to just using copies to satisfy regalloc constraints for div and mod on x86/x64. r=bhackett
authorDan Gohman <sunfish@mozilla.com>
Wed, 19 Feb 2014 11:37:25 -0500
changeset 169881 ad545722ca5fc801c18551da9bb045671b7d7dc9
parent 169880 e42874936c101388c8a887aa66eda092d7701c08
child 169882 521123eb35841d08084818e2799c19b8441cb73f
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersbhackett
bugs946478
milestone30.0a1
Bug 946478 - IonMonkey: Go back to just using copies to satisfy regalloc constraints for div and mod on x86/x64. r=bhackett
js/src/jit/shared/CodeGenerator-x86-shared.cpp
js/src/jit/shared/CodeGenerator-x86-shared.h
js/src/jit/shared/LIR-x86-shared.h
js/src/jit/shared/Lowering-x86-shared.cpp
js/src/jit/x64/LOpcodes-x64.h
js/src/jit/x86/LOpcodes-x86.h
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -783,37 +783,44 @@ CodeGeneratorX86Shared::visitReturnZero(
     masm.mov(ImmWord(0), ool->reg());
     masm.jmp(ool->rejoin());
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins)
 {
-    JS_ASSERT(ToRegister(ins->lhs()) == eax);
+    Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
+    JS_ASSERT_IF(lhs != rhs, rhs != eax);
+    JS_ASSERT(rhs != edx);
     JS_ASSERT_IF(output == eax, ToRegister(ins->remainder()) == edx);
 
     ReturnZero *ool = nullptr;
 
+    // Put the lhs in eax.
+    if (lhs != eax)
+        masm.mov(lhs, eax);
+
     // Prevent divide by zero.
     if (ins->canBeDivideByZero()) {
         masm.testl(rhs, rhs);
         if (ins->mir()->isTruncated()) {
             if (!ool)
                 ool = new(alloc()) ReturnZero(output);
             masm.j(Assembler::Zero, ool->entry());
         } else {
             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
                 return false;
         }
     }
 
+    // Zero extend the lhs into edx to make (edx:eax), since udiv is 64-bit.
     masm.mov(ImmWord(0), edx);
     masm.udiv(rhs);
 
     // Unsigned div or mod can return a value that's not a signed int32.
     // If our users aren't expecting that, bail.
     if (!ins->mir()->isTruncated()) {
         masm.testl(output, output);
         if (!bailoutIf(Assembler::Signed, ins->snapshot()))
@@ -888,54 +895,38 @@ 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();
-
-    // If we can't divide by zero, lowering should have just used a constant one.
-    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(ImmWord(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();
 
+    JS_ASSERT_IF(lhs != rhs, rhs != eax);
+    JS_ASSERT(rhs != edx);
     JS_ASSERT(remainder == edx);
-    JS_ASSERT(lhs == eax);
     JS_ASSERT(output == eax);
 
     Label done;
     ReturnZero *ool = nullptr;
 
+    // Put the lhs in eax, for either the negative overflow case or the regular
+    // divide case.
+    if (lhs != eax)
+        masm.mov(lhs, eax);
+
     // Handle divide by zero.
     if (mir->canBeDivideByZero()) {
         masm.testl(rhs, rhs);
         if (mir->isTruncated()) {
             // Truncated division by zero is zero (Infinity|0 == 0)
             if (!ool)
                 ool = new(alloc()) ReturnZero(output);
             masm.j(Assembler::Zero, ool->entry());
@@ -970,17 +961,19 @@ CodeGeneratorX86Shared::visitDivI(LDivI 
         masm.testl(lhs, lhs);
         masm.j(Assembler::NonZero, &nonzero);
         masm.cmpl(rhs, Imm32(0));
         if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
             return false;
         masm.bind(&nonzero);
     }
 
-    // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit.
+    // Sign extend the lhs into edx to make (edx:eax), since idiv is 64-bit.
+    if (lhs != eax)
+        masm.mov(lhs, eax);
     masm.cdq();
     masm.idiv(rhs);
 
     if (!mir->isTruncated()) {
         // If the remainder is > 0, bailout since this must be a double.
         masm.testl(remainder, remainder);
         if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
             return false;
@@ -993,49 +986,16 @@ CodeGeneratorX86Shared::visitDivI(LDivI 
             return false;
         masm.bind(ool->rejoin());
     }
 
     return true;
 }
 
 bool
-CodeGeneratorX86Shared::visitModSelfI(LModSelfI *ins)
-{
-    Register op = ToRegister(ins->op());
-    Register output = ToRegister(ins->output());
-    MMod *mir = ins->mir();
-
-    // If we're not fallible, lowering should have just used a constant zero.
-    JS_ASSERT(mir->fallible());
-    JS_ASSERT(mir->canBeDivideByZero() || (!mir->isUnsigned() && mir->canBeNegativeDividend()));
-
-    masm.testl(op, op);
-
-    // For a negative operand, we need to return negative zero. We can't
-    // represent that as an int32, so bail if that happens.
-    if (!mir->isUnsigned() && mir->canBeNegativeDividend()) {
-        if (!bailoutIf(Assembler::Signed, ins->snapshot()))
-             return false;
-    }
-
-    // For a zero operand, we need to return NaN. We can't
-    // represent that as an int32, so bail if that happens.
-    if (mir->canBeDivideByZero()) {
-        if (!bailoutIf(Assembler::Zero, ins->snapshot()))
-            return false;
-    }
-
-    // For any other value, return 0.
-    masm.mov(ImmWord(0), output);
-
-    return true;
-}
-
-bool
 CodeGeneratorX86Shared::visitModPowTwoI(LModPowTwoI *ins)
 {
     Register lhs = ToRegister(ins->getOperand(0));
     int32_t shift = ins->shift();
 
     Label negative;
 
     if (ins->mir()->canBeNegativeDividend()) {
@@ -1109,24 +1069,29 @@ CodeGeneratorX86Shared::visitModOverflow
 bool
 CodeGeneratorX86Shared::visitModI(LModI *ins)
 {
     Register remainder = ToRegister(ins->remainder());
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
 
     // Required to use idiv.
-    JS_ASSERT(lhs == eax);
+    JS_ASSERT_IF(lhs != rhs, rhs != eax);
+    JS_ASSERT(rhs != edx);
     JS_ASSERT(remainder == edx);
     JS_ASSERT(ToRegister(ins->getTemp(0)) == eax);
 
     Label done;
     ReturnZero *ool = nullptr;
     ModOverflowCheck *overflow = nullptr;
 
+    // Set up eax in preparation for doing a div.
+    if (lhs != eax)
+        masm.mov(lhs, eax);
+
     // Prevent divide by zero.
     if (ins->mir()->canBeDivideByZero()) {
         masm.testl(rhs, rhs);
         if (ins->mir()->isTruncated()) {
             if (!ool)
                 ool = new(alloc()) ReturnZero(edx);
             masm.j(Assembler::Zero, ool->entry());
         } else {
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -86,20 +86,18 @@ class CodeGeneratorX86Shared : public Co
     virtual bool visitSqrtD(LSqrtD *ins);
     virtual bool visitSqrtF(LSqrtF *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 visitModSelfI(LModSelfI *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);
     virtual bool visitTestFAndBranch(LTestFAndBranch *test);
     virtual bool visitCompare(LCompare *comp);
--- a/js/src/jit/shared/LIR-x86-shared.h
+++ b/js/src/jit/shared/LIR-x86-shared.h
@@ -67,35 +67,16 @@ 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);
@@ -109,35 +90,16 @@ class LModI : public LBinaryMath<1>
     const LDefinition *remainder() {
         return getDef(0);
     }
     MMod *mir() const {
         return mir_->toMod();
     }
 };
 
-// Modulo of a number by itself. Returns 0 unless the number is zero.
-class LModSelfI : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(ModSelfI)
-
-    LModSelfI(const LAllocation &op) {
-        setOperand(0, op);
-    }
-
-    const LAllocation *op() {
-        return getOperand(0);
-    }
-
-    MMod *mir() const {
-        return mir_->toMod();
-    }
-};
-
 // This class performs a simple x86 'div', yielding either a quotient or remainder depending on
 // whether this instruction is defined to output eax (quotient) or edx (remainder).
 class LUDivOrMod : public LBinaryMath<1>
 {
   public:
     LIR_HEADER(UDivOrMod);
 
     LUDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -155,34 +155,18 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
                 lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift);
             }
             if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
                 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(alloc()) LInteger(1), div);
-
-        LDivSelfI *lir = new(alloc()) LDivSelfI(useRegisterAtStart(div->lhs()));
-        if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
-            return false;
-        return define(lir, div);
-    }
-
-    LDivI *lir = new(alloc()) LDivI(useFixed(div->lhs(), eax), useRegister(div->rhs()), tempFixed(edx));
+    LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()),
+                                    tempFixed(edx));
     if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
     return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
 }
 
 bool
 LIRGeneratorX86Shared::lowerModI(MMod *mod)
 {
@@ -195,30 +179,17 @@ LIRGeneratorX86Shared::lowerModI(MMod *m
         if (rhs > 0 && 1 << shift == rhs) {
             LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
             if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
                 return false;
             return defineReuseInput(lir, mod, 0);
         }
     }
 
-    // Optimize x%x. The comments in lowerDivI apply here as well, except
-    // that we return 0 for all cases except when x is 0 and we're not
-    // truncated.
-    if (mod->rhs() == mod->lhs()) {
-        if (mod->isTruncated())
-            return define(new(alloc()) LInteger(0), mod);
-
-        LModSelfI *lir = new(alloc()) LModSelfI(useRegisterAtStart(mod->lhs()));
-        if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
-            return false;
-        return define(lir, mod);
-    }
-
-    LModI *lir = new(alloc()) LModI(useFixedAtStart(mod->lhs(), eax),
+    LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()),
                                     useRegister(mod->rhs()),
                                     tempFixed(eax));
     if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
     return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
 }
 
 bool
@@ -232,50 +203,28 @@ LIRGeneratorX86Shared::visitAsmJSNeg(MAs
 
     JS_ASSERT(ins->type() == MIRType_Double);
     return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(ins->input())), ins, 0);
 }
 
 bool
 LIRGeneratorX86Shared::lowerUDiv(MDiv *div)
 {
-    // Optimize x/x. The comments in lowerDivI apply here as well.
-    if (div->lhs() == div->rhs()) {
-        if (!div->canBeDivideByZero())
-            return define(new(alloc()) LInteger(1), div);
-
-        LDivSelfI *lir = new(alloc()) LDivSelfI(useRegisterAtStart(div->lhs()));
-        if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
-            return false;
-        return define(lir, div);
-    }
-
-    LUDivOrMod *lir = new(alloc()) LUDivOrMod(useFixedAtStart(div->lhs(), eax),
+    LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(div->lhs()),
                                               useRegister(div->rhs()),
                                               tempFixed(edx));
     if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
     return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
 }
 
 bool
 LIRGeneratorX86Shared::lowerUMod(MMod *mod)
 {
-    // Optimize x%x. The comments in lowerModI apply here as well.
-    if (mod->lhs() == mod->rhs()) {
-        if (mod->isTruncated() || (mod->isUnsigned() && !mod->canBeDivideByZero()))
-            return define(new(alloc()) LInteger(0), mod);
-
-        LModSelfI *lir = new(alloc()) LModSelfI(useRegisterAtStart(mod->lhs()));
-        if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
-            return false;
-        return define(lir, mod);
-    }
-
-    LUDivOrMod *lir = new(alloc()) LUDivOrMod(useFixedAtStart(mod->lhs(), eax),
+    LUDivOrMod *lir = new(alloc()) LUDivOrMod(useRegister(mod->lhs()),
                                               useRegister(mod->rhs()),
                                               tempFixed(eax));
     if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
     return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
 }
 
 bool
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -8,19 +8,17 @@
 #define jit_x64_LOpcodes_x64_h
 
 #define LIR_CPU_OPCODE_LIST(_)      \
     _(Box)                          \
     _(Unbox)                        \
     _(UnboxFloatingPoint)           \
     _(DivI)                         \
     _(DivPowTwoI)                   \
-    _(DivSelfI)                     \
     _(ModI)                         \
     _(ModPowTwoI)                   \
-    _(ModSelfI)                     \
     _(PowHalfD)                     \
     _(AsmJSUInt32ToDouble)          \
     _(AsmJSUInt32ToFloat32)         \
     _(AsmJSLoadFuncPtr)             \
     _(UDivOrMod)
 
 #endif /* jit_x64_LOpcodes_x64_h */
--- a/js/src/jit/x86/LOpcodes-x86.h
+++ b/js/src/jit/x86/LOpcodes-x86.h
@@ -9,19 +9,17 @@
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(Unbox)                    \
     _(UnboxFloatingPoint)       \
     _(Box)                      \
     _(BoxFloatingPoint)         \
     _(DivI)                     \
     _(DivPowTwoI)               \
-    _(DivSelfI)                 \
     _(ModI)                     \
     _(ModPowTwoI)               \
-    _(ModSelfI)                 \
     _(PowHalfD)                 \
     _(AsmJSUInt32ToDouble)      \
     _(AsmJSUInt32ToFloat32)     \
     _(AsmJSLoadFuncPtr)         \
     _(UDivOrMod)
 
 #endif /* jit_x86_LOpcodes_x86_h */