diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index b32d39ef78..7e037a7052 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -123,20 +123,6 @@ void ArmJit::GenerateFixedCode() { POP(2, SCRATCHREG1, R_PC); } - // Must preserve SCRATCHREG1 (R0), destroys SCRATCHREG2 (LR) - updateRoundingMode = AlignCode16(); { - PUSH(2, SCRATCHREG1, R_LR); - LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31)); - MOVI2R(SCRATCHREG1, 0x1000003); - TST(SCRATCHREG2, SCRATCHREG1); - FixupBranch skip = B_CC(CC_EQ); // zero - MOVI2R(SCRATCHREG2, 1); - MOVP2R(SCRATCHREG1, &js.hasSetRounding); - STRB(SCRATCHREG2, SCRATCHREG1, 0); - SetJumpTarget(skip); - POP(2, SCRATCHREG1, R_PC); - } - FlushLitPool(); enterDispatcher = AlignCode16(); diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index 475cf7fdbd..971f8cebdc 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -416,8 +416,10 @@ void ArmJit::Comp_mxc1(MIPSOpcode op) // Must clear before setting, since ApplyRoundingMode() assumes it was cleared. RestoreRoundingMode(); bool wasImm = gpr.IsImm(rt); + u32 immVal = -1; if (wasImm) { - gpr.SetImm(MIPS_REG_FPCOND, (gpr.GetImm(rt) >> 23) & 1); + immVal = gpr.GetImm(rt); + gpr.SetImm(MIPS_REG_FPCOND, (immVal >> 23) & 1); gpr.MapReg(rt); } else { gpr.MapDirtyIn(MIPS_REG_FPCOND, rt); @@ -433,8 +435,10 @@ void ArmJit::Comp_mxc1(MIPSOpcode op) MOV(SCRATCHREG1, Operand2(gpr.R(rt), ST_LSR, 23)); AND(gpr.R(MIPS_REG_FPCOND), SCRATCHREG1, Operand2(1)); #endif + UpdateRoundingMode(); + } else { + UpdateRoundingMode(immVal); } - UpdateRoundingMode(); ApplyRoundingMode(); } else { Comp_Generic(op); diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 7e9d6aa3f6..ea206a6d26 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -640,8 +640,12 @@ void ArmJit::ApplyRoundingMode(bool force) { } // Does (must!) not destroy R0 (SCRATCHREG1). Destroys R14 (SCRATCHREG2). -void ArmJit::UpdateRoundingMode() { - QuickCallFunction(R1, updateRoundingMode); +void ArmJit::UpdateRoundingMode(u32 fcr31) { + // We must set js.hasSetRounding at compile time, or this block will use the wrong rounding mode. + // The fcr31 parameter is -1 when not known at compile time, so we just assume it was changed. + if (fcr31 & 0x01000003) { + js.hasSetRounding = true; + } } // IDEA - could have a WriteDualExit that takes two destinations and two condition flags, diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 941b7372fb..af2b6a128d 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -203,7 +203,7 @@ private: void WriteDownCountR(ArmGen::ARMReg reg); void RestoreRoundingMode(bool force = false); void ApplyRoundingMode(bool force = false); - void UpdateRoundingMode(); + void UpdateRoundingMode(u32 fcr31 = -1); void MovFromPC(ArmGen::ARMReg r); void MovToPC(ArmGen::ARMReg r); @@ -311,7 +311,6 @@ public: const u8 *restoreRoundingMode; const u8 *applyRoundingMode; - const u8 *updateRoundingMode; const u8 *breakpointBailout; }; diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index f0f5ac3e74..2390ed9673 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -177,17 +177,6 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { ADDI2R(SCRATCH2, SCRATCH2, 4); SetJumpTarget(skip); - // We need both SCRATCH1 and SCRATCH2 for updating hasSetRounding. - PUSH(SCRATCH2); - // We can only skip if the rounding mode is zero and flush is not set. - CMPI2R(SCRATCH2, 0); - FixupBranch skip2 = B(CC_EQ); - MOVI2R(SCRATCH2, 1); - MOVP2R(SCRATCH1_64, &js.hasSetRounding); - STRB(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0); - SetJumpTarget(skip2); - POP(SCRATCH2); - // Let's update js.currentRoundingFunc with the right convertS0ToSCRATCH1 func. MOVP2R(SCRATCH1_64, convertS0ToSCRATCH1); LSL(SCRATCH2, SCRATCH2, 3); diff --git a/Core/MIPS/ARM64/Arm64CompFPU.cpp b/Core/MIPS/ARM64/Arm64CompFPU.cpp index ea971de24f..e608baa6d4 100644 --- a/Core/MIPS/ARM64/Arm64CompFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompFPU.cpp @@ -375,8 +375,10 @@ void Arm64Jit::Comp_mxc1(MIPSOpcode op) // Must clear before setting, since ApplyRoundingMode() assumes it was cleared. RestoreRoundingMode(); bool wasImm = gpr.IsImm(rt); + u32 immVal = -1; if (wasImm) { - gpr.SetImm(MIPS_REG_FPCOND, (gpr.GetImm(rt) >> 23) & 1); + immVal = gpr.GetImm(rt); + gpr.SetImm(MIPS_REG_FPCOND, (immVal >> 23) & 1); gpr.MapReg(rt); } else { gpr.MapDirtyIn(MIPS_REG_FPCOND, rt); @@ -387,9 +389,11 @@ void Arm64Jit::Comp_mxc1(MIPSOpcode op) STR(INDEX_UNSIGNED, gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31)); if (!wasImm) { UBFX(gpr.R(MIPS_REG_FPCOND), gpr.R(rt), 23, 1); + // TODO: We do have the fcr31 value in a register here, could use that in UpdateRoundingMode to avoid reloading it. + UpdateRoundingMode(); + } else { + UpdateRoundingMode(immVal); } - // TODO: We do have the fcr31 value in a register here, could use that in UpdateRoundingMode to avoid reloading it. - UpdateRoundingMode(); ApplyRoundingMode(); } else { Comp_Generic(op); diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 378d38a3e5..46b1a9bf3e 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -602,7 +602,12 @@ void Arm64Jit::ApplyRoundingMode(bool force) { } // Destroys SCRATCH1 and SCRATCH2 -void Arm64Jit::UpdateRoundingMode() { +void Arm64Jit::UpdateRoundingMode(u32 fcr31) { + // We must set js.hasSetRounding at compile time, or this block will use the wrong rounding mode. + // The fcr31 parameter is -1 when not known at compile time, so we just assume it was changed. + if (fcr31 & 0x01000003) { + js.hasSetRounding = true; + } QuickCallFunction(SCRATCH2_64, updateRoundingMode); } diff --git a/Core/MIPS/ARM64/Arm64Jit.h b/Core/MIPS/ARM64/Arm64Jit.h index 5d815eef83..3d84451384 100644 --- a/Core/MIPS/ARM64/Arm64Jit.h +++ b/Core/MIPS/ARM64/Arm64Jit.h @@ -202,7 +202,7 @@ private: void WriteDownCountR(Arm64Gen::ARM64Reg reg, bool updateFlags = true); void RestoreRoundingMode(bool force = false); void ApplyRoundingMode(bool force = false); - void UpdateRoundingMode(); + void UpdateRoundingMode(u32 fcr31 = -1); void MovFromPC(Arm64Gen::ARM64Reg r); void MovToPC(Arm64Gen::ARM64Reg r); diff --git a/Core/MIPS/IR/IRFrontend.cpp b/Core/MIPS/IR/IRFrontend.cpp index d7ca005e65..b86ff2890e 100644 --- a/Core/MIPS/IR/IRFrontend.cpp +++ b/Core/MIPS/IR/IRFrontend.cpp @@ -200,6 +200,8 @@ void IRFrontend::ApplyRoundingMode(bool force) { // Destroys SCRATCH1 and SCRATCH2 void IRFrontend::UpdateRoundingMode() { + // We must set js.hasSetRounding at compile time, or this block will use the wrong rounding mode. + js.hasSetRounding = true; ir.Write(IROp::UpdateRoundingMode); } diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index 64d0e9af35..a6242801ff 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -109,18 +109,6 @@ void Jit::GenerateFixedCode(JitOptions &jo) { RET(); } - updateRoundingMode = AlignCode16(); { - // If it's only ever 0, we don't actually bother applying or restoring it. - // This is the most common situation. - TEST(32, MIPSSTATE_VAR(fcr31), Imm32(0x01000003)); - FixupBranch skip = J_CC(CC_Z); - // TODO: Move the hasSetRounding flag somewhere we can reach it through the context pointer, or something. - MOV(PTRBITS, R(RAX), ImmPtr(&js.hasSetRounding)); - MOV(8, MatR(RAX), Imm8(1)); - SetJumpTarget(skip); - RET(); - } - enterDispatcher = AlignCode16(); ABI_PushAllCalleeSavedRegsAndAdjustStack(); #ifdef _M_X64 diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index 9ed0c6871c..664490966e 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -426,7 +426,7 @@ void Jit::Comp_mxc1(MIPSOpcode op) { if ((gpr.GetImm(rt) & 0x1000003) == 0) { // Default nearest / no-flush mode, just leave it cleared. } else { - UpdateRoundingMode(); + UpdateRoundingMode(gpr.GetImm(rt)); ApplyRoundingMode(); } } else { diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index d92f33a1ca..45eadbf612 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -198,8 +198,12 @@ void Jit::ApplyRoundingMode(bool force) { } } -void Jit::UpdateRoundingMode() { - CALL(updateRoundingMode); +void Jit::UpdateRoundingMode(u32 fcr31) { + // We must set js.hasSetRounding at compile time, or this block will use the wrong rounding mode. + // The fcr31 parameter is -1 when not known at compile time, so we just assume it was changed. + if (fcr31 & 0x01000003) { + js.hasSetRounding = true; + } } void Jit::ClearCache() @@ -418,8 +422,6 @@ void Jit::AddContinuedBlock(u32 dest) { bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) { if (ptr == applyRoundingMode) name = "applyRoundingMode"; - else if (ptr == updateRoundingMode) - name = "updateRoundingMode"; else if (ptr == dispatcher) name = "dispatcher"; else if (ptr == dispatcherInEAXNoCheck) diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 973c5ce496..1c397005ff 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -155,7 +155,7 @@ public: void RestoreRoundingMode(bool force = false); void ApplyRoundingMode(bool force = false); - void UpdateRoundingMode(); + void UpdateRoundingMode(u32 fcr31 = -1); JitBlockCache *GetBlockCache() override { return &blocks; } JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; } @@ -324,7 +324,6 @@ private: const u8 *restoreRoundingMode; const u8 *applyRoundingMode; - const u8 *updateRoundingMode; const u8 *endOfPregeneratedCode;