diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 81d126ba3b..77905ca8ae 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -614,6 +614,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc const GekkoOPInfo *opinfo = ops[i].opinfo; js.downcountAmount += opinfo->numCycles; js.fastmemLoadStore = NULL; + js.fixupExceptionHandler = false; if (i == (code_block.m_num_instructions - 1)) { @@ -767,7 +768,9 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { // If we have a fastmem loadstore, we can omit the exception check and let fastmem handle it. FixupBranch memException; - if (!js.fastmemLoadStore) + _assert_msg_(DYNA_REC, !(js.fastmemLoadStore && js.fixupExceptionHandler), + "Fastmem loadstores shouldn't have exception handler fixups (PC=%x)!", ops[i].address); + if (!js.fastmemLoadStore && !js.fixupExceptionHandler) { TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_DSI)); memException = J_CC(CC_NZ, true); @@ -777,7 +780,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (!js.fastmemLoadStore) { exceptionHandlerAtLoc[js.fastmemLoadStore] = NULL; - SetJumpTarget(memException); + SetJumpTarget(js.fixupExceptionHandler ? js.exceptionHandler : memException); } else { diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index ae6b50f9cf..1edd6b3868 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -258,17 +258,15 @@ void Jit64::lXXx(UGeckoInstruction inst) if (update && storeAddress) { - MEMCHECK_START + MemoryExceptionCheck(); MOV(32, gpr.R(a), opAddress); - MEMCHECK_END } // TODO: support no-swap in SafeLoadToReg instead if (byte_reversed) { - MEMCHECK_START + MemoryExceptionCheck(); BSWAP(accessSize, gpr.RX(d)); - MEMCHECK_END } gpr.UnlockAll(); @@ -372,9 +370,8 @@ void Jit64::stX(UGeckoInstruction inst) else { gpr.KillImmediate(a, true, true); - MEMCHECK_START + MemoryExceptionCheck(); ADD(32, gpr.R(a), Imm32((u32)offset)); - MEMCHECK_END } } } @@ -404,9 +401,8 @@ void Jit64::stX(UGeckoInstruction inst) if (update) { - MEMCHECK_START + MemoryExceptionCheck(); ADD(32, gpr.R(a), Imm32((u32)offset)); - MEMCHECK_END } } gpr.UnlockAll(); @@ -485,9 +481,8 @@ void Jit64::stXx(UGeckoInstruction inst) if (update) { - MEMCHECK_START + MemoryExceptionCheck(); MOV(32, gpr.R(a), R(RSCRATCH2)); - MEMCHECK_END; } gpr.UnlockAll(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp index 061759857c..4cfbc3b756 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp @@ -72,7 +72,7 @@ void Jit64::lfXXX(UGeckoInstruction inst) registersInUse[RSCRATCH2] = true; SafeLoadToReg(RSCRATCH, addr, single ? 32 : 64, offset, registersInUse, false); - MEMCHECK_START + MemoryExceptionCheck(); if (single) { ConvertSingleToDouble(fpr.RX(d), RSCRATCH, true); @@ -84,7 +84,6 @@ void Jit64::lfXXX(UGeckoInstruction inst) } if (update && js.memcheck) MOV(32, gpr.R(a), addr); - MEMCHECK_END fpr.UnlockAll(); gpr.UnlockAll(); } @@ -141,9 +140,8 @@ void Jit64::stfXXX(UGeckoInstruction inst) else { gpr.KillImmediate(a, true, true); - MEMCHECK_START + MemoryExceptionCheck(); ADD(32, gpr.R(a), Imm32((u32)imm)); - MEMCHECK_END } } fpr.UnlockAll(); @@ -187,9 +185,8 @@ void Jit64::stfXXX(UGeckoInstruction inst) if (update) { - MEMCHECK_START + MemoryExceptionCheck(); MOV(32, gpr.R(a), R(RSCRATCH2)); - MEMCHECK_END } fpr.UnlockAll(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp index 160547bf9a..b6dac78f86 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -78,12 +78,11 @@ void Jit64::psq_stXX(UGeckoInstruction inst) if (update && js.memcheck) { - MEMCHECK_START + MemoryExceptionCheck(); if (indexed) ADD(32, gpr.R(a), gpr.R(b)); else ADD(32, gpr.R(a), Imm32((u32)offset)); - MEMCHECK_END } gpr.UnlockAll(); gpr.UnlockAllX(); @@ -137,7 +136,7 @@ void Jit64::psq_lXX(UGeckoInstruction inst) CALLptr(MScaled(RSCRATCH, SCALE_8, (u32)(u64)(&asm_routines.pairedLoadQuantized[w * 8]))); - MEMCHECK_START + MemoryExceptionCheck(); CVTPS2PD(fpr.RX(s), R(XMM0)); if (update && js.memcheck) { @@ -146,7 +145,6 @@ void Jit64::psq_lXX(UGeckoInstruction inst) else ADD(32, gpr.R(a), Imm32((u32)offset)); } - MEMCHECK_END gpr.UnlockAll(); gpr.UnlockAllX(); diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 99d89e548e..5a526f8f48 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -73,7 +73,12 @@ protected: int downcountAmount; u32 numLoadStoreInst; u32 numFloatingPointInst; + // If this is set, we need to generate an exception handler for the fastmem load. u8* fastmemLoadStore; + // If this is set, a load or store already prepared a jump to the exception handler for us, + // so just fixup that branch instead of testing for a DSI again. + bool fixupExceptionHandler; + Gen::FixupBranch exceptionHandler; bool firstFPInstructionFound; bool isLastInstruction; diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp index 35a74201ae..fef3e90677 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp @@ -13,6 +13,16 @@ using namespace Gen; +void EmuCodeBlock::MemoryExceptionCheck() +{ + if (jit->js.memcheck && !jit->js.fastmemLoadStore && !jit->js.fixupExceptionHandler) + { + TEST(32, PPCSTATE(Exceptions), Gen::Imm32(EXCEPTION_DSI)); + jit->js.exceptionHandler = J_CC(Gen::CC_NZ, true); + jit->js.fixupExceptionHandler = true; + } +} + void EmuCodeBlock::LoadAndSwap(int size, Gen::X64Reg dst, const Gen::OpArg& src) { if (cpu_info.bMOVBE) @@ -350,7 +360,7 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, } ABI_PopRegistersAndAdjustStack(registersInUse, 0); - MEMCHECK_START + MemoryExceptionCheck(); if (signExtend && accessSize < 32) { // Need to sign extend values coming from the Read_U* functions. @@ -360,7 +370,6 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, { MOVZX(64, accessSize, reg_value, R(ABI_RETURN)); } - MEMCHECK_END } } else @@ -400,7 +409,7 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, } ABI_PopRegistersAndAdjustStack(registersInUse, rsp_alignment); - MEMCHECK_START + MemoryExceptionCheck(); if (signExtend && accessSize < 32) { // Need to sign extend values coming from the Read_U* functions. @@ -410,7 +419,6 @@ void EmuCodeBlock::SafeLoadToReg(X64Reg reg_value, const Gen::OpArg & opAddress, { MOVZX(64, accessSize, reg_value, R(ABI_RETURN)); } - MEMCHECK_END if (farcode.Enabled()) { diff --git a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h index 322425b9d4..6681808aa7 100644 --- a/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitCommon/Jit_Util.h @@ -12,16 +12,6 @@ namespace MMIO { class Mapping; } -#define MEMCHECK_START \ - Gen::FixupBranch memException; \ - if (jit->js.memcheck && !jit->js.fastmemLoadStore) \ - { TEST(32, PPCSTATE(Exceptions), Gen::Imm32(EXCEPTION_DSI)); \ - memException = J_CC(Gen::CC_NZ, true); } - -#define MEMCHECK_END \ - if (jit->js.memcheck && !jit->js.fastmemLoadStore) \ - SetJumpTarget(memException); - // We offset by 0x80 because the range of one byte memory offsets is // -0x80..0x7f. #define PPCSTATE(x) MDisp(RPPCSTATE, \ @@ -59,6 +49,8 @@ public: FarCodeCache farcode; u8* nearcode; // Backed up when we switch to far code. + void MemoryExceptionCheck(); + // Simple functions to switch between near and far code emitting void SwitchToFarCode() {