@@ -668,7 +668,6 @@ void LOLJIT::privateCompileSlowCases()
668668 DEFINE_SLOWCASE_OP (op_loop_hint)
669669 DEFINE_SLOWCASE_OP (op_enter)
670670 DEFINE_SLOWCASE_OP (op_check_traps)
671- DEFINE_SLOWCASE_OP (op_mod)
672671 DEFINE_SLOWCASE_OP (op_pow)
673672 DEFINE_SLOWCASE_OP (op_mul)
674673 DEFINE_SLOWCASE_OP (op_negate)
@@ -699,6 +698,7 @@ void LOLJIT::privateCompileSlowCases()
699698 DEFINE_SLOWCASE_SLOW_OP (rshift, OpRshift)
700699 DEFINE_SLOWCASE_SLOW_OP (urshift, OpUrshift)
701700 DEFINE_SLOWCASE_SLOW_OP (div, OpDiv)
701+ DEFINE_SLOWCASE_SLOW_OP (mod, OpMod)
702702 DEFINE_SLOWCASE_SLOW_OP (create_this, OpCreateThis)
703703 DEFINE_SLOWCASE_SLOW_OP (create_promise, OpCreatePromise)
704704 DEFINE_SLOWCASE_SLOW_OP (create_generator, OpCreateGenerator)
@@ -2871,6 +2871,90 @@ void LOLJIT::emitSlow_op_sub(const JSInstruction* currentInstruction, Vector<Slo
28712871 emitMathICSlow<OpSub>(subIC, currentInstruction, operationValueSubProfiledOptimize, operationValueSubProfiled, operationValueSubOptimize, iter);
28722872}
28732873
2874+ #if CPU(X86_64)
2875+
2876+ void LOLJIT::emit_op_mod (const JSInstruction* currentInstruction)
2877+ {
2878+ auto bytecode = currentInstruction->as <OpMod>();
2879+ auto allocations = m_fastAllocator.allocate (*this , bytecode, m_bytecodeIndex);
2880+ auto [ lhsRegs, rhsRegs ] = allocations.uses ;
2881+ auto [ dstRegs ] = allocations.defs ;
2882+
2883+ // Make sure registers are correct for x86 IDIV instructions.
2884+ ASSERT (regT0 == X86Registers::eax);
2885+ auto eax = X86Registers::eax;
2886+ auto edx = X86Registers::edx;
2887+ auto ecx = X86Registers::ecx;
2888+
2889+ addSlowCase (branchIfNotInt32 (lhsRegs));
2890+ addSlowCase (branchIfNotInt32 (rhsRegs));
2891+ addSlowCase (branchTest32 (Zero, rhsRegs.payloadGPR ()));
2892+
2893+ // Check for INT32_MIN % -1 (would overflow on IDIV)
2894+ Jump denominatorNotNeg1 = branch32 (NotEqual, rhsRegs.payloadGPR (), TrustedImm32 (-1 ));
2895+ addSlowCase (branch32 (Equal, lhsRegs.payloadGPR (), TrustedImm32 (INT32_MIN )));
2896+ denominatorNotNeg1.link (this );
2897+
2898+ move (rhsRegs.payloadGPR (), ecx);
2899+ move (lhsRegs.payloadGPR (), eax);
2900+
2901+ // Sign extend eax to edx:eax
2902+ x86ConvertToDoubleWord32 (eax, edx);
2903+ // Perform division: quotient in eax, remainder in edx
2904+ x86Div32 (ecx);
2905+
2906+ // Check for negative zero result: if numerator was negative and remainder is 0
2907+ Jump numeratorPositive = branch32 (GreaterThanOrEqual, lhsRegs.payloadGPR (), TrustedImm32 (0 ));
2908+ addSlowCase (branchTest32 (Zero, edx));
2909+ numeratorPositive.link (this );
2910+
2911+ // Box the remainder result
2912+ boxInt32 (edx, dstRegs);
2913+
2914+ m_fastAllocator.releaseScratches (allocations);
2915+ }
2916+
2917+ #elif CPU(ARM64)
2918+
2919+ void LOLJIT::emit_op_mod (const JSInstruction* currentInstruction)
2920+ {
2921+ auto bytecode = currentInstruction->as <OpMod>();
2922+ auto allocations = m_fastAllocator.allocate (*this , bytecode, m_bytecodeIndex);
2923+ auto [ lhsRegs, rhsRegs ] = allocations.uses ;
2924+ auto [ dstRegs ] = allocations.defs ;
2925+
2926+ addSlowCase (branchIfNotInt32 (lhsRegs));
2927+ addSlowCase (branchIfNotInt32 (rhsRegs));
2928+
2929+ GPRReg dividendGPR = lhsRegs.payloadGPR ();
2930+ GPRReg divisorGPR = rhsRegs.payloadGPR ();
2931+ GPRReg quotientThenRemainderGPR = s_scratch;
2932+ // GPRReg multiplyAnswerGPR = s_scratch;
2933+ addSlowCase (branchTest32 (Zero, divisorGPR));
2934+
2935+ // This is doing: x - ((x / y) * y)
2936+ div32 (dividendGPR, divisorGPR, quotientThenRemainderGPR);
2937+ // This should only overflow for INT32_MIN % -1 but that will end up with quotientThenRemainderGPR == 0 and finally yield -0.0 as expected.
2938+ multiplySub32 (quotientThenRemainderGPR, divisorGPR, dividendGPR, quotientThenRemainderGPR);
2939+
2940+ // Make sure we're not accidentally producing a positive zero when it should be a negative zero.
2941+ Jump numeratorPositive = branch32 (GreaterThanOrEqual, dividendGPR, TrustedImm32 (0 ));
2942+ Jump nonZeroRemainder = branchTest32 (NonZero, quotientThenRemainderGPR);
2943+ moveValue (jsDoubleNumber (-0.0 ), dstRegs);
2944+ Jump done = jump ();
2945+
2946+ numeratorPositive.link (this );
2947+ nonZeroRemainder.link (this );
2948+
2949+ boxInt32 (quotientThenRemainderGPR, dstRegs);
2950+ done.link (this );
2951+
2952+ m_fastAllocator.releaseScratches (allocations);
2953+ }
2954+ #else
2955+ #error "Unsupported Architecture"
2956+ #endif
2957+
28742958void LOLJIT::emit_op_negate (const JSInstruction* currentInstruction)
28752959{
28762960 UnaryArithProfile* arithProfile = &m_unlinkedCodeBlock->unaryArithProfile (currentInstruction->as <OpNegate>().m_profileIndex );
0 commit comments