From ab809bd19ee15d2ef03a250345f70eb9948ecf01 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 1 Apr 2018 10:36:16 -0700 Subject: [PATCH] jit: Apply hasSetRounding at compile time. Otherwise, the block will be executed with the wrong rounding mode the first time rounding is set. This could be important if it was set for a single operation. This is only a problem the first time it's set. --- Core/MIPS/ARM/ArmAsm.cpp | 14 -------------- Core/MIPS/ARM/ArmCompFPU.cpp | 8 ++++++-- Core/MIPS/ARM/ArmJit.cpp | 8 ++++++-- Core/MIPS/ARM/ArmJit.h | 3 +-- Core/MIPS/ARM64/Arm64Asm.cpp | 11 ----------- Core/MIPS/ARM64/Arm64CompFPU.cpp | 10 +++++++--- Core/MIPS/ARM64/Arm64Jit.cpp | 7 ++++++- Core/MIPS/ARM64/Arm64Jit.h | 2 +- Core/MIPS/IR/IRFrontend.cpp | 2 ++ Core/MIPS/x86/Asm.cpp | 12 ------------ Core/MIPS/x86/CompFPU.cpp | 2 +- Core/MIPS/x86/Jit.cpp | 10 ++++++---- Core/MIPS/x86/Jit.h | 3 +-- 13 files changed, 37 insertions(+), 55 deletions(-) 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;