Bug 1279248 - Part 12: Implement the 64bit variant of Div and Mod on x86, r=jandem
authorHannes Verschore <hv1989@gmail.com>
Fri, 29 Jul 2016 16:51:42 +0200
changeset 349403 b15c4d7a91ac77d73cd873b79282b3ffcdf7f952
parent 349402 61f6a14488120dce6b9f9022060d816e23ad54b3
child 349404 39ec8e937bf87e90e3aef6b838b4cf9bba6cdbc8
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1279248
milestone50.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 1279248 - Part 12: Implement the 64bit variant of Div and Mod on x86, r=jandem
js/src/asmjs/WasmTypes.cpp
js/src/asmjs/WasmTypes.h
js/src/jit/MacroAssembler.h
js/src/jit/arm/MacroAssembler-arm-inl.h
js/src/jit/arm64/MacroAssembler-arm64-inl.h
js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
js/src/jit/mips32/MacroAssembler-mips32-inl.h
js/src/jit/mips64/MacroAssembler-mips64-inl.h
js/src/jit/x64/CodeGenerator-x64.cpp
js/src/jit/x64/CodeGenerator-x64.h
js/src/jit/x64/LIR-x64.h
js/src/jit/x64/LOpcodes-x64.h
js/src/jit/x64/Lowering-x64.cpp
js/src/jit/x64/Lowering-x64.h
js/src/jit/x64/MacroAssembler-x64-inl.h
js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
js/src/jit/x86/CodeGenerator-x86.cpp
js/src/jit/x86/CodeGenerator-x86.h
js/src/jit/x86/LIR-x86.h
js/src/jit/x86/LOpcodes-x86.h
js/src/jit/x86/Lowering-x86.cpp
js/src/jit/x86/Lowering-x86.h
js/src/jit/x86/MacroAssembler-x86-inl.h
--- a/js/src/asmjs/WasmTypes.cpp
+++ b/js/src/asmjs/WasmTypes.cpp
@@ -157,16 +157,54 @@ CoerceInPlace_ToNumber(MutableHandleValu
     double dbl;
     if (!ToNumber(cx, val, &dbl))
         return false;
     val.set(DoubleValue(dbl));
 
     return true;
 }
 
+static int64_t
+DivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
+{
+    int64_t x = ((uint64_t)x_hi << 32) + x_lo;
+    int64_t y = ((uint64_t)y_hi << 32) + y_lo;
+    MOZ_ASSERT(x != INT64_MIN || y != -1);
+    MOZ_ASSERT(y != 0);
+    return x / y;
+}
+
+static int64_t
+UDivI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
+{
+    uint64_t x = ((uint64_t)x_hi << 32) + x_lo;
+    uint64_t y = ((uint64_t)y_hi << 32) + y_lo;
+    MOZ_ASSERT(y != 0);
+    return x / y;
+}
+
+static int64_t
+ModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
+{
+    int64_t x = ((uint64_t)x_hi << 32) + x_lo;
+    int64_t y = ((uint64_t)y_hi << 32) + y_lo;
+    MOZ_ASSERT(x != INT64_MIN || y != -1);
+    MOZ_ASSERT(y != 0);
+    return x % y;
+}
+
+static int64_t
+UModI64(uint32_t x_hi, uint32_t x_lo, uint32_t y_hi, uint32_t y_lo)
+{
+    uint64_t x = ((uint64_t)x_hi << 32) + x_lo;
+    uint64_t y = ((uint64_t)y_hi << 32) + y_lo;
+    MOZ_ASSERT(y != 0);
+    return x % y;
+}
+
 template <class F>
 static inline void*
 FuncCast(F* pf, ABIFunctionType type)
 {
     void *pv = JS_FUNC_TO_DATA_PTR(void*, pf);
 #ifdef JS_SIMULATOR
     pv = Simulator::RedirectNativeFunction(pv, type);
 #endif
@@ -196,16 +234,24 @@ wasm::AddressOf(SymbolicAddress imm, Exc
       case SymbolicAddress::CallImport_F64:
         return FuncCast(Instance::callImport_f64, Args_General3);
       case SymbolicAddress::CoerceInPlace_ToInt32:
         return FuncCast(CoerceInPlace_ToInt32, Args_General1);
       case SymbolicAddress::CoerceInPlace_ToNumber:
         return FuncCast(CoerceInPlace_ToNumber, Args_General1);
       case SymbolicAddress::ToInt32:
         return FuncCast<int32_t (double)>(JS::ToInt32, Args_Int_Double);
+      case SymbolicAddress::DivI64:
+        return FuncCast(DivI64, Args_General4);
+      case SymbolicAddress::UDivI64:
+        return FuncCast(UDivI64, Args_General4);
+      case SymbolicAddress::ModI64:
+        return FuncCast(ModI64, Args_General4);
+      case SymbolicAddress::UModI64:
+        return FuncCast(UModI64, Args_General4);
 #if defined(JS_CODEGEN_ARM)
       case SymbolicAddress::aeabi_idivmod:
         return FuncCast(__aeabi_idivmod, Args_General2);
       case SymbolicAddress::aeabi_uidivmod:
         return FuncCast(__aeabi_uidivmod, Args_General2);
       case SymbolicAddress::AtomicCmpXchg:
         return FuncCast<int32_t (int32_t, int32_t, int32_t, int32_t)>(js::atomics_cmpxchg_asm_callout, Args_General4);
       case SymbolicAddress::AtomicXchg:
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -892,16 +892,20 @@ enum class SymbolicAddress
     HandleExecutionInterrupt,
     HandleTrap,
     CallImport_Void,
     CallImport_I32,
     CallImport_I64,
     CallImport_F64,
     CoerceInPlace_ToInt32,
     CoerceInPlace_ToNumber,
+    DivI64,
+    UDivI64,
+    ModI64,
+    UModI64,
     Limit
 };
 
 void*
 AddressOf(SymbolicAddress imm, ExclusiveContext* cx);
 
 // A wasm::Trap is a reason for why we reached a trap in executed code. Each
 // different trap is mapped to a different error message.
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1015,22 +1015,24 @@ class MacroAssembler : public MacroAssem
     template <class L>
     inline void branchTest32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH;
     template <class L>
     inline void branchTest32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH;
     inline void branchTest32(Condition cond, const Address& lhs, Imm32 rhh, Label* label) PER_SHARED_ARCH;
     inline void branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
-    inline void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) PER_SHARED_ARCH;
+    template <class L>
+    inline void branchTestPtr(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH;
     inline void branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
     inline void branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label) PER_SHARED_ARCH;
 
+    template <class L>
     inline void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label) PER_ARCH;
+                             L label) PER_ARCH;
 
     // Branches to |label| if |reg| is false. |reg| should be a C++ bool.
     template <class L>
     inline void branchIfFalseBool(Register reg, L label);
 
     // Branches to |label| if |reg| is true. |reg| should be a C++ bool.
     inline void branchIfTrueBool(Register reg, Label* label);
 
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -993,37 +993,39 @@ void
 MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
 {
     // branchTest32 will use ScratchRegister.
     AutoRegisterScope scratch2(*this, secondScratchReg_);
     load32(lhs, scratch2);
     branchTest32(cond, scratch2, rhs, label);
 }
 
+template <class L>
 void
-MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, L label)
 {
     branchTest32(cond, lhs, rhs, label);
 }
 
 void
 MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
 {
     branchTest32(cond, lhs, rhs, label);
 }
 
 void
 MacroAssembler::branchTestPtr(Condition cond, const Address& lhs, Imm32 rhs, Label* label)
 {
     branchTest32(cond, lhs, rhs, label);
 }
 
+template <class L>
 void
 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label)
+                             L label)
 {
     if (cond == Assembler::Zero) {
         MOZ_ASSERT(lhs.low == rhs.low);
         MOZ_ASSERT(lhs.high == rhs.high);
         ma_orr(lhs.low, lhs.high, ScratchRegister);
         branchTestPtr(cond, ScratchRegister, ScratchRegister, label);
     } else {
         MOZ_CRASH("Unsupported condition");
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -1037,18 +1037,19 @@ void
 MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
 {
     vixl::UseScratchRegisterScope temps(this);
     const Register scratch = temps.AcquireX().asUnsized();
     load32(lhs, scratch);
     branchTest32(cond, scratch, rhs, label);
 }
 
+template <class L>
 void
-MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, L label)
 {
     Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64)));
     B(label, cond);
 }
 
 void
 MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
 {
@@ -1061,19 +1062,20 @@ MacroAssembler::branchTestPtr(Condition 
 {
     vixl::UseScratchRegisterScope temps(this);
     const Register scratch = temps.AcquireX().asUnsized();
     MOZ_ASSERT(scratch != lhs.base);
     loadPtr(lhs, scratch);
     branchTestPtr(cond, scratch, rhs, label);
 }
 
+template <class L>
 void
 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label)
+                             L label)
 {
     branchTestPtr(cond, lhs.reg, rhs.reg, label);
 }
 
 void
 MacroAssembler::branchTestUndefined(Condition cond, Register tag, Label* label)
 {
     branchTestUndefinedImpl(cond, tag, label);
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
@@ -668,18 +668,19 @@ MacroAssembler::branchTest32(Condition c
 
 void
 MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
 {
     load32(lhs, SecondScratchReg);
     branchTest32(cond, SecondScratchReg, rhs, label);
 }
 
+template <class L>
 void
-MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, L label)
 {
     MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
     if (lhs == rhs) {
         ma_b(lhs, rhs, label, cond);
     } else {
         as_and(ScratchRegister, lhs, rhs);
         ma_b(ScratchRegister, ScratchRegister, label, cond);
     }
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -295,19 +295,20 @@ MacroAssembler::branch64(Condition cond,
 }
 
 void
 MacroAssembler::branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label)
 {
     branchPtr(cond, lhs, rhs, label);
 }
 
+template <class L>
 void
 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label)
+                             L label)
 {
     if (cond == Assembler::Zero) {
         MOZ_ASSERT(lhs.low == rhs.low);
         MOZ_ASSERT(lhs.high == rhs.high);
         as_or(ScratchRegister, lhs.low, lhs.high);
         branchTestPtr(cond, ScratchRegister, ScratchRegister, label);
     } else {
         MOZ_CRASH("Unsupported condition");
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -234,19 +234,20 @@ MacroAssembler::branchPrivatePtr(Conditi
 {
     if (rhs != ScratchRegister)
         movePtr(rhs, ScratchRegister);
     // Instead of unboxing lhs, box rhs and do direct comparison with lhs.
     rshiftPtr(Imm32(1), ScratchRegister);
     branchPtr(cond, lhs, ScratchRegister, label);
 }
 
+template <class L>
 void
 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label)
+                             L label)
 {
     branchTestPtr(cond, lhs.reg, rhs.reg, label);
 }
 
 void
 MacroAssembler::branchTestUndefined(Condition cond, const ValueOperand& value, Label* label)
 {
     SecondScratchRegisterScope scratch2(*this);
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -302,17 +302,17 @@ CodeGeneratorX64::visitDivOrModI64(LDivO
     // Sign extend the lhs into rdx to make rdx:rax.
     masm.cqo();
     masm.idivq(rhs);
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorX64::visitUDivOrMod64(LUDivOrMod64* lir)
+CodeGeneratorX64::visitUDivOrModI64(LUDivOrModI64* lir)
 {
     Register lhs = ToRegister(lir->lhs());
     Register rhs = ToRegister(lir->rhs());
 
     DebugOnly<Register> output = ToRegister(lir->output());
     MOZ_ASSERT_IF(lhs != rhs, rhs != rax);
     MOZ_ASSERT(rhs != rdx);
     MOZ_ASSERT_IF(output.value == rax, ToRegister(lir->remainder()) == rdx);
--- a/js/src/jit/x64/CodeGenerator-x64.h
+++ b/js/src/jit/x64/CodeGenerator-x64.h
@@ -48,17 +48,17 @@ class CodeGeneratorX64 : public CodeGene
     void visitUnbox(LUnbox* unbox);
     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 visitUDivOrMod64(LUDivOrMod64* lir);
+    void visitUDivOrModI64(LUDivOrModI64* lir);
     void visitNotI64(LNotI64* lir);
     void visitClzI64(LClzI64* lir);
     void visitCtzI64(LCtzI64* lir);
     void visitPopcntI64(LPopcntI64* lir);
     void visitTruncateDToInt32(LTruncateDToInt32* ins);
     void visitTruncateFToInt32(LTruncateFToInt32* ins);
     void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
     void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
--- a/js/src/jit/x64/LIR-x64.h
+++ b/js/src/jit/x64/LIR-x64.h
@@ -109,22 +109,22 @@ class LDivOrModI64 : public LBinaryMath<
             return mir_->toMod()->canBeNegativeDividend();
         return mir_->toDiv()->canBeNegativeOverflow();
     }
 };
 
 // This class performs a simple x86 'div', yielding either a quotient or
 // remainder depending on whether this instruction is defined to output
 // rax (quotient) or rdx (remainder).
-class LUDivOrMod64 : public LBinaryMath<1>
+class LUDivOrModI64 : public LBinaryMath<1>
 {
   public:
-    LIR_HEADER(UDivOrMod64);
+    LIR_HEADER(UDivOrModI64);
 
-    LUDivOrMod64(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
+    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);
     }
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -7,17 +7,17 @@
 #ifndef jit_x64_LOpcodes_x64_h
 #define jit_x64_LOpcodes_x64_h
 
 #include "jit/shared/LOpcodes-shared.h"
 
 #define LIR_CPU_OPCODE_LIST(_)      \
     _(DivOrModConstantI)            \
     _(DivOrModI64)                  \
-    _(UDivOrMod64)                  \
+    _(UDivOrModI64)                 \
     _(WasmTruncateToInt64)          \
     _(Int64ToFloatingPoint)         \
     _(SimdValueInt32x4)             \
     _(SimdValueFloat32x4)           \
     _(UDivOrMod)                    \
     _(UDivOrModConstant)
 
 #endif /* jit_x64_LOpcodes_x64_h */
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -412,53 +412,53 @@ LIRGeneratorX64::visitRandom(MRandom* in
                                         temp());
     defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
 }
 
 void
 LIRGeneratorX64::lowerDivI64(MDiv* div)
 {
     if (div->isUnsigned()) {
-        lowerUDiv64(div);
+        lowerUDivI64(div);
         return;
     }
 
     LDivOrModI64* lir = new(alloc()) LDivOrModI64(useRegister(div->lhs()), useRegister(div->rhs()),
                                                   tempFixed(rdx));
     defineInt64Fixed(lir, div, LInt64Allocation(LAllocation(AnyRegister(rax))));
 }
 
 void
 LIRGeneratorX64::lowerModI64(MMod* mod)
 {
     if (mod->isUnsigned()) {
-        lowerUMod64(mod);
+        lowerUModI64(mod);
         return;
     }
 
     LDivOrModI64* lir = new(alloc()) LDivOrModI64(useRegister(mod->lhs()), useRegister(mod->rhs()),
                                                   tempFixed(rax));
     defineInt64Fixed(lir, mod, LInt64Allocation(LAllocation(AnyRegister(rdx))));
 }
 
 void
-LIRGeneratorX64::lowerUDiv64(MDiv* div)
+LIRGeneratorX64::lowerUDivI64(MDiv* div)
 {
-    LUDivOrMod64* lir = new(alloc()) LUDivOrMod64(useRegister(div->lhs()),
-                                                  useRegister(div->rhs()),
-                                                  tempFixed(rdx));
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(div->lhs()),
+                                                    useRegister(div->rhs()),
+                                                    tempFixed(rdx));
     defineInt64Fixed(lir, div, LInt64Allocation(LAllocation(AnyRegister(rax))));
 }
 
 void
-LIRGeneratorX64::lowerUMod64(MMod* mod)
+LIRGeneratorX64::lowerUModI64(MMod* mod)
 {
-    LUDivOrMod64* lir = new(alloc()) LUDivOrMod64(useRegister(mod->lhs()),
-                                                  useRegister(mod->rhs()),
-                                                  tempFixed(rax));
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useRegister(mod->lhs()),
+                                                    useRegister(mod->rhs()),
+                                                    tempFixed(rax));
     defineInt64Fixed(lir, mod, LInt64Allocation(LAllocation(AnyRegister(rdx))));
 }
 
 void
 LIRGeneratorX64::visitWasmTruncateToInt64(MWasmTruncateToInt64* ins)
 {
     MDefinition* opd = ins->input();
     MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -39,18 +39,18 @@ class LIRGeneratorX64 : public LIRGenera
     LDefinition tempByteOpRegister();
 
     LDefinition tempToUnbox();
 
     bool needTempForPostBarrier() { return false; }
 
     void lowerDivI64(MDiv* div);
     void lowerModI64(MMod* mod);
-    void lowerUDiv64(MDiv* div);
-    void lowerUMod64(MMod* mod);
+    void lowerUDivI64(MDiv* div);
+    void lowerUModI64(MMod* mod);
 
   public:
     void visitBox(MBox* box);
     void visitUnbox(MUnbox* unbox);
     void visitReturn(MReturn* ret);
     void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
     void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
     void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -680,19 +680,20 @@ MacroAssembler::branchTest32(Condition c
     } else {
         ScratchRegisterScope scratch(*this);
         mov(ImmPtr(lhs.addr), scratch);
         test32(Operand(scratch, 0), rhs);
     }
     j(cond, label);
 }
 
+template <class L>
 void
 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label)
+                             L label)
 {
     branchTestPtr(cond, lhs.reg, rhs.reg, label);
 }
 
 void
 MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label)
 {
     test32(value.valueReg(), value.valueReg());
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
@@ -672,18 +672,19 @@ MacroAssembler::branchTest32(Condition c
 void
 MacroAssembler::branchTest32(Condition cond, const Address& lhs, Imm32 rhs, Label* label)
 {
     MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
     test32(Operand(lhs), rhs);
     j(cond, label);
 }
 
+template <class L>
 void
-MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label)
+MacroAssembler::branchTestPtr(Condition cond, Register lhs, Register rhs, L label)
 {
     testPtr(lhs, rhs);
     j(cond, label);
 }
 
 void
 MacroAssembler::branchTestPtr(Condition cond, Register lhs, Imm32 rhs, Label* label)
 {
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -1303,8 +1303,101 @@ CodeGeneratorX86::visitCompareI64AndBran
         jumpToBlock(lir->ifTrue(), cond3);
         jumpToBlock(lir->ifFalse());
         break;
       }
       default:
         MOZ_CRASH("unexpected op");
     }
 }
+
+void
+CodeGeneratorX86::visitDivOrModI64(LDivOrModI64* lir)
+{
+    Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
+    Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
+    Register64 output = ToOutRegister64(lir);
+
+    MOZ_ASSERT(output == ReturnReg64);
+
+    // We are free to clobber all registers, since this is a call instruction.
+    AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
+    regs.take(lhs.low);
+    regs.take(lhs.high);
+    regs.take(rhs.low);
+    regs.take(rhs.high);
+    Register temp = regs.takeAny();
+
+    Label done;
+
+    // Handle divide by zero.
+    if (lir->canBeDivideByZero())
+        masm.branchTest64(Assembler::Zero, rhs, rhs, temp, wasm::JumpTarget::IntegerDivideByZero);
+
+    // Handle an integer overflow exception from INT64_MIN / -1.
+    if (lir->canBeNegativeOverflow()) {
+        Label notmin;
+        masm.branch64(Assembler::NotEqual, lhs, Imm64(INT64_MIN), &notmin);
+        masm.branch64(Assembler::NotEqual, rhs, Imm64(-1), &notmin);
+        if (lir->mir()->isMod())
+            masm.xor64(output, output);
+        else
+            masm.jump(wasm::JumpTarget::IntegerOverflow);
+        masm.jump(&done);
+        masm.bind(&notmin);
+    }
+
+    masm.setupUnalignedABICall(temp);
+    masm.passABIArg(lhs.high);
+    masm.passABIArg(lhs.low);
+    masm.passABIArg(rhs.high);
+    masm.passABIArg(rhs.low);
+
+    MOZ_ASSERT(gen->compilingAsmJS());
+    if (lir->mir()->isMod())
+        masm.callWithABI(wasm::SymbolicAddress::ModI64);
+    else
+        masm.callWithABI(wasm::SymbolicAddress::DivI64);
+
+    // output in edx:eax, move to output register.
+    masm.movl(edx, output.high);
+    MOZ_ASSERT(eax == output.low);
+
+    masm.bind(&done);
+}
+
+void
+CodeGeneratorX86::visitUDivOrModI64(LUDivOrModI64* lir)
+{
+    Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
+    Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
+    Register64 output = ToOutRegister64(lir);
+
+    MOZ_ASSERT(output == ReturnReg64);
+
+    // We are free to clobber all registers, since this is a call instruction.
+    AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
+    regs.take(lhs.low);
+    regs.take(lhs.high);
+    regs.take(rhs.low);
+    regs.take(rhs.high);
+    Register temp = regs.takeAny();
+
+    // Prevent divide by zero.
+    if (lir->canBeDivideByZero())
+        masm.branchTest64(Assembler::Zero, rhs, rhs, temp, wasm::JumpTarget::IntegerDivideByZero);
+
+    masm.setupUnalignedABICall(temp);
+    masm.passABIArg(lhs.high);
+    masm.passABIArg(lhs.low);
+    masm.passABIArg(rhs.high);
+    masm.passABIArg(rhs.low);
+
+    MOZ_ASSERT(gen->compilingAsmJS());
+    if (lir->mir()->isMod())
+        masm.callWithABI(wasm::SymbolicAddress::UModI64);
+    else
+        masm.callWithABI(wasm::SymbolicAddress::UDivI64);
+
+    // output in edx:eax, move to output register.
+    masm.movl(edx, output.high);
+    MOZ_ASSERT(eax == output.low);
+}
--- a/js/src/jit/x86/CodeGenerator-x86.h
+++ b/js/src/jit/x86/CodeGenerator-x86.h
@@ -70,16 +70,18 @@ class CodeGeneratorX86 : public CodeGene
     void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins);
     void visitWasmTruncateToInt32(LWasmTruncateToInt32* ins);
 
     void visitOutOfLineTruncate(OutOfLineTruncate* ool);
     void visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool);
 
     void visitCompareI64(LCompareI64* lir);
     void visitCompareI64AndBranch(LCompareI64AndBranch* lir);
+    void visitDivOrModI64(LDivOrModI64* lir);
+    void visitUDivOrModI64(LUDivOrModI64* lir);
 
   private:
     void asmJSAtomicComputeAddress(Register addrTemp, Register ptrReg,
                                    const MWasmMemoryAccess* access);
 };
 
 typedef CodeGeneratorX86 CodeGeneratorSpecific;
 
--- a/js/src/jit/x86/LIR-x86.h
+++ b/js/src/jit/x86/LIR-x86.h
@@ -104,12 +104,72 @@ class LAsmJSUInt32ToFloat32: public LIns
         setOperand(0, input);
         setTemp(0, temp);
     }
     const LDefinition* temp() {
         return getTemp(0);
     }
 };
 
+class LDivOrModI64 : public LCallInstructionHelper<INT64_PIECES, INT64_PIECES*2, 0>
+{
+  public:
+    LIR_HEADER(DivOrModI64)
+
+    static const size_t Lhs = 0;
+    static const size_t Rhs = INT64_PIECES;
+
+    LDivOrModI64(const LInt64Allocation& lhs, const LInt64Allocation& rhs)
+    {
+        setInt64Operand(Lhs, lhs);
+        setInt64Operand(Rhs, rhs);
+    }
+
+    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 LCallInstructionHelper<INT64_PIECES, INT64_PIECES*2, 0>
+{
+  public:
+    LIR_HEADER(UDivOrModI64)
+
+    static const size_t Lhs = 0;
+    static const size_t Rhs = INT64_PIECES;
+
+    LUDivOrModI64(const LInt64Allocation& lhs, const LInt64Allocation& rhs)
+    {
+        setInt64Operand(Lhs, lhs);
+        setInt64Operand(Rhs, rhs);
+    }
+
+    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();
+    }
+};
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_LIR_x86_h */
--- a/js/src/jit/x86/LOpcodes-x86.h
+++ b/js/src/jit/x86/LOpcodes-x86.h
@@ -10,11 +10,13 @@
 #include "jit/shared/LOpcodes-shared.h"
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(BoxFloatingPoint)         \
     _(DivOrModConstantI)        \
     _(SimdValueInt32x4)         \
     _(SimdValueFloat32x4)       \
     _(UDivOrMod)                \
-    _(UDivOrModConstant)
+    _(UDivOrModConstant)        \
+    _(UDivOrModI64)             \
+    _(DivOrModI64)
 
 #endif /* jit_x86_LOpcodes_x86_h */
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -515,23 +515,53 @@ LIRGeneratorX86::visitAsmJSAtomicBinopHe
         define(lir, ins);
     else
         defineReuseInput(lir, ins, LAsmJSAtomicBinopHeap::valueOp);
 }
 
 void
 LIRGeneratorX86::lowerDivI64(MDiv* div)
 {
-    MOZ_CRASH("NYI");
+    if (div->isUnsigned()) {
+        lowerUDivI64(div);
+        return;
+    }
+
+    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(div->lhs()),
+                                                  useInt64RegisterAtStart(div->rhs()));
+    defineReturn(lir, div);
 }
 
 void
 LIRGeneratorX86::lowerModI64(MMod* mod)
 {
-    MOZ_CRASH("NYI");
+    if (mod->isUnsigned()) {
+        lowerUModI64(mod);
+        return;
+    }
+
+    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
+                                                  useInt64RegisterAtStart(mod->rhs()));
+    defineReturn(lir, mod);
+}
+
+void
+LIRGeneratorX86::lowerUDivI64(MDiv* div)
+{
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(div->lhs()),
+                                                    useInt64RegisterAtStart(div->rhs()));
+    defineReturn(lir, div);
+}
+
+void
+LIRGeneratorX86::lowerUModI64(MMod* mod)
+{
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
+                                                    useInt64RegisterAtStart(mod->rhs()));
+    defineReturn(lir, mod);
 }
 
 void
 LIRGeneratorX86::visitSubstr(MSubstr* ins)
 {
     // Due to lack of registers on x86, we reuse the string register as
     // temporary. As a result we only need two temporary registers and take a
     // bugos temporary as fifth argument.
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -46,16 +46,18 @@ class LIRGeneratorX86 : public LIRGenera
     void defineInt64Phi(MPhi* phi, size_t lirIndex);
 
     void lowerForALUInt64(LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* ins,
                           MDefinition* mir, MDefinition* lhs, MDefinition* rhs);
     void lowerForMulInt64(LMulI64* ins, MMul* mir, MDefinition* lhs, MDefinition* rhs);
 
     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 visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement* ins);
     void visitAtomicExchangeTypedArrayElement(MAtomicExchangeTypedArrayElement* ins);
     void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop* ins);
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -729,19 +729,20 @@ MacroAssembler::branchTruncateDouble(Flo
 
 void
 MacroAssembler::branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
 {
     test32(Operand(lhs), rhs);
     j(cond, label);
 }
 
+template <class L>
 void
 MacroAssembler::branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp,
-                             Label* label)
+                             L label)
 {
     if (cond == Assembler::Zero) {
         MOZ_ASSERT(lhs.low == rhs.low);
         MOZ_ASSERT(lhs.high == rhs.high);
         movl(lhs.low, temp);
         orl(lhs.high, temp);
         branchTestPtr(cond, temp, temp, label);
     } else {