From 6dd86cd843ed3a7f43a681bb2028a1abd21b0ecc Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 8 Oct 2015 10:29:35 +0200 Subject: [PATCH 1/3] Get rid of the ForceFlushToZero hidden config option --- Core/Config.cpp | 9 ----- Core/Config.h | 1 - Core/MIPS/ARM/ArmJit.cpp | 67 ++++++++++++++-------------------- Core/MIPS/ARM64/Arm64Jit.cpp | 70 +++++++++++++++--------------------- Core/MIPS/x86/Jit.cpp | 24 +++++-------- 5 files changed, 63 insertions(+), 108 deletions(-) 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); } } From bfed830f91399cab8a31f587f62bf538c1ce8cda Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 8 Oct 2015 10:32:39 +0200 Subject: [PATCH 2/3] Remove the ability to disable rounding mode support. It's time. --- Core/Config.cpp | 1 - Core/Config.h | 1 - Core/MIPS/ARM/ArmJit.cpp | 36 +++++++++++++++++------------------- Core/MIPS/ARM64/Arm64Jit.cpp | 36 +++++++++++++++++------------------- Core/MIPS/x86/Jit.cpp | 29 +++++++++++++---------------- UI/GameSettingsScreen.cpp | 1 - headless/Headless.cpp | 1 - 7 files changed, 47 insertions(+), 58 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 53cdfe926e..1892c4a68a 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -334,7 +334,6 @@ static ConfigSetting cpuSettings[] = { ConfigSetting("FastMemoryAccess", &g_Config.bFastMemory, true, true, true), ReportedConfigSetting("FuncReplacements", &g_Config.bFuncReplacements, true, true, true), ReportedConfigSetting("CPUSpeed", &g_Config.iLockedCPUSpeed, 0, true, true), - ReportedConfigSetting("SetRoundingMode", &g_Config.bSetRoundingMode, true, true, true), ConfigSetting(false), }; diff --git a/Core/Config.h b/Core/Config.h index 81a1f63d64..e360488880 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -116,7 +116,6 @@ public: bool bCheckForNewVersion; bool bForceLagSync; bool bFuncReplacements; - bool bSetRoundingMode; // 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 3410aaf221..d889479e1f 100644 --- a/Core/MIPS/ARM/ArmJit.cpp +++ b/Core/MIPS/ARM/ArmJit.cpp @@ -587,7 +587,7 @@ 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 || js.hasSetRounding)) { + if (force || js.hasSetRounding) { VMRS(SCRATCHREG2); // Assume we're always in round-to-nearest mode beforehand. Flush-to-zero is off. BIC(SCRATCHREG2, SCRATCHREG2, AssumeMakeOperand2((3 | 4) << 22)); @@ -598,7 +598,7 @@ 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 || js.hasSetRounding)) { + if (force || js.hasSetRounding) { LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31)); TST(SCRATCHREG2, AssumeMakeOperand2(1 << 24)); @@ -639,25 +639,23 @@ void ArmJit::ApplyRoundingMode(bool force) { void ArmJit::UpdateRoundingMode() { // NOTE: Must not destroy R0. - if (g_Config.bSetRoundingMode) { - LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31)); + LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31)); - 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)); + 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); - MOVI2R(SCRATCHREG2, 1); - MOVP2R(SCRATCHREG1, &js.hasSetRounding); - STRB(SCRATCHREG2, SCRATCHREG1, 0); - POP(1, SCRATCHREG1); - SetJumpTarget(skip); - } + FixupBranch skip = B_CC(CC_EQ); + PUSH(1, SCRATCHREG1); + MOVI2R(SCRATCHREG2, 1); + MOVP2R(SCRATCHREG1, &js.hasSetRounding); + STRB(SCRATCHREG2, SCRATCHREG1, 0); + POP(1, SCRATCHREG1); + SetJumpTarget(skip); } // IDEA - could have a WriteDualExit that takes two destinations and two condition flags, diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 3df1cfc545..71dfa81e78 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -526,7 +526,7 @@ 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 || js.hasSetRounding)) { + if (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); @@ -540,7 +540,7 @@ 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 || js.hasSetRounding)) { + if (force || js.hasSetRounding) { LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); TSTI2R(SCRATCH2, 1 << 24); ANDI2R(SCRATCH2, SCRATCH2, 3); @@ -591,26 +591,24 @@ void Arm64Jit::ApplyRoundingMode(bool force) { void Arm64Jit::UpdateRoundingMode() { // NOTE: Must not destroy SCRATCH1. - if (g_Config.bSetRoundingMode) { - LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); + LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); - TSTI2R(SCRATCH2, 1 << 24); - ANDI2R(SCRATCH2, SCRATCH2, 3); - FixupBranch skip = B(CC_EQ); - ADDI2R(SCRATCH2, SCRATCH2, 4); - SetJumpTarget(skip); + 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); + // 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(skip2); - } + 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(skip2); } // IDEA - could have a WriteDualExit that takes two destinations and two condition flags, diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 1195e04502..c1a0a4ef01 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 || js.hasSetRounding)) + if (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 || js.hasSetRounding)) + if (force || js.hasSetRounding) { if (emitter == NULL) emitter = this; @@ -273,24 +273,21 @@ void Jit::ApplyRoundingMode(bool force, XEmitter *emitter) void Jit::UpdateRoundingMode(XEmitter *emitter) { - if (g_Config.bSetRoundingMode) - { - if (emitter == NULL) - emitter = this; + if (emitter == NULL) + emitter = this; - // If it's only ever 0, we don't actually bother applying or restoring it. - // This is the most common situation. - emitter->TEST(32, M(&mips_->fcr31), Imm32(0x01000003)); - FixupBranch skip = emitter->J_CC(CC_Z); + // If it's only ever 0, we don't actually bother applying or restoring it. + // This is the most common situation. + emitter->TEST(32, M(&mips_->fcr31), Imm32(0x01000003)); + FixupBranch skip = emitter->J_CC(CC_Z); #ifdef _M_X64 - // TODO: Move the hasSetRounding flag somewhere we can reach it through the context pointer, or something. - emitter->MOV(64, R(RAX), Imm64((uintptr_t)&js.hasSetRounding)); - emitter->MOV(8, MatR(RAX), Imm8(1)); + // TODO: Move the hasSetRounding flag somewhere we can reach it through the context pointer, or something. + emitter->MOV(64, R(RAX), Imm64((uintptr_t)&js.hasSetRounding)); + emitter->MOV(8, MatR(RAX), Imm8(1)); #else - emitter->MOV(8, M(&js.hasSetRounding), Imm8(1)); + emitter->MOV(8, M(&js.hasSetRounding), Imm8(1)); #endif - emitter->SetJumpTarget(skip); - } + emitter->SetJumpTarget(skip); } void Jit::ClearCache() diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index f1043c11e1..3c8c505c40 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -509,7 +509,6 @@ void GameSettingsScreen::CreateViews() { #ifndef MOBILE_DEVICE systemSettings->Add(new PopupSliderChoice(&g_Config.iRewindFlipFrequency, 0, 1800, sy->T("Rewind Snapshot Frequency", "Rewind Snapshot Frequency (0 = off, mem hog)"), screenManager())); #endif - systemSettings->Add(new CheckBox(&g_Config.bSetRoundingMode, sy->T("Respect FPU rounding (disable for old GEB saves)")))->OnClick.Handle(this, &GameSettingsScreen::OnJitAffectingSetting); systemSettings->Add(new ItemHeader(sy->T("General"))); diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 8b6d2d29d2..92490cc4ac 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -357,7 +357,6 @@ int main(int argc, const char* argv[]) g_Config.bSoftwareSkinning = true; g_Config.bVertexDecoderJit = true; g_Config.bBlockTransferGPU = true; - g_Config.bSetRoundingMode = true; #ifdef _WIN32 InitSysDirectories(); From 8a3c96a413e57f9a2474b5241a1e1a5fa584d4ba Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 8 Oct 2015 11:03:08 +0200 Subject: [PATCH 3/3] ARM64: Don't need to avoid destroying SCRATCH1 in these functions. --- Core/MIPS/ARM64/Arm64CompFPU.cpp | 1 + Core/MIPS/ARM64/Arm64Jit.cpp | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Core/MIPS/ARM64/Arm64CompFPU.cpp b/Core/MIPS/ARM64/Arm64CompFPU.cpp index df71b3b3d4..d34f8333c1 100644 --- a/Core/MIPS/ARM64/Arm64CompFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompFPU.cpp @@ -386,6 +386,7 @@ void Arm64Jit::Comp_mxc1(MIPSOpcode op) 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(); ApplyRoundingMode(); } else { diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index 71dfa81e78..96b4b51807 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -524,6 +524,7 @@ void Arm64Jit::WriteDownCountR(ARM64Reg reg, bool updateFlags) { } } +// Destroys SCRATCH2 void Arm64Jit::RestoreRoundingMode(bool force) { // If the game has never set an interesting rounding mode, we can safely skip this. if (force || js.hasSetRounding) { @@ -537,8 +538,8 @@ void Arm64Jit::RestoreRoundingMode(bool force) { } } +// Destroys SCRATCH1 and SCRATCH2 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 (force || js.hasSetRounding) { LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); @@ -551,7 +552,6 @@ void Arm64Jit::ApplyRoundingMode(bool force) { CMPI2R(SCRATCH2, 4); // At this point, if it was zero, we can skip the rest. FixupBranch skip = B(CC_EQ); - PUSH(SCRATCH1); // MIPS Rounding Mode: ARM Rounding Mode // 0: Round nearest 0 @@ -584,13 +584,12 @@ void Arm64Jit::ApplyRoundingMode(bool force) { MOVP2R(SCRATCH1_64, &js.currentRoundingFunc); STR(INDEX_UNSIGNED, SCRATCH2_64, SCRATCH1_64, 0); - POP(SCRATCH1); SetJumpTarget(skip); } } +// Destroys SCRATCH1 and SCRATCH2 void Arm64Jit::UpdateRoundingMode() { - // NOTE: Must not destroy SCRATCH1. LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31)); TSTI2R(SCRATCH2, 1 << 24); @@ -603,11 +602,9 @@ void Arm64Jit::UpdateRoundingMode() { 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(skip2); }