diff --git a/Core/Config.cpp b/Core/Config.cpp index 874456780f..53cdfe926e 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -326,14 +326,6 @@ static ConfigSetting generalSettings[] = { ConfigSetting(false), }; -static bool DefaultForceFlushToZero() { -#ifdef ARM - return true; -#else - return false; -#endif -} - static ConfigSetting cpuSettings[] = { ReportedConfigSetting("Jit", &g_Config.bJit, &DefaultJit, true, true), ReportedConfigSetting("SeparateCPUThread", &g_Config.bSeparateCPUThread, false, true, true), @@ -343,7 +335,6 @@ static ConfigSetting cpuSettings[] = { ReportedConfigSetting("FuncReplacements", &g_Config.bFuncReplacements, true, true, true), ReportedConfigSetting("CPUSpeed", &g_Config.iLockedCPUSpeed, 0, true, true), ReportedConfigSetting("SetRoundingMode", &g_Config.bSetRoundingMode, true, true, true), - ReportedConfigSetting("ForceFlushToZero", &g_Config.bForceFlushToZero, &DefaultForceFlushToZero, true, true), ConfigSetting(false), }; diff --git a/Core/Config.h b/Core/Config.h index 531896e00b..81a1f63d64 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -117,7 +117,6 @@ public: bool bForceLagSync; bool bFuncReplacements; bool bSetRoundingMode; - bool bForceFlushToZero; // Definitely cannot be changed while game is running. bool bSeparateCPUThread; diff --git a/Core/MIPS/ARM/ArmJit.cpp b/Core/MIPS/ARM/ArmJit.cpp index 506c16a10e..3410aaf221 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -587,14 +587,10 @@ void ArmJit::WriteDownCountR(ARMReg reg) { void ArmJit::RestoreRoundingMode(bool force) { // If the game has never set an interesting rounding mode, we can safely skip this. - if (g_Config.bSetRoundingMode && (force || !g_Config.bForceFlushToZero || js.hasSetRounding)) { + if (g_Config.bSetRoundingMode && (force || js.hasSetRounding)) { VMRS(SCRATCHREG2); - // Assume we're always in round-to-nearest mode beforehand. - // Also on ARM, we're always in flush-to-zero in C++, so stay that way. - if (!g_Config.bForceFlushToZero) { - ORR(SCRATCHREG2, SCRATCHREG2, AssumeMakeOperand2(4 << 22)); - } - BIC(SCRATCHREG2, SCRATCHREG2, AssumeMakeOperand2(3 << 22)); + // Assume we're always in round-to-nearest mode beforehand. Flush-to-zero is off. + BIC(SCRATCHREG2, SCRATCHREG2, AssumeMakeOperand2((3 | 4) << 22)); VMSR(SCRATCHREG2); } } @@ -602,19 +598,17 @@ void ArmJit::RestoreRoundingMode(bool force) { void ArmJit::ApplyRoundingMode(bool force) { // NOTE: Must not destroy R0. // If the game has never set an interesting rounding mode, we can safely skip this. - if (g_Config.bSetRoundingMode && (force || !g_Config.bForceFlushToZero || js.hasSetRounding)) { + if (g_Config.bSetRoundingMode && (force || js.hasSetRounding)) { LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31)); - if (!g_Config.bForceFlushToZero) { - TST(SCRATCHREG2, AssumeMakeOperand2(1 << 24)); - AND(SCRATCHREG2, SCRATCHREG2, Operand2(3)); - SetCC(CC_NEQ); - ADD(SCRATCHREG2, SCRATCHREG2, Operand2(4)); - SetCC(CC_AL); - // We can only skip if the rounding mode is zero and flush is set. - CMP(SCRATCHREG2, Operand2(4)); - } else { - ANDS(SCRATCHREG2, SCRATCHREG2, Operand2(3)); - } + + TST(SCRATCHREG2, AssumeMakeOperand2(1 << 24)); + AND(SCRATCHREG2, SCRATCHREG2, Operand2(3)); + SetCC(CC_NEQ); + ADD(SCRATCHREG2, SCRATCHREG2, Operand2(4)); + SetCC(CC_AL); + // We can only skip if the rounding mode is zero and flush is not set. + CMP(SCRATCHREG2, Operand2(3)); + // At this point, if it was zero, we can skip the rest. FixupBranch skip = B_CC(CC_EQ); PUSH(1, SCRATCHREG1); @@ -624,12 +618,8 @@ void ArmJit::ApplyRoundingMode(bool force) { // 1: Round to zero 3 // 2: Round up (ceil) 1 // 3: Round down (floor) 2 - if (!g_Config.bForceFlushToZero) { - AND(SCRATCHREG1, SCRATCHREG2, Operand2(3)); - CMP(SCRATCHREG1, Operand2(1)); - } else { - CMP(SCRATCHREG2, Operand2(1)); - } + AND(SCRATCHREG1, SCRATCHREG2, Operand2(3)); + CMP(SCRATCHREG1, Operand2(1)); SetCC(CC_EQ); ADD(SCRATCHREG2, SCRATCHREG2, Operand2(2)); SetCC(CC_GT); SUB(SCRATCHREG2, SCRATCHREG2, Operand2(1)); @@ -637,10 +627,8 @@ void ArmJit::ApplyRoundingMode(bool force) { VMRS(SCRATCHREG1); // Assume we're always in round-to-nearest mode beforehand. - if (!g_Config.bForceFlushToZero) { - // But we need to clear flush to zero in this case anyway. - BIC(SCRATCHREG1, SCRATCHREG1, AssumeMakeOperand2(7 << 22)); - } + // But we need to clear flush to zero in this case anyway. + BIC(SCRATCHREG1, SCRATCHREG1, AssumeMakeOperand2((3 | 4) << 22)); ORR(SCRATCHREG1, SCRATCHREG1, Operand2(SCRATCHREG2, ST_LSL, 22)); VMSR(SCRATCHREG1); @@ -650,20 +638,17 @@ void ArmJit::ApplyRoundingMode(bool force) { } void ArmJit::UpdateRoundingMode() { - // NOTE: Must not destory R0. + // NOTE: Must not destroy R0. if (g_Config.bSetRoundingMode) { LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31)); - if (!g_Config.bForceFlushToZero) { - TST(SCRATCHREG2, AssumeMakeOperand2(1 << 24)); - AND(SCRATCHREG2, SCRATCHREG2, Operand2(3)); - SetCC(CC_NEQ); - ADD(SCRATCHREG2, SCRATCHREG2, Operand2(4)); - SetCC(CC_AL); - // We can only skip if the rounding mode is zero and flush is set. - CMP(SCRATCHREG2, Operand2(4)); - } else { - ANDS(SCRATCHREG2, SCRATCHREG2, Operand2(3)); - } + + TST(SCRATCHREG2, AssumeMakeOperand2(1 << 24)); + AND(SCRATCHREG2, SCRATCHREG2, Operand2(3)); + SetCC(CC_NEQ); + ADD(SCRATCHREG2, SCRATCHREG2, Operand2(4)); + SetCC(CC_AL); + // We can only skip if the rounding mode is zero and flush is not set. + CMP(SCRATCHREG2, Operand2(3)); FixupBranch skip = B_CC(CC_EQ); PUSH(1, SCRATCHREG1); diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 9ab45e3962..3df1cfc545 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -526,14 +526,13 @@ void Arm64Jit::WriteDownCountR(ARM64Reg reg, bool updateFlags) { void Arm64Jit::RestoreRoundingMode(bool force) { // If the game has never set an interesting rounding mode, we can safely skip this. - if (g_Config.bSetRoundingMode && (force || !g_Config.bForceFlushToZero || js.hasSetRounding)) { + if (g_Config.bSetRoundingMode && (force || js.hasSetRounding)) { MRS(SCRATCH2_64, FIELD_FPCR); + // We are not in flush-to-zero mode outside the JIT, so let's turn it off. + uint32_t mask = ~(4 << 22); // Assume we're always in round-to-nearest mode beforehand. - // Also on ARM, we're always in flush-to-zero in C++, so stay that way. - if (!g_Config.bForceFlushToZero) { - ORRI2R(SCRATCH2, SCRATCH2, 4 << 22); - } - ANDI2R(SCRATCH2, SCRATCH2, ~(3 << 22)); + mask &= ~(3 << 22); + ANDI2R(SCRATCH2, SCRATCH2, mask); _MSR(FIELD_FPCR, SCRATCH2_64); } } @@ -541,19 +540,15 @@ void Arm64Jit::RestoreRoundingMode(bool force) { void Arm64Jit::ApplyRoundingMode(bool force) { // NOTE: Must not destroy SCRATCH1. // If the game has never set an interesting rounding mode, we can safely skip this. - if (g_Config.bSetRoundingMode && (force || !g_Config.bForceFlushToZero || js.hasSetRounding)) { + if (g_Config.bSetRoundingMode && (force || js.hasSetRounding)) { LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); - if (!g_Config.bForceFlushToZero) { - TSTI2R(SCRATCH2, 1 << 24); - ANDI2R(SCRATCH2, SCRATCH2, 3); - FixupBranch skip1 = B(CC_EQ); - ADDI2R(SCRATCH2, SCRATCH2, 4); - SetJumpTarget(skip1); - // We can only skip if the rounding mode is zero and flush is set. - CMPI2R(SCRATCH2, 4); - } else { - ANDSI2R(SCRATCH2, SCRATCH2, 3); - } + TSTI2R(SCRATCH2, 1 << 24); + ANDI2R(SCRATCH2, SCRATCH2, 3); + FixupBranch skip1 = B(CC_EQ); + ADDI2R(SCRATCH2, SCRATCH2, 4); + SetJumpTarget(skip1); + // We can only skip if the rounding mode is zero and flush is set. + CMPI2R(SCRATCH2, 4); // At this point, if it was zero, we can skip the rest. FixupBranch skip = B(CC_EQ); PUSH(SCRATCH1); @@ -563,12 +558,8 @@ void Arm64Jit::ApplyRoundingMode(bool force) { // 1: Round to zero 3 // 2: Round up (ceil) 1 // 3: Round down (floor) 2 - if (!g_Config.bForceFlushToZero) { - ANDI2R(SCRATCH1, SCRATCH2, 3); - CMPI2R(SCRATCH1, 1); - } else { - CMPI2R(SCRATCH2, 1); - } + ANDI2R(SCRATCH1, SCRATCH2, 3); + CMPI2R(SCRATCH1, 1); FixupBranch skipadd = B(CC_NEQ); ADDI2R(SCRATCH2, SCRATCH2, 2); @@ -578,11 +569,10 @@ void Arm64Jit::ApplyRoundingMode(bool force) { SetJumpTarget(skipsub); MRS(SCRATCH1_64, FIELD_FPCR); - // Assume we're always in round-to-nearest mode beforehand. - if (!g_Config.bForceFlushToZero) { - // But we need to clear flush to zero in this case anyway. - ANDI2R(SCRATCH1, SCRATCH1, ~(7 << 22)); - } + + // Clear both flush-to-zero and rounding before re-setting them. + ANDI2R(SCRATCH1, SCRATCH1, ~((4 | 3) << 22)); + ORR(SCRATCH1, SCRATCH1, SCRATCH2, ArithOption(SCRATCH2, ST_LSL, 22)); _MSR(FIELD_FPCR, SCRATCH1_64); @@ -603,25 +593,23 @@ void Arm64Jit::UpdateRoundingMode() { // NOTE: Must not destroy SCRATCH1. if (g_Config.bSetRoundingMode) { LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); - if (!g_Config.bForceFlushToZero) { - TSTI2R(SCRATCH2, 1 << 24); - ANDI2R(SCRATCH2, SCRATCH2, 3); - FixupBranch skip = B(CC_EQ); - ADDI2R(SCRATCH2, SCRATCH2, 4); - SetJumpTarget(skip); - // We can only skip if the rounding mode is zero and flush is set. - CMPI2R(SCRATCH2, 4); - } else { - ANDSI2R(SCRATCH2, SCRATCH2, 3); - } + TSTI2R(SCRATCH2, 1 << 24); + ANDI2R(SCRATCH2, SCRATCH2, 3); FixupBranch skip = B(CC_EQ); + ADDI2R(SCRATCH2, SCRATCH2, 4); + SetJumpTarget(skip); + + // We can only skip if the rounding mode is zero and flush is not set. + CMPI2R(SCRATCH2, 3); + + FixupBranch skip2 = B(CC_EQ); PUSH(SCRATCH1_64); MOVI2R(SCRATCH2, 1); MOVP2R(SCRATCH1_64, &js.hasSetRounding); STRB(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0); POP(SCRATCH1_64); - SetJumpTarget(skip); + SetJumpTarget(skip2); } } diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index de02a2802e..1195e04502 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -223,7 +223,7 @@ void Jit::WriteDowncount(int offset) void Jit::RestoreRoundingMode(bool force, XEmitter *emitter) { // If the game has never set an interesting rounding mode, we can safely skip this. - if (g_Config.bSetRoundingMode && (force || g_Config.bForceFlushToZero || js.hasSetRounding)) + if (g_Config.bSetRoundingMode && (force || js.hasSetRounding)) { if (emitter == NULL) emitter = this; @@ -237,7 +237,7 @@ void Jit::RestoreRoundingMode(bool force, XEmitter *emitter) void Jit::ApplyRoundingMode(bool force, XEmitter *emitter) { // If the game has never set an interesting rounding mode, we can safely skip this. - if (g_Config.bSetRoundingMode && (force || g_Config.bForceFlushToZero || js.hasSetRounding)) + if (g_Config.bSetRoundingMode && (force || js.hasSetRounding)) { if (emitter == NULL) emitter = this; @@ -247,9 +247,7 @@ void Jit::ApplyRoundingMode(bool force, XEmitter *emitter) // If it's 0, we don't actually bother setting. This is the most common. // We always use nearest as the default rounding mode with // flush-to-zero disabled. - FixupBranch skip; - if (!g_Config.bForceFlushToZero) - skip = emitter->J_CC(CC_Z); + FixupBranch skip = emitter->J_CC(CC_Z); emitter->STMXCSR(M(&mips_->temp)); @@ -263,19 +261,13 @@ void Jit::ApplyRoundingMode(bool force, XEmitter *emitter) emitter->SHL(32, R(EAX), Imm8(13)); emitter->OR(32, M(&mips_->temp), R(EAX)); - if (g_Config.bForceFlushToZero) { - emitter->OR(32, M(&mips_->temp), Imm32(1 << 15)); - } else { - emitter->TEST(32, M(&mips_->fcr31), Imm32(1 << 24)); - FixupBranch skip3 = emitter->J_CC(CC_Z); - emitter->OR(32, M(&mips_->temp), Imm32(1 << 15)); - emitter->SetJumpTarget(skip3); - } + emitter->TEST(32, M(&mips_->fcr31), Imm32(1 << 24)); + FixupBranch skip3 = emitter->J_CC(CC_Z); + emitter->OR(32, M(&mips_->temp), Imm32(1 << 15)); + emitter->SetJumpTarget(skip3); emitter->LDMXCSR(M(&mips_->temp)); - - if (!g_Config.bForceFlushToZero) - emitter->SetJumpTarget(skip); + emitter->SetJumpTarget(skip); } }