Bug 1290812 - Part 10: Implement the 64bit variant of Div and Mod on mips64. r=jandem
authorHeiher <r@hev.cc>
Mon, 10 Oct 2016 17:08:01 +0800
changeset 317284 3adcf117e4ed54c41e04c02c7500bbb97ce5ccc9
parent 317283 381865deea13ac3fe9da91be3b2a4cafbc29223c
child 317285 1fdf443d5f1c9c7c3882ccd945b9d25024877639
push id30800
push userphilringnalda@gmail.com
push dateTue, 11 Oct 2016 02:08:53 +0000
treeherdermozilla-central@ece56e142a1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1290812
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1290812 - Part 10: Implement the 64bit variant of Div and Mod on mips64. r=jandem --- js/src/jit/mips-shared/Lowering-mips-shared.cpp | 12 ----- js/src/jit/mips-shared/Lowering-mips-shared.h | 2 - js/src/jit/mips64/CodeGenerator-mips64.cpp | 59 +++++++++++++++++++++++ js/src/jit/mips64/CodeGenerator-mips64.h | 2 + js/src/jit/mips64/LIR-mips64.h | 62 +++++++++++++++++++++++++ js/src/jit/mips64/LOpcodes-mips64.h | 4 +- js/src/jit/mips64/Lowering-mips64.cpp | 44 ++++++++++++++++++ js/src/jit/mips64/Lowering-mips64.h | 5 ++ 8 files changed, 175 insertions(+), 15 deletions(-)
js/src/jit/mips-shared/Lowering-mips-shared.cpp
js/src/jit/mips-shared/Lowering-mips-shared.h
js/src/jit/mips64/CodeGenerator-mips64.cpp
js/src/jit/mips64/CodeGenerator-mips64.h
js/src/jit/mips64/LIR-mips64.h
js/src/jit/mips64/LOpcodes-mips64.h
js/src/jit/mips64/Lowering-mips64.cpp
js/src/jit/mips64/Lowering-mips64.h
--- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp
@@ -221,28 +221,16 @@ LIRGeneratorMIPSShared::lowerModI(MMod* 
                            temp(LDefinition::GENERAL));
 
     if (mod->fallible())
         assignSnapshot(lir, Bailout_DoubleOutput);
     define(lir, mod);
 }
 
 void
-LIRGeneratorMIPSShared::lowerDivI64(MDiv* div)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
-LIRGeneratorMIPSShared::lowerModI64(MMod* mod)
-{
-    MOZ_CRASH("NYI");
-}
-
-void
 LIRGeneratorMIPSShared::visitPowHalf(MPowHalf* ins)
 {
     MDefinition* input = ins->input();
     MOZ_ASSERT(input->type() == MIRType::Double);
     LPowHalfD* lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
     defineReuseInput(lir, ins, 0);
 }
 
--- a/js/src/jit/mips-shared/Lowering-mips-shared.h
+++ b/js/src/jit/mips-shared/Lowering-mips-shared.h
@@ -61,18 +61,16 @@ class LIRGeneratorMIPSShared : public LI
     {
         return lowerForFPU(ins, mir, lhs, rhs);
     }
 
     void lowerForBitAndAndBranch(LBitAndAndBranch* baab, MInstruction* mir,
                                  MDefinition* lhs, MDefinition* rhs);
     void lowerDivI(MDiv* div);
     void lowerModI(MMod* mod);
-    void lowerDivI64(MDiv* div);
-    void lowerModI64(MMod* mod);
     void lowerMulI(MMul* mul, MDefinition* lhs, MDefinition* rhs);
     void lowerUDiv(MDiv* div);
     void lowerUMod(MMod* mod);
     void visitPowHalf(MPowHalf* ins);
     void visitAsmJSNeg(MAsmJSNeg* ins);
     void visitWasmLoad(MWasmLoad* ins);
     void visitWasmStore(MWasmStore* ins);
     void visitAsmSelect(MAsmSelect* ins);
--- a/js/src/jit/mips64/CodeGenerator-mips64.cpp
+++ b/js/src/jit/mips64/CodeGenerator-mips64.cpp
@@ -347,16 +347,75 @@ CodeGeneratorMIPS64::visitCompareI64AndB
     }
 
     bool isSigned = mir->compareType() == MCompare::Compare_Int64;
     Assembler::Condition cond = JSOpToCondition(lir->jsop(), isSigned);
     emitBranch(lhsReg, rhsReg, cond, lir->ifTrue(), lir->ifFalse());
 }
 
 void
+CodeGeneratorMIPS64::visitDivOrModI64(LDivOrModI64* lir)
+{
+    Register lhs = ToRegister(lir->lhs());
+    Register rhs = ToRegister(lir->rhs());
+    Register output = ToRegister(lir->output());
+
+    Label done;
+
+    // Handle divide by zero.
+    if (lir->canBeDivideByZero())
+        masm.ma_b(rhs, rhs, wasm::JumpTarget::IntegerDivideByZero, Assembler::Zero);
+
+    // Handle an integer overflow exception from INT64_MIN / -1.
+    if (lir->canBeNegativeOverflow()) {
+        Label notmin;
+        masm.branchPtr(Assembler::NotEqual, lhs, ImmWord(INT64_MIN), &notmin);
+        masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(-1), &notmin);
+        if (lir->mir()->isMod())
+            masm.ma_xor(output, output);
+        else
+            masm.jump(wasm::JumpTarget::IntegerOverflow);
+        masm.jump(&done);
+        masm.bind(&notmin);
+    }
+
+    masm.as_ddiv(lhs, rhs);
+
+    if (lir->mir()->isMod())
+        masm.as_mfhi(output);
+    else
+        masm.as_mflo(output);
+
+    masm.bind(&done);
+}
+
+void
+CodeGeneratorMIPS64::visitUDivOrModI64(LUDivOrModI64* lir)
+{
+    Register lhs = ToRegister(lir->lhs());
+    Register rhs = ToRegister(lir->rhs());
+    Register output = ToRegister(lir->output());
+
+    Label done;
+
+    // Prevent divide by zero.
+    if (lir->canBeDivideByZero())
+        masm.ma_b(rhs, rhs, wasm::JumpTarget::IntegerDivideByZero, Assembler::Zero);
+
+    masm.as_ddivu(lhs, rhs);
+
+    if (lir->mir()->isMod())
+        masm.as_mfhi(output);
+    else
+        masm.as_mflo(output);
+
+    masm.bind(&done);
+}
+
+void
 CodeGeneratorMIPS64::visitWasmLoadI64(LWasmLoadI64* lir)
 {
     const MWasmLoad* mir = lir->mir();
 
     MOZ_ASSERT(lir->mir()->type() == MIRType::Int64);
     MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
 
     uint32_t offset = mir->offset();
--- a/js/src/jit/mips64/CodeGenerator-mips64.h
+++ b/js/src/jit/mips64/CodeGenerator-mips64.h
@@ -41,16 +41,18 @@ class CodeGeneratorMIPS64 : public CodeG
 
   public:
     void visitCompareB(LCompareB* lir);
     void visitCompareBAndBranch(LCompareBAndBranch* lir);
     void visitCompareBitwise(LCompareBitwise* lir);
     void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir);
     void visitCompareI64(LCompareI64* lir);
     void visitCompareI64AndBranch(LCompareI64AndBranch* lir);
+    void visitDivOrModI64(LDivOrModI64* lir);
+    void visitUDivOrModI64(LUDivOrModI64* lir);
     void visitWasmLoadI64(LWasmLoadI64* lir);
     void visitAsmSelectI64(LAsmSelectI64* ins);
     void visitAsmReinterpretFromI64(LAsmReinterpretFromI64* lir);
     void visitAsmReinterpretToI64(LAsmReinterpretToI64* lir);
 
     // Out of line visitors.
     void visitOutOfLineBailout(OutOfLineBailout* ool);
     void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
--- a/js/src/jit/mips64/LIR-mips64.h
+++ b/js/src/jit/mips64/LIR-mips64.h
@@ -41,12 +41,74 @@ class LUnboxFloatingPoint : public LUnbo
         type_(type)
     { }
 
     MIRType type() const {
         return type_;
     }
 };
 
+class LDivOrModI64 : public LBinaryMath<1>
+{
+  public:
+    LIR_HEADER(DivOrModI64)
+
+    LDivOrModI64(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
+        setOperand(0, lhs);
+        setOperand(1, rhs);
+        setTemp(0, temp);
+    }
+
+    const LDefinition* remainder() {
+        return getTemp(0);
+    }
+
+    MBinaryArithInstruction* mir() const {
+        MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
+        return static_cast<MBinaryArithInstruction*>(mir_);
+    }
+    bool canBeDivideByZero() const {
+        if (mir_->isMod())
+            return mir_->toMod()->canBeDivideByZero();
+        return mir_->toDiv()->canBeDivideByZero();
+    }
+    bool canBeNegativeOverflow() const {
+        if (mir_->isMod())
+            return mir_->toMod()->canBeNegativeDividend();
+        return mir_->toDiv()->canBeNegativeOverflow();
+    }
+};
+
+class LUDivOrModI64 : public LBinaryMath<1>
+{
+  public:
+    LIR_HEADER(UDivOrModI64);
+
+    LUDivOrModI64(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
+        setOperand(0, lhs);
+        setOperand(1, rhs);
+        setTemp(0, temp);
+    }
+
+    const LDefinition* remainder() {
+        return getTemp(0);
+    }
+
+    const char* extraName() const {
+        return mir()->isTruncated() ? "Truncated" : nullptr;
+    }
+
+    MBinaryArithInstruction* mir() const {
+        MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
+        return static_cast<MBinaryArithInstruction*>(mir_);
+    }
+
+    bool canBeDivideByZero() const {
+        if (mir_->isMod())
+            return mir_->toMod()->canBeDivideByZero();
+        return mir_->toDiv()->canBeDivideByZero();
+    }
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips64_LIR_mips64_h */
--- a/js/src/jit/mips64/LOpcodes-mips64.h
+++ b/js/src/jit/mips64/LOpcodes-mips64.h
@@ -6,11 +6,13 @@
 
 #ifndef jit_mips64_LOpcodes_mips64_h__
 #define jit_mips64_LOpcodes_mips64_h__
 
 #include "jit/shared/LOpcodes-shared.h"
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(ModMaskI)                 \
-    _(UDivOrMod)
+    _(DivOrModI64)              \
+    _(UDivOrMod)                \
+    _(UDivOrModI64)
 
 #endif // jit_mips64_LOpcodes_mips64_h__
--- a/js/src/jit/mips64/Lowering-mips64.cpp
+++ b/js/src/jit/mips64/Lowering-mips64.cpp
@@ -33,16 +33,60 @@ LIRGeneratorMIPS64::useBoxFixed(MDefinit
 {
     MOZ_ASSERT(mir->type() == MIRType::Value);
 
     ensureDefined(mir);
     return LBoxAllocation(LUse(reg1, mir->virtualRegister(), useAtStart));
 }
 
 void
+LIRGeneratorMIPS64::lowerDivI64(MDiv* div)
+{
+    if (div->isUnsigned()) {
+        lowerUDivI64(div);
+        return;
+    }
+
+    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useRegister(div->lhs()), useRegister(div->rhs()),
+                                                  temp());
+    defineInt64(lir, div);
+}
+
+void
+LIRGeneratorMIPS64::lowerModI64(MMod* mod)
+{
+    if (mod->isUnsigned()) {
+        lowerUModI64(mod);
+        return;
+    }
+
+    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useRegister(mod->lhs()), useRegister(mod->rhs()),
+                                                  temp());
+    defineInt64(lir, mod);
+}
+
+void
+LIRGeneratorMIPS64::lowerUDivI64(MDiv* div)
+{
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(div->lhs()),
+                                                    useRegister(div->rhs()),
+                                                    temp());
+    defineInt64(lir, div);
+}
+
+void
+LIRGeneratorMIPS64::lowerUModI64(MMod* mod)
+{
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(mod->lhs()),
+                                                    useRegister(mod->rhs()),
+                                                    temp());
+    defineInt64(lir, mod);
+}
+
+void
 LIRGeneratorMIPS64::visitBox(MBox* box)
 {
     MDefinition* opd = box->getOperand(0);
 
     // If the operand is a constant, emit near its uses.
     if (opd->isConstant() && box->canEmitAtUses()) {
         emitAtUses(box);
         return;
--- a/js/src/jit/mips64/Lowering-mips64.h
+++ b/js/src/jit/mips64/Lowering-mips64.h
@@ -32,16 +32,21 @@ class LIRGeneratorMIPS64 : public LIRGen
     }
 
     void lowerUntypedPhiInput(MPhi* phi, uint32_t inputPosition, LBlock* block, size_t lirIndex);
     void defineUntypedPhi(MPhi* phi, size_t lirIndex);
 
     void lowerTruncateDToInt32(MTruncateToInt32* ins);
     void lowerTruncateFToInt32(MTruncateToInt32* ins);
 
+    void lowerDivI64(MDiv* div);
+    void lowerModI64(MMod* mod);
+    void lowerUDivI64(MDiv* div);
+    void lowerUModI64(MMod* mod);
+
   public:
     void visitBox(MBox* box);
     void visitUnbox(MUnbox* unbox);
     void visitReturn(MReturn* ret);
     void visitRandom(MRandom* ins);
 };
 
 typedef LIRGeneratorMIPS64 LIRGeneratorSpecific;