diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index ab3058bd8d..a7f7bd967b 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -96,6 +96,20 @@ void STACKALIGN CheckGatherPipe() // move back the spill bytes memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); + + // Profile where the FIFO writes are occurring. + if (jit && PC != 0 && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) + { + // Log only stores, fp stores and ps stores, filtering out other instructions arrived via optimizeGatherPipe + int type = GetOpInfo(Memory::ReadUnchecked_U32(PC))->type; + if (type == OPTYPE_STORE || type == OPTYPE_STOREFP || (type == OPTYPE_PS && !strcmp(GetOpInfo(Memory::ReadUnchecked_U32(PC))->opname, "psq_st"))) + { + jit->js.fifoWriteAddresses.insert(PC); + + // Invalidate the JIT block so that it gets recompiled with the external exception check included. + jit->GetBlockCache()->InvalidateICache(PC, 4); + } + } } } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 3995fc9299..1ad545ec0a 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -611,6 +611,30 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc js.firstFPInstructionFound = true; } + // Add an external exception check if the instruction writes to the FIFO. + if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end()) + { + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT)); + FixupBranch clearInt = J_CC(CC_NZ, true); + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = J_CC(CC_Z, true); + TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = J_CC(CC_Z, true); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); + FixupBranch noCPInt = J_CC(CC_Z, true); + + MOV(32, M(&PC), Imm32(ops[i].address)); + WriteExternalExceptionExit(); + + SetJumpTarget(noCPInt); + SetJumpTarget(noExtIntEnable); + SetJumpTarget(noExtException); + SetJumpTarget(clearInt); + } + if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) { gpr.Flush(FLUSH_ALL); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index fdec5b747d..2a830a03cf 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -1269,7 +1269,7 @@ static const unsigned alwaysUsedList[] = { Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck, - DSIExceptionCheck, ISIException, BreakPointCheck, + DSIExceptionCheck, ISIException, ExtExceptionCheck, BreakPointCheck, Int3, Tramp, Nop }; static const unsigned extra8RegList[] = { diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index 5bc7da9d8d..7fabd946f9 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -168,7 +168,7 @@ enum Opcode { // used for exception checking, at least until someone // has a better idea of integrating it FPExceptionCheck, DSIExceptionCheck, - ISIException, BreakPointCheck, + ISIException, ExtExceptionCheck, BreakPointCheck, // "Opcode" representing a register too far away to // reference directly; this is a size optimization Tramp, @@ -411,6 +411,9 @@ public: InstLoc EmitISIException(InstLoc dest) { return EmitUOp(ISIException, dest); } + InstLoc EmitExtExceptionCheck(InstLoc pc) { + return EmitUOp(ExtExceptionCheck, pc); + } InstLoc EmitBreakPointCheck(InstLoc pc) { return EmitUOp(BreakPointCheck, pc); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 88d815e33d..7c12d613a3 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -762,6 +762,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak case FPExceptionCheck: case DSIExceptionCheck: case ISIException: + case ExtExceptionCheck: case BreakPointCheck: case Int3: case Tramp: @@ -1940,6 +1941,27 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->WriteExceptionExit(); break; } + case ExtExceptionCheck: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT)); + FixupBranch clearInt = Jit->J_CC(CC_NZ); + Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); + FixupBranch noCPInt = Jit->J_CC(CC_Z); + + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->WriteExceptionExit(); + + Jit->SetJumpTarget(noCPInt); + Jit->SetJumpTarget(noExtIntEnable); + Jit->SetJumpTarget(noExtException); + Jit->SetJumpTarget(clearInt); + break; + } case BreakPointCheck: { unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp index f10df33d99..a60becfad9 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp @@ -679,6 +679,11 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address)); } + if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) + { + ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } + if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) { ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address)); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h index 9b8c67474c..158171be0f 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h @@ -74,6 +74,8 @@ protected: u8* rewriteStart; JitBlock *curBlock; + + std::set fifoWriteAddresses; }; public: