commit 9facb17058555906d21c74efef7fbb338dd96d5a parent 86937429cf28205d79998d147380193138a6b7c3 Author: Sandor Molnar <smolnar@mozilla.com> Date: Tue, 21 Oct 2025 20:22:55 +0300 Revert "Bug 1995387: Change division and remainder MacroAssembler method to be three-operand instructions. r=spidermonkey-reviewers,jandem" for causing spider-monkey failures. This reverts commit 8f9b2d7dad176ad0b574e9fdb820000a529a5e67. Diffstat:
24 files changed, 513 insertions(+), 522 deletions(-)
diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp @@ -3433,7 +3433,8 @@ bool CacheIRCompiler::emitInt32DivResult(Int32OperandId lhsId, masm.branchTest32(Assembler::Signed, rhs, rhs, failure->label()); masm.bind(¬Zero); - masm.flexibleDivMod32(lhs, rhs, scratch, rem, false, liveVolatileRegs()); + masm.mov(lhs, scratch); + masm.flexibleDivMod32(rhs, scratch, rem, false, liveVolatileRegs()); // A remainder implies a double result. masm.branchTest32(Assembler::NonZero, rem, rem, failure->label()); @@ -3466,7 +3467,8 @@ bool CacheIRCompiler::emitInt32ModResult(Int32OperandId lhsId, masm.branch32(Assembler::Equal, rhs, Imm32(-1), failure->label()); masm.bind(¬Overflow); - masm.flexibleRemainder32(lhs, rhs, scratch, false, liveVolatileRegs()); + masm.mov(lhs, scratch); + masm.flexibleRemainder32(rhs, scratch, false, liveVolatileRegs()); // Modulo takes the sign of the dividend; we can't return negative zero here. Label notZero; @@ -4011,7 +4013,8 @@ bool CacheIRCompiler::emitBigIntPtrDiv(IntPtrOperandId lhsId, LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs()); - masm.flexibleQuotientPtr(lhs, rhs, output, false, volatileRegs); + masm.movePtr(lhs, output); + masm.flexibleQuotientPtr(rhs, output, false, volatileRegs); return true; } @@ -4035,18 +4038,18 @@ bool CacheIRCompiler::emitBigIntPtrMod(IntPtrOperandId lhsId, // Prevent division by 0. masm.branchTestPtr(Assembler::Zero, rhs, rhs, failure->label()); + masm.movePtr(lhs, output); + // Prevent INTPTR_MIN / -1. - Label notOverflow, done; + Label notOverflow; masm.branchPtr(Assembler::NotEqual, lhs, ImmWord(DigitMin), ¬Overflow); masm.branchPtr(Assembler::NotEqual, rhs, Imm32(-1), ¬Overflow); masm.movePtr(ImmWord(0), output); - masm.jump(&done); masm.bind(¬Overflow); LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs()); - masm.flexibleRemainderPtr(lhs, rhs, output, false, volatileRegs); - masm.bind(&done); + masm.flexibleRemainderPtr(rhs, output, false, volatileRegs); return true; } diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp @@ -1996,7 +1996,8 @@ void MacroAssembler::loadInt32ToStringWithBase( branch32(Assembler::AboveOrEqual, input, scratch1, fail); { // Compute |scratch1 = input / base| and |scratch2 = input % base|. - flexibleDivMod32(input, base, scratch1, scratch2, true, volatileRegs); + move32(input, scratch1); + flexibleDivMod32(base, scratch1, scratch2, true, volatileRegs); // Compute the digits of the divisor and remainder. toChar(scratch1); diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h @@ -1212,46 +1212,41 @@ class MacroAssembler : public MacroAssemblerSpecific { // zero. rhs must not be zero, and the division must not overflow. // // On ARM, the chip must have hardware division instructions. - inline void quotient32(Register lhs, Register rhs, Register dest, - bool isUnsigned) + inline void quotient32(Register rhs, Register srcDest, bool isUnsigned) DEFINED_ON(mips64, arm, arm64, loong64, riscv64, wasm32); - inline void quotient64(Register lhs, Register rhs, Register dest, - bool isUnsigned) + inline void quotient64(Register rhs, Register srcDest, bool isUnsigned) DEFINED_ON(arm64, loong64, mips64, riscv64); - // As above, but lhs and dest must be eax and tempEdx must be edx. - inline void quotient32(Register lhs, Register rhs, Register dest, - Register tempEdx, bool isUnsigned) - DEFINED_ON(x86_shared); + // As above, but srcDest must be eax and tempEdx must be edx. + inline void quotient32(Register rhs, Register srcDest, Register tempEdx, + bool isUnsigned) DEFINED_ON(x86_shared); // Perform an integer division, returning the remainder part. // rhs must not be zero, and the division must not overflow. // // On ARM, the chip must have hardware division instructions. - inline void remainder32(Register lhs, Register rhs, Register dest, - bool isUnsigned) + inline void remainder32(Register rhs, Register srcDest, bool isUnsigned) DEFINED_ON(mips64, arm, arm64, loong64, riscv64, wasm32); - inline void remainder64(Register lhs, Register rhs, Register dest, - bool isUnsigned) + inline void remainder64(Register rhs, Register srcDest, bool isUnsigned) DEFINED_ON(arm64, loong64, mips64, riscv64); - // As above, but lhs and dest must be eax and tempEdx must be edx. - inline void remainder32(Register lhs, Register rhs, Register dest, - Register tempEdx, bool isUnsigned) - DEFINED_ON(x86_shared); + // As above, but srcDest must be eax and tempEdx must be edx. + inline void remainder32(Register rhs, Register srcDest, Register tempEdx, + bool isUnsigned) DEFINED_ON(x86_shared); // Perform an integer division, returning the integer part rounded toward // zero. rhs must not be zero, and the division must not overflow. // // This variant preserves registers, and doesn't require hardware division // instructions on ARM (will call out to a runtime routine). - void flexibleRemainder32( - Register lhs, Register rhs, Register dest, bool isUnsigned, - const LiveRegisterSet& volatileLiveRegs) PER_SHARED_ARCH; - void flexibleRemainderPtr(Register lhs, Register rhs, Register dest, - bool isUnsigned, + // + // rhs is preserved, srdDest is clobbered. + void flexibleRemainder32(Register rhs, Register srcDest, bool isUnsigned, + const LiveRegisterSet& volatileLiveRegs) + PER_SHARED_ARCH; + void flexibleRemainderPtr(Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) PER_ARCH; // Perform an integer division, returning the integer part rounded toward @@ -1259,25 +1254,25 @@ class MacroAssembler : public MacroAssemblerSpecific { // // This variant preserves registers, and doesn't require hardware division // instructions on ARM (will call out to a runtime routine). - void flexibleQuotient32( - Register lhs, Register rhs, Register dest, bool isUnsigned, - const LiveRegisterSet& volatileLiveRegs) PER_SHARED_ARCH; - void flexibleQuotientPtr(Register lhs, Register rhs, Register dest, - bool isUnsigned, + // + // rhs is preserved, srdDest is clobbered. + void flexibleQuotient32(Register rhs, Register srcDest, bool isUnsigned, + const LiveRegisterSet& volatileLiveRegs) + PER_SHARED_ARCH; + void flexibleQuotientPtr(Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) PER_ARCH; // Perform an integer division, returning the integer part rounded toward - // zero in the third argument register. rhs must not be zero, and the division - // must not overflow. The remainder is stored into the fourth argument - // register here. + // zero. rhs must not be zero, and the division must not overflow. The + // remainder is stored into the third argument register here. // // This variant preserves registers, and doesn't require hardware division // instructions on ARM (will call out to a runtime routine). // - // lhs and rhs are preserved, divOutput and remOutput are clobbered. + // rhs is preserved, srdDest and remOutput are clobbered. void flexibleDivMod32( - Register lhs, Register rhs, Register divOutput, Register remOutput, - bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) PER_SHARED_ARCH; + Register rhs, Register srcDest, Register remOutput, bool isUnsigned, + const LiveRegisterSet& volatileLiveRegs) PER_SHARED_ARCH; inline void divFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; inline void divDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH; diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -564,25 +564,25 @@ void MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, mulDouble(scratchDouble, dest); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned) { MOZ_ASSERT(ARMFlags::HasIDIV()); if (isUnsigned) { - ma_udiv(lhs, rhs, dest); + ma_udiv(srcDest, rhs, srcDest); } else { - ma_sdiv(lhs, rhs, dest); + ma_sdiv(srcDest, rhs, srcDest); } } -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned) { MOZ_ASSERT(ARMFlags::HasIDIV()); ScratchRegisterScope scratch(*this); if (isUnsigned) { - ma_umod(lhs, rhs, dest, scratch); + ma_umod(srcDest, rhs, srcDest, scratch); } else { - ma_smod(lhs, rhs, dest, scratch); + ma_smod(srcDest, rhs, srcDest, scratch); } } diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -6004,15 +6004,18 @@ extern MOZ_EXPORT int64_t __aeabi_idivmod(int, int); extern MOZ_EXPORT int64_t __aeabi_uidivmod(int, int); } -static void EmitRemainderOrQuotient(bool isRemainder, MacroAssembler& masm, - Register lhs, Register rhs, Register output, +inline void EmitRemainderOrQuotient(bool isRemainder, MacroAssembler& masm, + Register rhs, Register lhsOutput, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { + // Currently this helper can't handle this situation. + MOZ_ASSERT(lhsOutput != rhs); + if (ARMFlags::HasIDIV()) { if (isRemainder) { - masm.remainder32(lhs, rhs, output, isUnsigned); + masm.remainder32(rhs, lhsOutput, isUnsigned); } else { - masm.quotient32(lhs, rhs, output, isUnsigned); + masm.quotient32(rhs, lhsOutput, isUnsigned); } } else { // Ensure that the output registers are saved and restored properly. @@ -6027,7 +6030,7 @@ static void EmitRemainderOrQuotient(bool isRemainder, MacroAssembler& masm, ScratchRegisterScope scratch(masm); masm.setupUnalignedABICall(scratch); } - masm.passABIArg(lhs); + masm.passABIArg(lhsOutput); masm.passABIArg(rhs); if (isUnsigned) { masm.callWithABI<Fn, __aeabi_uidivmod>( @@ -6037,57 +6040,53 @@ static void EmitRemainderOrQuotient(bool isRemainder, MacroAssembler& masm, ABIType::Int64, CheckUnsafeCallWithABI::DontCheckOther); } if (isRemainder) { - masm.mov(ReturnRegVal1, output); + masm.mov(ReturnRegVal1, lhsOutput); } else { - masm.mov(ReturnRegVal0, output); + masm.mov(ReturnRegVal0, lhsOutput); } LiveRegisterSet ignore; - ignore.add(output); + ignore.add(lhsOutput); masm.PopRegsInMaskIgnore(liveRegs, ignore); } } void MacroAssembler::flexibleQuotient32( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - EmitRemainderOrQuotient(false, *this, lhs, rhs, dest, isUnsigned, + EmitRemainderOrQuotient(false, *this, rhs, srcDest, isUnsigned, volatileLiveRegs); } void MacroAssembler::flexibleQuotientPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - flexibleQuotient32(lhs, rhs, dest, isUnsigned, volatileLiveRegs); + flexibleQuotient32(rhs, srcDest, isUnsigned, volatileLiveRegs); } void MacroAssembler::flexibleRemainder32( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - EmitRemainderOrQuotient(true, *this, lhs, rhs, dest, isUnsigned, + EmitRemainderOrQuotient(true, *this, rhs, srcDest, isUnsigned, volatileLiveRegs); } void MacroAssembler::flexibleRemainderPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - flexibleRemainder32(lhs, rhs, dest, isUnsigned, volatileLiveRegs); + flexibleRemainder32(rhs, srcDest, isUnsigned, volatileLiveRegs); } -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, +void MacroAssembler::flexibleDivMod32(Register rhs, Register lhsOutput, + Register remOutput, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - MOZ_ASSERT(lhs != divOutput && lhs != remOutput, "lhs is preserved"); - MOZ_ASSERT(rhs != divOutput && rhs != remOutput, "rhs is preserved"); + // Currently this helper can't handle this situation. + MOZ_ASSERT(lhsOutput != rhs); if (ARMFlags::HasIDIV()) { - if (isUnsigned) { - as_udiv(divOutput, lhs, rhs); - } else { - as_sdiv(divOutput, lhs, rhs); - } - as_mls(remOutput, lhs, divOutput, rhs); + mov(lhsOutput, remOutput); + remainder32(rhs, remOutput, isUnsigned); + quotient32(rhs, lhsOutput, isUnsigned); } else { // Ensure that the output registers are saved and restored properly. LiveRegisterSet liveRegs = volatileLiveRegs; @@ -6101,7 +6100,7 @@ void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, ScratchRegisterScope scratch(*this); setupUnalignedABICall(scratch); } - passABIArg(lhs); + passABIArg(lhsOutput); passABIArg(rhs); if (isUnsigned) { callWithABI<Fn, __aeabi_uidivmod>(ABIType::Int64, @@ -6110,11 +6109,11 @@ void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, callWithABI<Fn, __aeabi_idivmod>(ABIType::Int64, CheckUnsafeCallWithABI::DontCheckOther); } - moveRegPair(ReturnRegVal0, ReturnRegVal1, divOutput, remOutput); + moveRegPair(ReturnRegVal0, ReturnRegVal1, lhsOutput, remOutput); LiveRegisterSet ignore; ignore.add(remOutput); - ignore.add(divOutput); + ignore.add(lhsOutput); PopRegsInMaskIgnore(liveRegs, ignore); } } diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -561,55 +561,62 @@ void MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - Udiv(ARMRegister(dest, 32), ARMRegister(lhs, 32), ARMRegister(rhs, 32)); + Udiv(ARMRegister(srcDest, 32), ARMRegister(srcDest, 32), + ARMRegister(rhs, 32)); } else { - Sdiv(ARMRegister(dest, 32), ARMRegister(lhs, 32), ARMRegister(rhs, 32)); + Sdiv(ARMRegister(srcDest, 32), ARMRegister(srcDest, 32), + ARMRegister(rhs, 32)); } } -void MacroAssembler::quotient64(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient64(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - Udiv(ARMRegister(dest, 64), ARMRegister(lhs, 64), ARMRegister(rhs, 64)); + Udiv(ARMRegister(srcDest, 64), ARMRegister(srcDest, 64), + ARMRegister(rhs, 64)); } else { - Sdiv(ARMRegister(dest, 64), ARMRegister(lhs, 64), ARMRegister(rhs, 64)); + Sdiv(ARMRegister(srcDest, 64), ARMRegister(srcDest, 64), + ARMRegister(rhs, 64)); } } // This does not deal with x % 0 or INT_MIN % -1, the caller needs to filter // those cases when they may occur. -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned) { vixl::UseScratchRegisterScope temps(this); ARMRegister scratch = temps.AcquireW(); if (isUnsigned) { - Udiv(scratch, ARMRegister(lhs, 32), ARMRegister(rhs, 32)); + Udiv(scratch, ARMRegister(srcDest, 32), ARMRegister(rhs, 32)); } else { - Sdiv(scratch, ARMRegister(lhs, 32), ARMRegister(rhs, 32)); + Sdiv(scratch, ARMRegister(srcDest, 32), ARMRegister(rhs, 32)); } - // Compute the remainder: dest = lhs - (scratch * rhs). - Msub(/* result= */ ARMRegister(dest, 32), scratch, ARMRegister(rhs, 32), - ARMRegister(lhs, 32)); + // Compute the remainder: srcDest = srcDest - (scratch * rhs). + Msub(/* result= */ ARMRegister(srcDest, 32), scratch, ARMRegister(rhs, 32), + ARMRegister(srcDest, 32)); } -void MacroAssembler::remainder64(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder64(Register rhs, Register srcDest, bool isUnsigned) { + const ARMRegister dividend64(srcDest, 64); + const ARMRegister divisor64(rhs, 64); + vixl::UseScratchRegisterScope temps(this); ARMRegister scratch64 = temps.AcquireX(); if (isUnsigned) { - Udiv(scratch64, ARMRegister(lhs, 64), ARMRegister(rhs, 64)); + Udiv(scratch64, ARMRegister(srcDest, 64), ARMRegister(rhs, 64)); } else { - Sdiv(scratch64, ARMRegister(lhs, 64), ARMRegister(rhs, 64)); + Sdiv(scratch64, ARMRegister(srcDest, 64), ARMRegister(rhs, 64)); } - // Compute the remainder: dest = lhs - (scratch64 * rhs). - Msub(/* result= */ ARMRegister(dest, 64), scratch64, ARMRegister(rhs, 64), - ARMRegister(lhs, 64)); + // Compute the remainder: srcDest = srcDest - (scratch * rhs). + Msub(/* result= */ ARMRegister(srcDest, 64), scratch64, ARMRegister(rhs, 64), + ARMRegister(srcDest, 64)); } void MacroAssembler::divFloat32(FloatRegister src, FloatRegister dest) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -3274,47 +3274,48 @@ void MacroAssembler::atomicEffectOpJS(Scalar::Type arrayType, void MacroAssembler::atomicPause() { Isb(); } -void MacroAssembler::flexibleQuotient32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleQuotient32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - quotient32(lhs, rhs, dest, isUnsigned); + quotient32(rhs, srcDest, isUnsigned); } void MacroAssembler::flexibleQuotientPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - quotient64(lhs, rhs, dest, isUnsigned); + quotient64(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleRemainder32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleRemainder32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - remainder32(lhs, rhs, dest, isUnsigned); + remainder32(rhs, srcDest, isUnsigned); } void MacroAssembler::flexibleRemainderPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - remainder64(lhs, rhs, dest, isUnsigned); + remainder64(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, const LiveRegisterSet&) { - MOZ_ASSERT(lhs != divOutput && lhs != remOutput, "lhs is preserved"); - MOZ_ASSERT(rhs != divOutput && rhs != remOutput, "rhs is preserved"); +void MacroAssembler::flexibleDivMod32(Register rhs, Register srcDest, + Register remOutput, bool isUnsigned, + const LiveRegisterSet&) { + vixl::UseScratchRegisterScope temps(this); + ARMRegister src = temps.AcquireW(); + + // Preserve src for remainder computation + Mov(src, ARMRegister(srcDest, 32)); if (isUnsigned) { - Udiv(ARMRegister(divOutput, 32), ARMRegister(lhs, 32), - ARMRegister(rhs, 32)); + Udiv(ARMRegister(srcDest, 32), src, ARMRegister(rhs, 32)); } else { - Sdiv(ARMRegister(divOutput, 32), ARMRegister(lhs, 32), - ARMRegister(rhs, 32)); + Sdiv(ARMRegister(srcDest, 32), src, ARMRegister(rhs, 32)); } - // Compute the remainder: remOutput = lhs - (divOutput * rhs). - Msub(/* result= */ ARMRegister(remOutput, 32), ARMRegister(divOutput, 32), - ARMRegister(rhs, 32), ARMRegister(lhs, 32)); + // Compute the remainder: remOutput = src - (srcDest * rhs). + Msub(/* result= */ ARMRegister(remOutput, 32), ARMRegister(srcDest, 32), + ARMRegister(rhs, 32), src); } CodeOffset MacroAssembler::moveNearAddressWithPatch(Register dest) { diff --git a/js/src/jit/loong64/MacroAssembler-loong64-inl.h b/js/src/jit/loong64/MacroAssembler-loong64-inl.h @@ -593,39 +593,39 @@ void MacroAssembler::inc64(AbsoluteAddress dest) { as_st_d(scratch2, scratch, 0); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - as_div_wu(dest, lhs, rhs); + as_div_wu(srcDest, srcDest, rhs); } else { - as_div_w(dest, lhs, rhs); + as_div_w(srcDest, srcDest, rhs); } } -void MacroAssembler::quotient64(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient64(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - as_div_du(dest, lhs, rhs); + as_div_du(srcDest, srcDest, rhs); } else { - as_div_d(dest, lhs, rhs); + as_div_d(srcDest, srcDest, rhs); } } -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - as_mod_wu(dest, lhs, rhs); + as_mod_wu(srcDest, srcDest, rhs); } else { - as_mod_w(dest, lhs, rhs); + as_mod_w(srcDest, srcDest, rhs); } } -void MacroAssembler::remainder64(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder64(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - as_mod_du(dest, lhs, rhs); + as_mod_du(srcDest, srcDest, rhs); } else { - as_mod_d(dest, lhs, rhs); + as_mod_d(srcDest, srcDest, rhs); } } diff --git a/js/src/jit/loong64/MacroAssembler-loong64.cpp b/js/src/jit/loong64/MacroAssembler-loong64.cpp @@ -4600,42 +4600,39 @@ void MacroAssembler::atomicPause() { nop(); } -void MacroAssembler::flexibleQuotient32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleQuotient32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - quotient32(lhs, rhs, dest, isUnsigned); + quotient32(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleQuotientPtr(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleQuotientPtr(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - quotient64(lhs, rhs, dest, isUnsigned); + quotient64(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleRemainder32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleRemainder32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - remainder32(lhs, rhs, dest, isUnsigned); + remainder32(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleRemainderPtr(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleRemainderPtr(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - remainder64(lhs, rhs, dest, isUnsigned); + remainder64(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, const LiveRegisterSet&) { - MOZ_ASSERT(lhs != divOutput && lhs != remOutput, "lhs is preserved"); - MOZ_ASSERT(rhs != divOutput && rhs != remOutput, "rhs is preserved"); - +void MacroAssembler::flexibleDivMod32(Register rhs, Register srcDest, + Register remOutput, bool isUnsigned, + const LiveRegisterSet&) { if (isUnsigned) { - as_div_wu(divOutput, lhs, rhs); - as_mod_wu(remOutput, lhs, rhs); + as_mod_wu(remOutput, srcDest, rhs); + as_div_wu(srcDest, srcDest, rhs); } else { - as_div_w(divOutput, lhs, rhs); - as_mod_w(remOutput, lhs, rhs); + as_mod_w(remOutput, srcDest, rhs); + as_div_w(srcDest, srcDest, rhs); } } diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -247,39 +247,43 @@ void MacroAssembler::mulDoublePtr(ImmPtr imm, Register temp, mulDouble(ScratchDoubleReg, dest); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned) { -#ifdef MIPSR6 if (isUnsigned) { - as_divu(dest, lhs, rhs); - } else { - as_div(dest, lhs, rhs); - } +#ifdef MIPSR6 + as_divu(srcDest, srcDest, rhs); #else - if (isUnsigned) { - as_divu(lhs, rhs); + as_divu(srcDest, rhs); +#endif } else { - as_div(lhs, rhs); +#ifdef MIPSR6 + as_div(srcDest, srcDest, rhs); +#else + as_div(srcDest, rhs); +#endif } - as_mflo(dest); +#ifndef MIPSR6 + as_mflo(srcDest); #endif } -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned) { -#ifdef MIPSR6 if (isUnsigned) { - as_modu(dest, lhs, rhs); - } else { - as_mod(dest, lhs, rhs); - } +#ifdef MIPSR6 + as_modu(srcDest, srcDest, rhs); #else - if (isUnsigned) { - as_divu(lhs, rhs); + as_divu(srcDest, rhs); +#endif } else { - as_div(lhs, rhs); +#ifdef MIPSR6 + as_mod(srcDest, srcDest, rhs); +#else + as_div(srcDest, rhs); +#endif } - as_mfhi(dest); +#ifndef MIPSR6 + as_mfhi(srcDest); #endif } diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp @@ -3105,40 +3105,44 @@ void MacroAssembler::atomicEffectOpJS(Scalar::Type arrayType, void MacroAssembler::atomicPause() { as_sync(); } -void MacroAssembler::flexibleQuotient32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleQuotient32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - quotient32(lhs, rhs, dest, isUnsigned); + quotient32(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleRemainder32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleRemainder32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - remainder32(lhs, rhs, dest, isUnsigned); + remainder32(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, const LiveRegisterSet&) { - MOZ_ASSERT(lhs != divOutput && lhs != remOutput, "lhs is preserved"); - MOZ_ASSERT(rhs != divOutput && rhs != remOutput, "rhs is preserved"); - -#ifdef MIPSR6 +void MacroAssembler::flexibleDivMod32(Register rhs, Register srcDest, + Register remOutput, bool isUnsigned, + const LiveRegisterSet&) { + UseScratchRegisterScope temps(*this); if (isUnsigned) { - as_divu(divOutput, lhs, rhs); - as_modu(remOutput, rhs, rhs); - } else { - as_div(divOutput, lhs, rhs); - as_mod(remOutput, lhs, rhs); - } +#ifdef MIPSR6 + Register scratch = temps.Acquire(); + as_divu(scratch, srcDest, rhs); + as_modu(remOutput, srcDest, rhs); + ma_move(srcDest, scratch); #else - if (isUnsigned) { - as_divu(lhs, rhs); + as_divu(srcDest, rhs); +#endif } else { - as_div(lhs, rhs); +#ifdef MIPSR6 + Register scratch = temps.Acquire(); + as_div(scratch, srcDest, rhs); + as_mod(remOutput, srcDest, rhs); + ma_move(srcDest, scratch); +#else + as_div(srcDest, rhs); +#endif } +#ifndef MIPSR6 as_mfhi(remOutput); - as_mflo(divOutput); + as_mflo(srcDest); #endif } diff --git a/js/src/jit/mips64/MacroAssembler-mips64-inl.h b/js/src/jit/mips64/MacroAssembler-mips64-inl.h @@ -361,39 +361,43 @@ void MacroAssembler::inc64(AbsoluteAddress dest) { as_sd(scratch2, scratch, 0); } -void MacroAssembler::quotient64(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient64(Register rhs, Register srcDest, bool isUnsigned) { -#ifdef MIPSR6 if (isUnsigned) { - as_ddivu(dest, lhs, rhs); - } else { - as_ddiv(dest, lhs, rhs); - } +#ifdef MIPSR6 + as_ddivu(srcDest, srcDest, rhs); #else - if (isUnsigned) { - as_ddivu(lhs, rhs); + as_ddivu(srcDest, rhs); +#endif } else { - as_ddiv(lhs, rhs); +#ifdef MIPSR6 + as_ddiv(srcDest, srcDest, rhs); +#else + as_ddiv(srcDest, rhs); +#endif } - as_mflo(dest); +#ifndef MIPSR6 + as_mflo(srcDest); #endif } -void MacroAssembler::remainder64(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder64(Register rhs, Register srcDest, bool isUnsigned) { -#ifdef MIPSR6 if (isUnsigned) { - as_dmodu(dest, lhs, rhs); - } else { - as_dmod(dest, lhs, rhs); - } +#ifdef MIPSR6 + as_dmodu(srcDest, srcDest, rhs); #else - if (isUnsigned) { - as_ddivu(lhs, rhs); + as_ddivu(srcDest, rhs); +#endif } else { - as_ddiv(lhs, rhs); +#ifdef MIPSR6 + as_dmod(srcDest, srcDest, rhs); +#else + as_ddiv(srcDest, rhs); +#endif } - as_mfhi(dest); +#ifndef MIPSR6 + as_mfhi(srcDest); #endif } diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -3363,15 +3363,15 @@ void MacroAssembler::convertUInt64ToFloat32(Register64 src_, FloatRegister dest, } void MacroAssembler::flexibleQuotientPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - quotient64(lhs, rhs, dest, isUnsigned); + quotient64(rhs, srcDest, isUnsigned); } void MacroAssembler::flexibleRemainderPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - remainder64(lhs, rhs, dest, isUnsigned); + remainder64(rhs, srcDest, isUnsigned); } void MacroAssembler::wasmMarkCallAsSlow() { mov(ra, ra); } diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h b/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h @@ -1922,39 +1922,39 @@ void MacroAssembler::popcnt64(Register64 input, Register64 output, Register tmp) { Popcnt64(output.reg, input.reg, tmp); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - ma_divu32(dest, lhs, rhs); + ma_divu32(srcDest, srcDest, rhs); } else { - ma_div32(dest, lhs, rhs); + ma_div32(srcDest, srcDest, rhs); } } -void MacroAssembler::quotient64(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient64(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - ma_divu64(dest, lhs, rhs); + ma_divu64(srcDest, srcDest, rhs); } else { - ma_div64(dest, lhs, rhs); + ma_div64(srcDest, srcDest, rhs); } } -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - ma_modu32(dest, lhs, rhs); + ma_modu32(srcDest, srcDest, rhs); } else { - ma_mod32(dest, lhs, rhs); + ma_mod32(srcDest, srcDest, rhs); } } -void MacroAssembler::remainder64(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder64(Register rhs, Register srcDest, bool isUnsigned) { if (isUnsigned) { - ma_modu64(dest, lhs, rhs); + ma_modu64(srcDest, srcDest, rhs); } else { - ma_mod64(dest, lhs, rhs); + ma_mod64(srcDest, srcDest, rhs); } } diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64.cpp b/js/src/jit/riscv64/MacroAssembler-riscv64.cpp @@ -3554,44 +3554,39 @@ void MacroAssembler::patchSub32FromMemAndBranchIfNegative(CodeOffset offset, inst->SetInstructionBits(((uint32_t)inst->InstructionBits() & ~kImm12Mask) | (((uint32_t)(-val) & 0xfff) << kImm12Shift)); } -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, const LiveRegisterSet&) { - MOZ_ASSERT(lhs != divOutput && lhs != remOutput, "lhs is preserved"); - MOZ_ASSERT(rhs != divOutput && rhs != remOutput, "rhs is preserved"); - - // The recommended code sequence to obtain both the quotient and remainder - // is div[u] followed by mod[u]. +void MacroAssembler::flexibleDivMod32(Register rhs, Register srcDest, + Register remOutput, bool isUnsigned, + const LiveRegisterSet&) { if (isUnsigned) { - ma_divu32(divOutput, lhs, rhs); - ma_modu32(remOutput, lhs, rhs); + ma_modu32(remOutput, srcDest, rhs); + ma_divu32(srcDest, srcDest, rhs); } else { - ma_div32(divOutput, lhs, rhs); - ma_mod32(remOutput, lhs, rhs); + ma_mod32(remOutput, srcDest, rhs); + ma_div32(srcDest, srcDest, rhs); } } -void MacroAssembler::flexibleQuotient32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleQuotient32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - quotient32(lhs, rhs, dest, isUnsigned); + quotient32(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleQuotientPtr(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleQuotientPtr(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - quotient64(lhs, rhs, dest, isUnsigned); + quotient64(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleRemainder32(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleRemainder32(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - remainder32(lhs, rhs, dest, isUnsigned); + remainder32(rhs, srcDest, isUnsigned); } -void MacroAssembler::flexibleRemainderPtr(Register lhs, Register rhs, - Register dest, bool isUnsigned, +void MacroAssembler::flexibleRemainderPtr(Register rhs, Register srcDest, + bool isUnsigned, const LiveRegisterSet&) { - remainder64(lhs, rhs, dest, isUnsigned); + remainder64(rhs, srcDest, isUnsigned); } void MacroAssembler::floorDoubleToInt32(FloatRegister src, Register dest, diff --git a/js/src/jit/wasm32/MacroAssembler-wasm32-inl.h b/js/src/jit/wasm32/MacroAssembler-wasm32-inl.h @@ -1127,12 +1127,12 @@ void MacroAssembler::branchAdd64(Condition cond, Imm64 imm, Register64 dest, MOZ_CRASH(); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, bool isUnsigned) { MOZ_CRASH(); } -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, bool isUnsigned) { MOZ_CRASH(); } diff --git a/js/src/jit/wasm32/MacroAssembler-wasm32.cpp b/js/src/jit/wasm32/MacroAssembler-wasm32.cpp @@ -48,33 +48,32 @@ void MacroAssembler::PopStackPtr() { MOZ_CRASH(); } void MacroAssembler::freeStackTo(uint32_t framePushed) { MOZ_CRASH(); } -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, +void MacroAssembler::flexibleDivMod32(Register rhs, Register srcDest, + Register remOutput, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { MOZ_CRASH(); } void MacroAssembler::flexibleQuotient32( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { MOZ_CRASH(); } void MacroAssembler::flexibleQuotientPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { MOZ_CRASH(); } void MacroAssembler::flexibleRemainder32( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { MOZ_CRASH(); } void MacroAssembler::flexibleRemainderPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -858,10 +858,9 @@ void MacroAssemblerX64::convertDoubleToPtr(FloatRegister src, Register dest, } // This operation really consists of five phases, in order to enforce the -// restriction that on x64, the dividend must be rax and both rax and rdx will -// be clobbered. +// restriction that on x64, srcDest must be rax and rdx will be clobbered. // -// Input: { lhs, rhs } +// Input: { rhs, lhsOutput } // // [PUSH] Preserve registers // [MOVE] Generate moves to specific registers @@ -869,17 +868,16 @@ void MacroAssemblerX64::convertDoubleToPtr(FloatRegister src, Register dest, // [DIV] Input: { regForRhs, RAX } // [DIV] extend RAX into RDX // [DIV] x64 Division operator -// [DIV] Output: { RAX, RDX } +// [DIV] Ouptut: { RAX, RDX } // // [MOVE] Move specific registers to outputs // [POP] Restore registers // -// Output: { output } -void MacroAssemblerX64::flexibleDivMod64(Register lhs, Register rhs, - Register output, bool isUnsigned, - bool isDiv) { - if (lhs == rhs) { - movq(ImmWord(isDiv ? 1 : 0), output); +// Output: { lhsOutput, remainderOutput } +void MacroAssemblerX64::flexibleDivMod64(Register rhs, Register lhsOutput, + bool isUnsigned, bool isDiv) { + if (lhsOutput == rhs) { + movq(ImmWord(isDiv ? 1 : 0), lhsOutput); return; } @@ -892,16 +890,14 @@ void MacroAssemblerX64::flexibleDivMod64(Register lhs, Register rhs, LiveGeneralRegisterSet preserve; preserve.add(rdx); preserve.add(rax); - if (rhs != regForRhs) { - preserve.add(regForRhs); - } + preserve.add(regForRhs); - preserve.takeUnchecked(output); + preserve.takeUnchecked(lhsOutput); asMasm().PushRegsInMask(preserve); // Shuffle input into place. - asMasm().moveRegPair(lhs, rhs, rax, regForRhs); + asMasm().moveRegPair(lhsOutput, rhs, rax, regForRhs); if (oom()) { return; } @@ -916,8 +912,8 @@ void MacroAssemblerX64::flexibleDivMod64(Register lhs, Register rhs, } Register result = isDiv ? rax : rdx; - if (result != output) { - movq(result, output); + if (result != lhsOutput) { + movq(result, lhsOutput); } asMasm().PopRegsInMask(preserve); @@ -1052,15 +1048,15 @@ void MacroAssembler::moveValue(const Value& src, const ValueOperand& dest) { // Arithmetic functions void MacroAssembler::flexibleQuotientPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - flexibleDivMod64(lhs, rhs, dest, isUnsigned, /* isDiv= */ true); + flexibleDivMod64(rhs, srcDest, isUnsigned, /* isDiv= */ true); } void MacroAssembler::flexibleRemainderPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - flexibleDivMod64(lhs, rhs, dest, isUnsigned, /* isDiv= */ false); + flexibleDivMod64(rhs, srcDest, isUnsigned, /* isDiv= */ false); } // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h @@ -76,8 +76,8 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared { X86Encoding::XMMRegisterID destId)); protected: - void flexibleDivMod64(Register lhs, Register rhs, Register output, - bool isUnsigned, bool isDiv); + void flexibleDivMod64(Register rhs, Register lhsOutput, bool isUnsigned, + bool isDiv); public: using MacroAssemblerX86Shared::load32; diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -252,9 +252,9 @@ void MacroAssembler::mulDouble(FloatRegister src, FloatRegister dest) { vmulsd(src, dest, dest); } -void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, +void MacroAssembler::quotient32(Register rhs, Register srcDest, Register tempEdx, bool isUnsigned) { - MOZ_ASSERT(lhs == eax && dest == eax && tempEdx == edx); + MOZ_ASSERT(srcDest == eax && tempEdx == edx); // Sign extend eax into edx to make (edx:eax): idiv/udiv are 64-bit. if (isUnsigned) { @@ -266,9 +266,9 @@ void MacroAssembler::quotient32(Register lhs, Register rhs, Register dest, } } -void MacroAssembler::remainder32(Register lhs, Register rhs, Register dest, +void MacroAssembler::remainder32(Register rhs, Register srcDest, Register tempEdx, bool isUnsigned) { - MOZ_ASSERT(lhs == eax && dest == eax && tempEdx == edx); + MOZ_ASSERT(srcDest == eax && tempEdx == edx); // Sign extend eax into edx to make (edx:eax): idiv/udiv are 64-bit. if (isUnsigned) { diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -352,10 +352,10 @@ void MacroAssembler::flush() {} void MacroAssembler::comment(const char* msg) { masm.comment(msg); } // This operation really consists of five phases, in order to enforce the -// restriction that on x86_shared, the dividend must be eax and both eax and edx -// will be clobbered. +// restriction that on x86_shared, srcDest must be eax and edx will be +// clobbered. // -// Input: { lhs, rhs } +// Input: { rhs, lhsOutput } // // [PUSH] Preserve registers // [MOVE] Generate moves to specific registers @@ -363,26 +363,20 @@ void MacroAssembler::comment(const char* msg) { masm.comment(msg); } // [DIV] Input: { regForRhs, EAX } // [DIV] extend EAX into EDX // [DIV] x86 Division operator -// [DIV] Output: { EAX, EDX } +// [DIV] Ouptut: { EAX, EDX } // // [MOVE] Move specific registers to outputs // [POP] Restore registers // -// Output: { quotientOutput, remainderOutput } -static void EmitDivMod32(MacroAssembler& masm, Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned) { - if (lhs == rhs) { - if (divOutput != Register::Invalid()) { - masm.movl(Imm32(1), divOutput); - } - if (remOutput != Register::Invalid()) { - masm.movl(Imm32(0), remOutput); - } - return; - } - - // Choose a register that is not edx or eax to hold the rhs; +// Output: { lhsOutput, remainderOutput } +void MacroAssembler::flexibleDivMod32(Register rhs, Register lhsOutput, + Register remOutput, bool isUnsigned, + const LiveRegisterSet&) { + // Currently this helper can't handle this situation. + MOZ_ASSERT(lhsOutput != rhs); + MOZ_ASSERT(lhsOutput != remOutput); + + // Choose a register that is not edx, or eax to hold the rhs; // ebx is chosen arbitrarily, and will be preserved if necessary. Register regForRhs = (rhs == eax || rhs == edx) ? ebx : rhs; @@ -391,64 +385,61 @@ static void EmitDivMod32(MacroAssembler& masm, Register lhs, Register rhs, LiveRegisterSet preserve; preserve.add(edx); preserve.add(eax); - if (rhs != regForRhs) { - preserve.add(regForRhs); - } + preserve.add(regForRhs); - if (divOutput != Register::Invalid()) { - preserve.takeUnchecked(divOutput); - } - if (remOutput != Register::Invalid()) { - preserve.takeUnchecked(remOutput); - } + preserve.takeUnchecked(lhsOutput); + preserve.takeUnchecked(remOutput); - masm.PushRegsInMask(preserve); + PushRegsInMask(preserve); // Shuffle input into place. - masm.moveRegPair(lhs, rhs, eax, regForRhs); + moveRegPair(lhsOutput, rhs, eax, regForRhs); // Sign extend eax into edx to make (edx:eax): idiv/udiv are 64-bit. if (isUnsigned) { - masm.mov(ImmWord(0), edx); - masm.udiv(regForRhs); + mov(ImmWord(0), edx); + udiv(regForRhs); } else { - masm.cdq(); - masm.idiv(regForRhs); + cdq(); + idiv(regForRhs); } - if (divOutput != Register::Invalid() && remOutput != Register::Invalid()) { - masm.moveRegPair(eax, edx, divOutput, remOutput); - } else { - if (divOutput != Register::Invalid() && divOutput != eax) { - masm.mov(eax, divOutput); - } - if (remOutput != Register::Invalid() && remOutput != edx) { - masm.mov(edx, remOutput); - } - } + moveRegPair(eax, edx, lhsOutput, remOutput); - masm.PopRegsInMask(preserve); -} - -void MacroAssembler::flexibleDivMod32(Register lhs, Register rhs, - Register divOutput, Register remOutput, - bool isUnsigned, const LiveRegisterSet&) { - MOZ_ASSERT(lhs != divOutput && lhs != remOutput, "lhs is preserved"); - MOZ_ASSERT(rhs != divOutput && rhs != remOutput, "rhs is preserved"); - - EmitDivMod32(*this, lhs, rhs, divOutput, remOutput, isUnsigned); + PopRegsInMask(preserve); } void MacroAssembler::flexibleQuotient32( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - EmitDivMod32(*this, lhs, rhs, dest, Register::Invalid(), isUnsigned); + // Choose an arbitrary register that isn't eax, edx, rhs or srcDest; + AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); + regs.takeUnchecked(eax); + regs.takeUnchecked(edx); + regs.takeUnchecked(rhs); + regs.takeUnchecked(srcDest); + + Register remOut = regs.takeAny(); + push(remOut); + flexibleDivMod32(rhs, srcDest, remOut, isUnsigned, volatileLiveRegs); + pop(remOut); } void MacroAssembler::flexibleRemainder32( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - EmitDivMod32(*this, lhs, rhs, Register::Invalid(), dest, isUnsigned); + // Choose an arbitrary register that isn't eax, edx, rhs or srcDest + AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); + regs.takeUnchecked(eax); + regs.takeUnchecked(edx); + regs.takeUnchecked(rhs); + regs.takeUnchecked(srcDest); + + Register remOut = regs.takeAny(); + push(remOut); + flexibleDivMod32(rhs, srcDest, remOut, isUnsigned, volatileLiveRegs); + mov(remOut, srcDest); + pop(remOut); } // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -959,15 +959,15 @@ void MacroAssembler::moveValue(const Value& src, const ValueOperand& dest) { // Arithmetic functions void MacroAssembler::flexibleQuotientPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - flexibleQuotient32(lhs, rhs, dest, isUnsigned, volatileLiveRegs); + flexibleQuotient32(rhs, srcDest, isUnsigned, volatileLiveRegs); } void MacroAssembler::flexibleRemainderPtr( - Register lhs, Register rhs, Register dest, bool isUnsigned, + Register rhs, Register srcDest, bool isUnsigned, const LiveRegisterSet& volatileLiveRegs) { - flexibleRemainder32(lhs, rhs, dest, isUnsigned, volatileLiveRegs); + flexibleRemainder32(rhs, srcDest, isUnsigned, volatileLiveRegs); } // =============================================================== diff --git a/js/src/jsapi-tests/testJitMacroAssembler.cpp b/js/src/jsapi-tests/testJitMacroAssembler.cpp @@ -5,8 +5,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mozilla/Sprintf.h" - #include "jit/IonAnalysis.h" #include "jit/Linker.h" #include "jit/MacroAssembler.h" @@ -37,80 +35,48 @@ BEGIN_TEST(testJitMacroAssembler_flexibleDivMod) { PrepareJit(masm); // Test case divides 9/2; - const uintptr_t dividend = 9; - const uintptr_t divisor = 2; const uintptr_t quotient_result = 4; const uintptr_t remainder_result = 1; + const uintptr_t dividend = 9; + const uintptr_t divisor = 2; - AllocatableGeneralRegisterSet leftHandSides(GeneralRegisterSet::All()); - while (!leftHandSides.empty()) { - Register lhs = leftHandSides.takeAny(); + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); while (!rightHandSides.empty()) { Register rhs = rightHandSides.takeAny(); - AllocatableGeneralRegisterSet quotients(GeneralRegisterSet::All()); - while (!quotients.empty()) { - Register quotientOutput = quotients.takeAny(); - - AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All()); - while (!remainders.empty()) { - Register remainderOutput = remainders.takeAny(); - - // lhs and rhs are preserved by |flexibleDivMod32|, so neither can be - // an output register. - if (lhs == quotientOutput || lhs == remainderOutput) { - continue; - } - if (rhs == quotientOutput || rhs == remainderOutput) { - continue; - } - - // Output registers must be distinct. - if (quotientOutput == remainderOutput) { - continue; - } - - AllocatableRegisterSet regs(RegisterSet::Volatile()); - LiveRegisterSet save(regs.asLiveSet()); - - Label next, fail; - masm.mov(ImmWord(dividend), lhs); - masm.mov(ImmWord(divisor), rhs); - masm.flexibleDivMod32(lhs, rhs, quotientOutput, remainderOutput, - false, save); - masm.branchPtr(Assembler::NotEqual, quotientOutput, - ImmWord(lhs != rhs ? quotient_result : 1), &fail); - masm.branchPtr(Assembler::NotEqual, remainderOutput, - ImmWord(lhs != rhs ? remainder_result : 0), &fail); - // Ensure LHS was not clobbered - masm.branchPtr(Assembler::NotEqual, lhs, - ImmWord(lhs != rhs ? dividend : divisor), &fail); - // Ensure RHS was not clobbered - masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(divisor), &fail); - masm.jump(&next); - masm.bind(&fail); - masm.printf("Failed\n"); - - char buffer[128]; - SprintfLiteral( - buffer, - "\tlhs = %s, rhs = %s, quotientOutput = %s, remainderOutput " - "= %s\n", - lhs.name(), rhs.name(), quotientOutput.name(), - remainderOutput.name()); - - masm.printf(buffer); - masm.printf("\tlhs = %d\n", lhs); - masm.printf("\trhs = %d\n", rhs); - masm.printf("\tquotientOutput = %d\n", quotientOutput); - masm.printf("\tremainderOutput = %d\n", remainderOutput); - - masm.breakpoint(); - - masm.bind(&next); + AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All()); + while (!remainders.empty()) { + Register remainderOutput = remainders.takeAny(); + if (lhsOutput == rhs || lhsOutput == remainderOutput || + rhs == remainderOutput) { + continue; } + + AllocatableRegisterSet regs(RegisterSet::Volatile()); + LiveRegisterSet save(regs.asLiveSet()); + + Label next, fail; + masm.mov(ImmWord(dividend), lhsOutput); + masm.mov(ImmWord(divisor), rhs); + masm.flexibleDivMod32(rhs, lhsOutput, remainderOutput, false, save); + masm.branch32(Assembler::NotEqual, AbsoluteAddress("ient_result), + lhsOutput, &fail); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result), + remainderOutput, &fail); + // Ensure RHS was not clobbered + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, + &fail); + masm.jump(&next); + masm.bind(&fail); + masm.printf("Failed"); + masm.breakpoint(); + + masm.bind(&next); } } } @@ -132,53 +98,36 @@ BEGIN_TEST(testJitMacroAssembler_flexibleRemainder) { const uintptr_t divisor = 2; const uintptr_t remainder_result = 1; - AllocatableGeneralRegisterSet leftHandSides(GeneralRegisterSet::All()); - while (!leftHandSides.empty()) { - Register lhs = leftHandSides.takeAny(); + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); while (!rightHandSides.empty()) { Register rhs = rightHandSides.takeAny(); - AllocatableGeneralRegisterSet outputs(GeneralRegisterSet::All()); - while (!outputs.empty()) { - Register output = outputs.takeAny(); - - AllocatableRegisterSet regs(RegisterSet::Volatile()); - LiveRegisterSet save(regs.asLiveSet()); - - Label next, fail; - masm.mov(ImmWord(dividend), lhs); - masm.mov(ImmWord(divisor), rhs); - masm.flexibleRemainder32(lhs, rhs, output, false, save); - masm.branchPtr(Assembler::NotEqual, output, - ImmWord(lhs != rhs ? remainder_result : 0), &fail); - // Ensure LHS was not clobbered - if (lhs != output) { - masm.branchPtr(Assembler::NotEqual, lhs, - ImmWord(lhs != rhs ? dividend : divisor), &fail); - } - // Ensure RHS was not clobbered - if (rhs != output) { - masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(divisor), &fail); - } - masm.jump(&next); - masm.bind(&fail); - masm.printf("Failed\n"); - - char buffer[128]; - SprintfLiteral(buffer, "\tlhs = %s, rhs = %s, output = %s\n", - lhs.name(), rhs.name(), output.name()); - - masm.printf(buffer); - masm.printf("\tlhs = %d\n", lhs); - masm.printf("\trhs = %d\n", rhs); - masm.printf("\toutput = %d\n", output); + if (lhsOutput == rhs) { + continue; + } - masm.breakpoint(); + AllocatableRegisterSet regs(RegisterSet::Volatile()); + LiveRegisterSet save(regs.asLiveSet()); + + Label next, fail; + masm.mov(ImmWord(dividend), lhsOutput); + masm.mov(ImmWord(divisor), rhs); + masm.flexibleRemainder32(rhs, lhsOutput, false, save); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&remainder_result), + lhsOutput, &fail); + // Ensure RHS was not clobbered + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail); + masm.jump(&next); + masm.bind(&fail); + masm.printf("Failed\n"); + masm.breakpoint(); - masm.bind(&next); - } + masm.bind(&next); } } @@ -199,53 +148,36 @@ BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) { const uintptr_t divisor = 2; const uintptr_t quotient_result = 4; - AllocatableGeneralRegisterSet leftHandSides(GeneralRegisterSet::All()); - while (!leftHandSides.empty()) { - Register lhs = leftHandSides.takeAny(); + AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); + + while (!leftOutputHandSides.empty()) { + Register lhsOutput = leftOutputHandSides.takeAny(); AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); while (!rightHandSides.empty()) { Register rhs = rightHandSides.takeAny(); - AllocatableGeneralRegisterSet outputs(GeneralRegisterSet::All()); - while (!outputs.empty()) { - Register output = outputs.takeAny(); - - AllocatableRegisterSet regs(RegisterSet::Volatile()); - LiveRegisterSet save(regs.asLiveSet()); - - Label next, fail; - masm.mov(ImmWord(dividend), lhs); - masm.mov(ImmWord(divisor), rhs); - masm.flexibleQuotient32(lhs, rhs, output, false, save); - masm.branchPtr(Assembler::NotEqual, output, - ImmWord(lhs != rhs ? quotient_result : 1), &fail); - // Ensure LHS was not clobbered - if (lhs != output) { - masm.branchPtr(Assembler::NotEqual, lhs, - ImmWord(lhs != rhs ? dividend : divisor), &fail); - } - // Ensure RHS was not clobbered - if (rhs != output) { - masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(divisor), &fail); - } - masm.jump(&next); - masm.bind(&fail); - masm.printf("Failed\n"); - - char buffer[128]; - SprintfLiteral(buffer, "\tlhs = %s, rhs = %s, output = %s\n", - lhs.name(), rhs.name(), output.name()); - - masm.printf(buffer); - masm.printf("\tlhs = %d\n", lhs); - masm.printf("\trhs = %d\n", rhs); - masm.printf("\toutput = %d\n", output); + if (lhsOutput == rhs) { + continue; + } - masm.breakpoint(); + AllocatableRegisterSet regs(RegisterSet::Volatile()); + LiveRegisterSet save(regs.asLiveSet()); + + Label next, fail; + masm.mov(ImmWord(dividend), lhsOutput); + masm.mov(ImmWord(divisor), rhs); + masm.flexibleQuotient32(rhs, lhsOutput, false, save); + masm.branch32(Assembler::NotEqual, AbsoluteAddress("ient_result), + lhsOutput, &fail); + // Ensure RHS was not clobbered + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&divisor), rhs, &fail); + masm.jump(&next); + masm.bind(&fail); + masm.printf("Failed\n"); + masm.breakpoint(); - masm.bind(&next); - } + masm.bind(&next); } } @@ -253,9 +185,14 @@ BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) { } END_TEST(testJitMacroAssembler_flexibleQuotient) +// To make sure ecx isn't being clobbered; globally scoped to ensure it has the +// right lifetime. +const uintptr_t guardEcx = 0xfeedbad; + bool shiftTest(JSContext* cx, const char* name, void (*operation)(StackMacroAssembler& masm, Register, Register), - uintptr_t lhsInput, uintptr_t rhsInput, uintptr_t result) { + const uintptr_t* lhsInput, const uintptr_t* rhsInput, + const uintptr_t* result) { TempAllocator tempAlloc(&cx->tempLifoAlloc()); JitContext jcx(cx); StackMacroAssembler masm(cx, tempAlloc); @@ -263,8 +200,6 @@ bool shiftTest(JSContext* cx, const char* name, PrepareJit(masm); - const uintptr_t guardEcx = 0xfeedbad; - JS::AutoSuppressGCAnalysis suppress; AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); @@ -276,33 +211,33 @@ bool shiftTest(JSContext* cx, const char* name, Register rhs = rightHandSides.takeAny(); // You can only use shift as the same reg if the values are the same - if (lhsOutput == rhs && lhsInput != rhsInput) { + if (lhsOutput == rhs && *lhsInput != *rhsInput) { continue; } Label next, outputFail, clobberRhs, clobberEcx, dump; masm.mov(ImmWord(guardEcx), ecx); - masm.mov(ImmWord(lhsInput), lhsOutput); - masm.mov(ImmWord(rhsInput), rhs); + masm.mov(ImmWord(*lhsInput), lhsOutput); + masm.mov(ImmWord(*rhsInput), rhs); operation(masm, rhs, lhsOutput); // Ensure Result is correct - masm.branchPtr(Assembler::NotEqual, lhsOutput, ImmWord(result), - &outputFail); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(result), lhsOutput, + &outputFail); // Ensure RHS was not clobbered, unless it's also the output register. if (lhsOutput != rhs) { - masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(rhsInput), - &clobberRhs); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(rhsInput), rhs, + &clobberRhs); } if (lhsOutput != ecx && rhs != ecx) { // If neither lhsOutput nor rhs is ecx, make sure ecx has been // preserved, otherwise it's expected to be covered by the RHS clobber // check above, or intentionally clobbered as the output. - masm.branchPtr(Assembler::NotEqual, ecx, ImmWord(guardEcx), - &clobberEcx); + masm.branch32(Assembler::NotEqual, AbsoluteAddress(&guardEcx), ecx, + &clobberEcx); } masm.jump(&next); @@ -347,7 +282,7 @@ BEGIN_TEST(testJitMacroAssembler_flexibleRshift) { [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { masm.flexibleRshift32(rhs, lhsOutput); }, - lhsInput, rhsInput, result); + &lhsInput, &rhsInput, &result); if (!res) { return false; } @@ -365,7 +300,7 @@ BEGIN_TEST(testJitMacroAssembler_flexibleRshift) { [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { masm.flexibleRshift32(rhs, lhsOutput); }, - lhsInput, rhsInput, result); + &lhsInput, &rhsInput, &result); if (!res) { return false; } @@ -386,7 +321,7 @@ BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) { [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { masm.flexibleRshift32Arithmetic(rhs, lhsOutput); }, - lhsInput, rhsInput, result); + &lhsInput, &rhsInput, &result); if (!res) { return false; } @@ -404,7 +339,7 @@ BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) { [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { masm.flexibleRshift32Arithmetic(rhs, lhsOutput); }, - lhsInput, rhsInput, result); + &lhsInput, &rhsInput, &result); if (!res) { return false; } @@ -426,7 +361,7 @@ BEGIN_TEST(testJitMacroAssembler_flexibleLshift) { [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { masm.flexibleLshift32(rhs, lhsOutput); }, - lhsInput, rhsInput, result); + &lhsInput, &rhsInput, &result); if (!res) { return false; } @@ -443,7 +378,7 @@ BEGIN_TEST(testJitMacroAssembler_flexibleLshift) { [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { masm.flexibleLshift32(rhs, lhsOutput); }, - lhsInput, rhsInput, result); + &lhsInput, &rhsInput, &result); if (!res) { return false; } diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp @@ -2382,18 +2382,18 @@ void BaseCompiler::popAndAllocateForDivAndRemI32(RegI32* r0, RegI32* r1, static void QuotientI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd, RegI32 reserved, IsUnsigned isUnsigned) { #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - masm.quotient32(rsd, rs, rsd, reserved, isUnsigned); + masm.quotient32(rs, rsd, reserved, isUnsigned); #else - masm.quotient32(rsd, rs, rsd, isUnsigned); + masm.quotient32(rs, rsd, isUnsigned); #endif } static void RemainderI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd, RegI32 reserved, IsUnsigned isUnsigned) { #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - masm.remainder32(rsd, rs, rsd, reserved, isUnsigned); + masm.remainder32(rs, rsd, reserved, isUnsigned); #else - masm.remainder32(rsd, rs, rsd, isUnsigned); + masm.remainder32(rs, rsd, isUnsigned); #endif } @@ -2457,8 +2457,37 @@ static void QuotientI64(MacroAssembler& masm, RegI64 rhs, RegI64 srcDest, masm.cqo(); masm.idivq(rhs.reg); } +# elif defined(JS_CODEGEN_MIPS64) + MOZ_ASSERT(reserved.isInvalid()); + if (isUnsigned) { + masm.as_ddivu(srcDest.reg, rhs.reg); + } else { + masm.as_ddiv(srcDest.reg, rhs.reg); + } + masm.as_mflo(srcDest.reg); +# elif defined(JS_CODEGEN_ARM64) + MOZ_ASSERT(reserved.isInvalid()); + ARMRegister sd(srcDest.reg, 64); + ARMRegister r(rhs.reg, 64); + if (isUnsigned) { + masm.Udiv(sd, sd, r); + } else { + masm.Sdiv(sd, sd, r); + } +# elif defined(JS_CODEGEN_LOONG64) + if (isUnsigned) { + masm.as_div_du(srcDest.reg, srcDest.reg, rhs.reg); + } else { + masm.as_div_d(srcDest.reg, srcDest.reg, rhs.reg); + } +# elif defined(JS_CODEGEN_RISCV64) + if (isUnsigned) { + masm.divu(srcDest.reg, srcDest.reg, rhs.reg); + } else { + masm.div(srcDest.reg, srcDest.reg, rhs.reg); + } # else - masm.quotient64(srcDest.reg, rhs.reg, srcDest.reg, isUnsigned); + MOZ_CRASH("BaseCompiler platform hook: quotientI64"); # endif } @@ -2477,8 +2506,39 @@ static void RemainderI64(MacroAssembler& masm, RegI64 rhs, RegI64 srcDest, masm.idivq(rhs.reg); } masm.movq(rdx, rax); +# elif defined(JS_CODEGEN_MIPS64) + MOZ_ASSERT(reserved.isInvalid()); + if (isUnsigned) { + masm.as_ddivu(srcDest.reg, rhs.reg); + } else { + masm.as_ddiv(srcDest.reg, rhs.reg); + } + masm.as_mfhi(srcDest.reg); +# elif defined(JS_CODEGEN_ARM64) + ARMRegister sd(srcDest.reg, 64); + ARMRegister r(rhs.reg, 64); + ARMRegister t(reserved.reg, 64); + if (isUnsigned) { + masm.Udiv(t, sd, r); + } else { + masm.Sdiv(t, sd, r); + } + masm.Mul(t, t, r); + masm.Sub(sd, sd, t); +# elif defined(JS_CODEGEN_LOONG64) + if (isUnsigned) { + masm.as_mod_du(srcDest.reg, srcDest.reg, rhs.reg); + } else { + masm.as_mod_d(srcDest.reg, srcDest.reg, rhs.reg); + } +# elif defined(JS_CODEGEN_RISCV64) + if (isUnsigned) { + masm.remu(srcDest.reg, srcDest.reg, rhs.reg); + } else { + masm.rem(srcDest.reg, srcDest.reg, rhs.reg); + } # else - masm.remainder64(srcDest.reg, rhs.reg, srcDest.reg, isUnsigned); + MOZ_CRASH("BaseCompiler platform hook: remainderI64"); # endif }