mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-24 08:39:51 +00:00
Merge pull request #10847 from unknownbrackets/arm64jit
arm64jit: Update rounding mode on thread switch
This commit is contained in:
commit
0d677fff87
@ -31,6 +31,7 @@
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/MemMapHelpers.h"
|
||||
#include "Core/MIPS/JitCommon/JitCommon.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
|
||||
@ -1460,6 +1461,10 @@ void __KernelLoadContext(ThreadContext *ctx, bool vfpuEnabled)
|
||||
}
|
||||
|
||||
memcpy(currentMIPS->other, ctx->other, sizeof(ctx->other));
|
||||
if (MIPSComp::jit) {
|
||||
// When thread switching, we must update the rounding mode if cached in the jit.
|
||||
MIPSComp::jit->UpdateFCR31();
|
||||
}
|
||||
|
||||
// Reset the llBit, the other thread may have touched memory.
|
||||
currentMIPS->llBit = 0;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -106,6 +106,9 @@ void ArmJit::DoState(PointerWrap &p)
|
||||
}
|
||||
}
|
||||
|
||||
void ArmJit::UpdateFCR31() {
|
||||
}
|
||||
|
||||
void ArmJit::FlushAll()
|
||||
{
|
||||
gpr.FlushAll();
|
||||
@ -637,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,
|
||||
|
@ -175,6 +175,7 @@ public:
|
||||
|
||||
void ClearCache() override;
|
||||
void InvalidateCacheAt(u32 em_address, int length = 4) override;
|
||||
void UpdateFCR31() override;
|
||||
|
||||
void EatPrefix() override { js.EatPrefix(); }
|
||||
|
||||
@ -202,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);
|
||||
|
||||
@ -310,7 +311,6 @@ public:
|
||||
|
||||
const u8 *restoreRoundingMode;
|
||||
const u8 *applyRoundingMode;
|
||||
const u8 *updateRoundingMode;
|
||||
|
||||
const u8 *breakpointBailout;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -79,7 +79,7 @@ Arm64Jit::Arm64Jit(MIPSState *mips) : blocks(mips, this), gpr(mips, &js, &jo), f
|
||||
AllocCodeSpace(1024 * 1024 * 16); // 32MB is the absolute max because that's what an ARM branch instruction can reach, backwards and forwards.
|
||||
GenerateFixedCode(jo);
|
||||
js.startDefaultPrefix = mips_->HasDefaultPrefix();
|
||||
js.currentRoundingFunc = convertS0ToSCRATCH1[0];
|
||||
js.currentRoundingFunc = convertS0ToSCRATCH1[mips_->fcr31 & 3];
|
||||
}
|
||||
|
||||
Arm64Jit::~Arm64Jit() {
|
||||
@ -98,13 +98,14 @@ void Arm64Jit::DoState(PointerWrap &p) {
|
||||
js.hasSetRounding = 1;
|
||||
}
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ) {
|
||||
js.currentRoundingFunc = convertS0ToSCRATCH1[(mips_->fcr31) & 3];
|
||||
}
|
||||
// Note: we can't update the currentRoundingFunc here because fcr31 wasn't loaded yet.
|
||||
}
|
||||
|
||||
void Arm64Jit::FlushAll()
|
||||
{
|
||||
void Arm64Jit::UpdateFCR31() {
|
||||
js.currentRoundingFunc = convertS0ToSCRATCH1[mips_->fcr31 & 3];
|
||||
}
|
||||
|
||||
void Arm64Jit::FlushAll() {
|
||||
gpr.FlushAll();
|
||||
fpr.FlushAll();
|
||||
FlushPrefixV();
|
||||
@ -601,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);
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ public:
|
||||
|
||||
void ClearCache() override;
|
||||
void InvalidateCacheAt(u32 em_address, int length = 4) override;
|
||||
void UpdateFCR31() override;
|
||||
|
||||
void EatPrefix() override { js.EatPrefix(); }
|
||||
|
||||
@ -201,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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,9 @@ void IRJit::DoState(PointerWrap &p) {
|
||||
frontend_.DoState(p);
|
||||
}
|
||||
|
||||
void IRJit::UpdateFCR31() {
|
||||
}
|
||||
|
||||
void IRJit::ClearCache() {
|
||||
ILOG("IRJit: Clearing the cache!");
|
||||
blocks_.Clear();
|
||||
|
@ -158,6 +158,7 @@ public:
|
||||
|
||||
void ClearCache() override;
|
||||
void InvalidateCacheAt(u32 em_address, int length = 4) override;
|
||||
void UpdateFCR31() override;
|
||||
|
||||
const u8 *GetDispatcher() const override { return nullptr; }
|
||||
|
||||
|
@ -131,6 +131,7 @@ namespace MIPSComp {
|
||||
virtual void Compile(u32 em_address) = 0;
|
||||
virtual void CompileFunction(u32 start_address, u32 length) { }
|
||||
virtual void ClearCache() = 0;
|
||||
virtual void UpdateFCR31() = 0;
|
||||
virtual MIPSOpcode GetOriginalOp(MIPSOpcode op) = 0;
|
||||
|
||||
// No jit operations may be run between these calls.
|
||||
|
@ -293,6 +293,11 @@ void MIPSState::DoState(PointerWrap &p) {
|
||||
p.Do(inDelaySlot);
|
||||
p.Do(llBit);
|
||||
p.Do(debugCount);
|
||||
|
||||
if (p.mode == p.MODE_READ && MIPSComp::jit) {
|
||||
// Now that we've loaded fcr31, update any jit state associated.
|
||||
MIPSComp::jit->UpdateFCR31();
|
||||
}
|
||||
}
|
||||
|
||||
void MIPSState::SingleStep() {
|
||||
|
@ -66,6 +66,9 @@ void MipsJit::DoState(PointerWrap &p)
|
||||
}
|
||||
}
|
||||
|
||||
void MipsJit::UpdateFCR31() {
|
||||
}
|
||||
|
||||
void MipsJit::FlushAll()
|
||||
{
|
||||
//gpr.FlushAll();
|
||||
|
@ -136,6 +136,7 @@ public:
|
||||
|
||||
void ClearCache() override;
|
||||
void InvalidateCacheAt(u32 em_address, int length = 4) override;
|
||||
void UpdateFCR31() override;
|
||||
|
||||
void EatPrefix() override { js.EatPrefix(); }
|
||||
|
||||
|
@ -528,6 +528,10 @@ namespace MIPSInt
|
||||
if (fs == 31) {
|
||||
currentMIPS->fcr31 = value & 0x0181FFFF;
|
||||
currentMIPS->fpcond = (value >> 23) & 1;
|
||||
if (MIPSComp::jit) {
|
||||
// In case of DISABLE, we need to tell jit we updated FCR31.
|
||||
MIPSComp::jit->UpdateFCR31();
|
||||
}
|
||||
} else {
|
||||
WARN_LOG_REPORT(CPU, "WriteFCR: Unexpected reg %d (value %08x)", fs, value);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -142,6 +142,9 @@ void Jit::DoState(PointerWrap &p) {
|
||||
CBreakPoints::SetSkipFirst(0);
|
||||
}
|
||||
|
||||
void Jit::UpdateFCR31() {
|
||||
}
|
||||
|
||||
void Jit::GetStateAndFlushAll(RegCacheState &state) {
|
||||
gpr.GetState(state.gpr);
|
||||
fpr.GetState(state.fpr);
|
||||
@ -195,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()
|
||||
@ -415,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)
|
||||
|
@ -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; }
|
||||
@ -171,6 +171,7 @@ public:
|
||||
blocks.InvalidateICache(em_address, length);
|
||||
}
|
||||
}
|
||||
void UpdateFCR31() override;
|
||||
|
||||
const u8 *GetDispatcher() const override {
|
||||
return dispatcher;
|
||||
@ -323,7 +324,6 @@ private:
|
||||
|
||||
const u8 *restoreRoundingMode;
|
||||
const u8 *applyRoundingMode;
|
||||
const u8 *updateRoundingMode;
|
||||
|
||||
const u8 *endOfPregeneratedCode;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user