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.
This commit is contained in:
Unknown W. Brackets 2018-04-01 10:36:16 -07:00
parent 09e307b097
commit ab809bd19e
13 changed files with 37 additions and 55 deletions

View file

@ -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();

View file

@ -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);

View file

@ -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,

View file

@ -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;
};

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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;