diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 2c73633cc..1d769ab27 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -48,20 +48,8 @@ namespace MIPSComp { using namespace Gen; -#ifdef _M_IX86 - -#define SAVE_FLAGS PUSHF(); -#define LOAD_FLAGS POPF(); - -#elif defined(_M_X64) - static u64 saved_flags; -#define SAVE_FLAGS {PUSHF(); POP(64, R(EAX)); MOV(64, M(&saved_flags), R(EAX));} -#define LOAD_FLAGS {MOV(64, R(EAX), M(&saved_flags)); PUSH(64, R(EAX)); POPF();} - -#endif - const bool USE_JIT_MISSMAP = false; static std::map notJitOps; @@ -138,8 +126,7 @@ Jit::Jit(MIPSState *mips) Jit::~Jit() { } -void Jit::DoState(PointerWrap &p) -{ +void Jit::DoState(PointerWrap &p) { auto s = p.Section("Jit", 1, 2); if (!s) return; @@ -158,8 +145,7 @@ void Jit::DoState(PointerWrap &p) } // This is here so the savestate matches between jit and non-jit. -void Jit::DoDummyState(PointerWrap &p) -{ +void Jit::DoDummyState(PointerWrap &p) { auto s = p.Section("Jit", 1, 2); if (!s) return; @@ -173,49 +159,41 @@ void Jit::DoDummyState(PointerWrap &p) } -void Jit::GetStateAndFlushAll(RegCacheState &state) -{ +void Jit::GetStateAndFlushAll(RegCacheState &state) { gpr.GetState(state.gpr); fpr.GetState(state.fpr); FlushAll(); } -void Jit::RestoreState(const RegCacheState& state) -{ +void Jit::RestoreState(const RegCacheState& state) { gpr.RestoreState(state.gpr); fpr.RestoreState(state.fpr); } -void Jit::FlushAll() -{ +void Jit::FlushAll() { gpr.Flush(); fpr.Flush(); FlushPrefixV(); } -void Jit::FlushPrefixV() -{ - if ((js.prefixSFlag & JitState::PREFIX_DIRTY) != 0) - { +void Jit::FlushPrefixV() { + if ((js.prefixSFlag & JitState::PREFIX_DIRTY) != 0) { MOV(32, M(&mips_->vfpuCtrl[VFPU_CTRL_SPREFIX]), Imm32(js.prefixS)); js.prefixSFlag = (JitState::PrefixState) (js.prefixSFlag & ~JitState::PREFIX_DIRTY); } - if ((js.prefixTFlag & JitState::PREFIX_DIRTY) != 0) - { + if ((js.prefixTFlag & JitState::PREFIX_DIRTY) != 0) { MOV(32, M(&mips_->vfpuCtrl[VFPU_CTRL_TPREFIX]), Imm32(js.prefixT)); js.prefixTFlag = (JitState::PrefixState) (js.prefixTFlag & ~JitState::PREFIX_DIRTY); } - if ((js.prefixDFlag & JitState::PREFIX_DIRTY) != 0) - { + if ((js.prefixDFlag & JitState::PREFIX_DIRTY) != 0) { MOV(32, M(&mips_->vfpuCtrl[VFPU_CTRL_DPREFIX]), Imm32(js.prefixD)); js.prefixDFlag = (JitState::PrefixState) (js.prefixDFlag & ~JitState::PREFIX_DIRTY); } } -void Jit::WriteDowncount(int offset) -{ +void Jit::WriteDowncount(int offset) { const int downcount = js.downcountAmount + offset; SUB(32, M(&mips_->downcount), downcount > 127 ? Imm32(downcount) : Imm8(downcount)); } @@ -245,32 +223,46 @@ void Jit::ClearCache() GenerateFixedCode(jo); } -void Jit::CompileDelaySlot(int flags, RegCacheState *state) -{ +void Jit::SaveFlags() { + PUSHF(); +#if defined(_M_X64) + // On X64, the above misaligns the stack. However there might be a cheaper solution than this. + POP(64, R(EAX)); + MOV(64, M(&saved_flags), R(EAX)); +#endif +} + +void Jit::LoadFlags() { +#if defined(_M_X64) + MOV(64, R(EAX), M(&saved_flags)); + PUSH(64, R(EAX)); +#endif + POPF(); +} + +void Jit::CompileDelaySlot(int flags, RegCacheState *state) { // Need to offset the downcount which was already incremented for the branch + delay slot. CheckJitBreakpoint(GetCompilerPC() + 4, -2); if (flags & DELAYSLOT_SAFE) - SAVE_FLAGS; // preserve flag around the delay slot! + SaveFlags(); // preserve flag around the delay slot! js.inDelaySlot = true; MIPSOpcode op = GetOffsetInstruction(1); MIPSCompileOp(op, this); js.inDelaySlot = false; - if (flags & DELAYSLOT_FLUSH) - { + if (flags & DELAYSLOT_FLUSH) { if (state != NULL) GetStateAndFlushAll(*state); else FlushAll(); } if (flags & DELAYSLOT_SAFE) - LOAD_FLAGS; // restore flag! + LoadFlags(); // restore flag! } -void Jit::EatInstruction(MIPSOpcode op) -{ +void Jit::EatInstruction(MIPSOpcode op) { MIPSInfo info = MIPSGetInfo(op); if (info & DELAYSLOT) { ERROR_LOG_REPORT_ONCE(ateDelaySlot, JIT, "Ate a branch op."); @@ -285,8 +277,7 @@ void Jit::EatInstruction(MIPSOpcode op) js.downcountAmount += MIPSGetInstructionCycleEstimate(op); } -void Jit::Compile(u32 em_address) -{ +void Jit::Compile(u32 em_address) { PROFILE_THIS_SCOPE("jitc"); if (GetSpaceLeft() < 0x10000 || blocks.IsFull()) { ClearCache(); @@ -327,8 +318,7 @@ void Jit::Compile(u32 em_address) } } -void Jit::RunLoopUntil(u64 globalticks) -{ +void Jit::RunLoopUntil(u64 globalticks) { PROFILE_THIS_SCOPE("jit"); ((void (*)())enterDispatcher)(); } @@ -569,8 +559,7 @@ bool Jit::ReplaceJalTo(u32 dest) { return true; } -void Jit::Comp_ReplacementFunc(MIPSOpcode op) -{ +void Jit::Comp_ReplacementFunc(MIPSOpcode op) { // We get here if we execute the first instruction of a replaced function. This means // that we do need to return to RA. @@ -646,8 +635,7 @@ void Jit::Comp_ReplacementFunc(MIPSOpcode op) } } -void Jit::Comp_Generic(MIPSOpcode op) -{ +void Jit::Comp_Generic(MIPSOpcode op) { FlushAll(); MIPSInterpretFunc func = MIPSGetInterpretFunc(op); _dbg_assert_msg_(JIT, (MIPSGetInfo(op) & DELAYSLOT) == 0, "Cannot use interpreter for branch ops."); @@ -675,16 +663,14 @@ void Jit::Comp_Generic(MIPSOpcode op) } } -void Jit::WriteExit(u32 destination, int exit_num) -{ +void Jit::WriteExit(u32 destination, int exit_num) { _dbg_assert_msg_(JIT, exit_num < MAX_JIT_BLOCK_EXITS, "Expected a valid exit_num"); if (!Memory::IsValidAddress(destination)) { ERROR_LOG_REPORT(JIT, "Trying to write block exit to illegal destination %08x: pc = %08x", destination, currentMIPS->pc); } // If we need to verify coreState and rewind, we may not jump yet. - if (js.afterOp & (JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE)) - { + if (js.afterOp & (JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE)) { // CORE_RUNNING is <= CORE_NEXTFRAME. CMP(32, M(&coreState), Imm32(CORE_NEXTFRAME)); FixupBranch skipCheck = J_CC(CC_LE); @@ -721,8 +707,7 @@ void Jit::WriteExit(u32 destination, int exit_num) } } -void Jit::WriteExitDestInReg(X64Reg reg) -{ +void Jit::WriteExitDestInReg(X64Reg reg) { // If we need to verify coreState and rewind, we may not jump yet. if (js.afterOp & (JitState::AFTER_CORE_STATE | JitState::AFTER_REWIND_PC_BAD_STATE)) { @@ -738,8 +723,7 @@ void Jit::WriteExitDestInReg(X64Reg reg) WriteDowncount(); // Validate the jump to avoid a crash? - if (!g_Config.bFastMemory) - { + if (!g_Config.bFastMemory) { CMP(32, R(reg), Imm32(PSP_GetKernelMemoryBase())); FixupBranch tooLow = J_CC(CC_B); CMP(32, R(reg), Imm32(PSP_GetUserMemoryEnd())); @@ -757,8 +741,7 @@ void Jit::WriteExitDestInReg(X64Reg reg) ABI_CallFunctionA((const void *)&Memory::GetPointer, R(reg)); // If we're ignoring, coreState didn't trip - so trip it now. - if (g_Config.bIgnoreBadMemAccess) - { + if (g_Config.bIgnoreBadMemAccess) { CMP(32, R(EAX), Imm32(0)); FixupBranch skip = J_CC(CC_NE); ABI_CallFunctionA((const void *)&Core_UpdateState, Imm32(CORE_ERROR)); @@ -767,18 +750,15 @@ void Jit::WriteExitDestInReg(X64Reg reg) SUB(32, M(&mips_->downcount), Imm8(0)); JMP(dispatcherCheckCoreState, true); - } - else if (reg == EAX) - { + } else if (reg == EAX) { J_CC(CC_NS, dispatcherInEAXNoCheck, true); JMP(dispatcher, true); - } - else + } else { JMP(dispatcher, true); + } } -void Jit::WriteSyscallExit() -{ +void Jit::WriteSyscallExit() { WriteDowncount(); if (js.afterOp & JitState::AFTER_MEMCHECK_CLEANUP) { RestoreRoundingMode(); @@ -788,11 +768,9 @@ void Jit::WriteSyscallExit() JMP(dispatcherCheckCoreState, true); } -bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset) -{ - if (CBreakPoints::IsAddressBreakPoint(addr)) - { - SAVE_FLAGS; +bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset) { + if (CBreakPoints::IsAddressBreakPoint(addr)) { + SaveFlags(); FlushAll(); MOV(32, M(&mips_->pc), Imm32(GetCompilerPC())); RestoreRoundingMode(); @@ -804,41 +782,36 @@ bool Jit::CheckJitBreakpoint(u32 addr, int downcountOffset) WriteDowncount(downcountOffset); ApplyRoundingMode(); // Just to fix the stack. - LOAD_FLAGS; + LoadFlags(); JMP(dispatcherCheckCoreState, true); SetJumpTarget(skip); ApplyRoundingMode(); - LOAD_FLAGS; - + LoadFlags(); return true; } return false; } -void Jit::CallProtectedFunction(const void *func, const OpArg &arg1) -{ +void Jit::CallProtectedFunction(const void *func, const OpArg &arg1) { // We don't regcache RCX, so the below is safe (and also faster, maybe branch prediction?) ABI_CallFunctionA(thunks.ProtectFunction(func, 1), arg1); } -void Jit::CallProtectedFunction(const void *func, const OpArg &arg1, const OpArg &arg2) -{ +void Jit::CallProtectedFunction(const void *func, const OpArg &arg1, const OpArg &arg2) { // We don't regcache RCX/RDX, so the below is safe (and also faster, maybe branch prediction?) ABI_CallFunctionAA(thunks.ProtectFunction(func, 2), arg1, arg2); } -void Jit::CallProtectedFunction(const void *func, const u32 arg1, const u32 arg2, const u32 arg3) -{ +void Jit::CallProtectedFunction(const void *func, const u32 arg1, const u32 arg2, const u32 arg3) { // On x64, we need to save R8, which is caller saved. thunks.Enter(this); ABI_CallFunctionCCC(func, arg1, arg2, arg3); thunks.Leave(this); } -void Jit::CallProtectedFunction(const void *func, const OpArg &arg1, const u32 arg2, const u32 arg3) -{ +void Jit::CallProtectedFunction(const void *func, const OpArg &arg1, const u32 arg2, const u32 arg3) { // On x64, we need to save R8, which is caller saved. thunks.Enter(this); ABI_CallFunctionACC(func, arg1, arg2, arg3); diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 72ca6d87b..de8ef4d8f 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -15,6 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// TODO: Implement https://github.com/dolphin-emu/dolphin/pull/1025/commits/b597ec3e081a289d9ac782586617a876535183d6 . + #pragma once #include "Common/CommonTypes.h" @@ -36,7 +39,6 @@ namespace MIPSComp { // This is called when Jit hits a breakpoint. Returns 1 when hit. u32 JitBreakpoint(); -// TODO: Hmm, humongous. struct RegCacheState { GPRRegCacheState gpr; FPURegCacheState fpr; @@ -292,6 +294,8 @@ private: } return true; } + void SaveFlags(); + void LoadFlags(); JitBlockCache blocks; JitOptions jo;