Merge pull request #8040 from hrydgard/rounding-cleanup

Rounding cleanup
This commit is contained in:
Henrik Rydgård committed 2015-10-08 18:52:44 +02:00
commit 809a0cdb4f
8 files changed
+91 -149

No files matched your search

-10
View File
@@ -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),
@@ -342,8 +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),
ReportedConfigSetting("ForceFlushToZero", &g_Config.bForceFlushToZero, &DefaultForceFlushToZero, true, true),
ConfigSetting(false),
};
-2
View File
@@ -116,8 +116,6 @@ public:
bool bCheckForNewVersion;
bool bForceLagSync;
bool bFuncReplacements;
bool bSetRoundingMode;
bool bForceFlushToZero;
// Definitely cannot be changed while game is running.
bool bSeparateCPUThread;
+34 -51
View File
@@ -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 (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 (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,29 +638,24 @@ void ArmJit::ApplyRoundingMode(bool force) {
}
void ArmJit::UpdateRoundingMode() {
// NOTE: Must not destory 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));
}
// NOTE: Must not destroy R0.
LDR(SCRATCHREG2, CTXREG, offsetof(MIPSState, fcr31));
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);
}
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);
}
// IDEA - could have a WriteDualExit that takes two destinations and two condition flags,
+1
View File
@@ -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 {
+37 -54
View File
@@ -524,51 +524,42 @@ 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 (g_Config.bSetRoundingMode && (force || !g_Config.bForceFlushToZero || 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);
// 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);
}
}
// 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 (g_Config.bSetRoundingMode && (force || !g_Config.bForceFlushToZero || js.hasSetRounding)) {
if (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);
// MIPS Rounding Mode: ARM Rounding Mode
// 0: Round nearest 0
// 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);
@@ -594,35 +584,28 @@ 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.
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);
}
LDR(INDEX_UNSIGNED, SCRATCH2, CTXREG, offsetof(MIPSState, fcr31));
FixupBranch skip = 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);
}
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);
MOVI2R(SCRATCH2, 1);
MOVP2R(SCRATCH1_64, &js.hasSetRounding);
STRB(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0);
SetJumpTarget(skip2);
}
// IDEA - could have a WriteDualExit that takes two destinations and two condition flags,
+19 -30
View File
@@ -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 (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 (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,42 +261,33 @@ 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);
}
}
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()
-1
View File
@@ -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")));
-1
View File
@@ -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();