mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-26 01:40:24 +00:00
Merge pull request #439 from unknownbrackets/jit-minor2
Jit breakpoints (x86 only)
This commit is contained in:
commit
f93f348a46
@ -19,6 +19,7 @@
|
||||
#include "Breakpoints.h"
|
||||
#include "SymbolMap.h"
|
||||
#include "FixedSizeUnorderedSet.h"
|
||||
#include "../MIPS/JitCommon/JitCommon.h"
|
||||
#include <cstdio>
|
||||
|
||||
#define MAX_BREAKPOINTS 16
|
||||
@ -73,6 +74,7 @@ void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
|
||||
if (m_iBreakPoints[i].iAddress == _iAddress)
|
||||
{
|
||||
m_iBreakPoints.remove(m_iBreakPoints[i]);
|
||||
InvalidateJit(_iAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -81,6 +83,7 @@ void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
|
||||
void CBreakPoints::ClearAllBreakPoints()
|
||||
{
|
||||
m_iBreakPoints.clear();
|
||||
InvalidateJit();
|
||||
}
|
||||
|
||||
MemCheck *CBreakPoints::GetMemCheck(u32 address)
|
||||
@ -123,5 +126,20 @@ void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
|
||||
pt.iAddress = _iAddress;
|
||||
|
||||
m_iBreakPoints.insert(pt);
|
||||
InvalidateJit(_iAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPoints::InvalidateJit(u32 _iAddress)
|
||||
{
|
||||
// Don't want to clear cache while running, I think?
|
||||
if (MIPSComp::jit && coreState == CORE_STEPPING)
|
||||
MIPSComp::jit->ClearCacheAt(_iAddress);
|
||||
}
|
||||
|
||||
void CBreakPoints::InvalidateJit()
|
||||
{
|
||||
// Don't want to clear cache while running, I think?
|
||||
if (MIPSComp::jit && coreState == CORE_STEPPING)
|
||||
MIPSComp::jit->ClearCache();
|
||||
}
|
||||
|
@ -80,6 +80,9 @@ public:
|
||||
static void RemoveBreakPoint(u32 _iAddress);
|
||||
|
||||
static void ClearAllBreakPoints();
|
||||
|
||||
static void InvalidateJit(u32 _iAddress);
|
||||
static void InvalidateJit();
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,6 +76,12 @@ void Jit::ClearCache()
|
||||
GenerateFixedCode();
|
||||
}
|
||||
|
||||
void Jit::ClearCacheAt(u32 em_address)
|
||||
{
|
||||
// TODO: Properly.
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
void Jit::CompileAt(u32 addr)
|
||||
{
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
|
@ -89,6 +89,7 @@ public:
|
||||
ArmJitBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
void ClearCache();
|
||||
void ClearCacheAt(u32 em_address);
|
||||
|
||||
private:
|
||||
void GenerateFixedCode();
|
||||
|
@ -45,20 +45,6 @@ using namespace MIPSAnalyst;
|
||||
namespace MIPSComp
|
||||
{
|
||||
|
||||
#ifdef _M_IX86
|
||||
|
||||
#define SAVE_FLAGS PUSHF();
|
||||
#define LOAD_FLAGS POPF();
|
||||
|
||||
#else
|
||||
|
||||
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
|
||||
|
||||
void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
|
||||
{
|
||||
if (js.inDelaySlot) {
|
||||
@ -96,12 +82,7 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
|
||||
Gen::FixupBranch ptr;
|
||||
if (!likely)
|
||||
{
|
||||
if (!delaySlotIsNice)
|
||||
SAVE_FLAGS; // preserve flag around the delay slot!
|
||||
CompileAt(js.compilerPC + 4);
|
||||
FlushAll();
|
||||
if (!delaySlotIsNice)
|
||||
LOAD_FLAGS; // restore flag!
|
||||
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
|
||||
ptr = J_CC(cc, true);
|
||||
}
|
||||
else
|
||||
@ -149,12 +130,7 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool likely)
|
||||
js.inDelaySlot = true;
|
||||
if (!likely)
|
||||
{
|
||||
if (!delaySlotIsNice)
|
||||
SAVE_FLAGS; // preserve flag around the delay slot! Better hope the delay slot instruction doesn't need to fall back to interpreter...
|
||||
CompileAt(js.compilerPC + 4);
|
||||
FlushAll();
|
||||
if (!delaySlotIsNice)
|
||||
LOAD_FLAGS; // restore flag!
|
||||
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
|
||||
ptr = J_CC(cc, true);
|
||||
}
|
||||
else
|
||||
@ -241,12 +217,7 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely)
|
||||
js.inDelaySlot = true;
|
||||
if (!likely)
|
||||
{
|
||||
if (!delaySlotIsNice)
|
||||
SAVE_FLAGS; // preserve flag around the delay slot!
|
||||
CompileAt(js.compilerPC + 4);
|
||||
FlushAll();
|
||||
if (!delaySlotIsNice)
|
||||
LOAD_FLAGS; // restore flag!
|
||||
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
|
||||
ptr = J_CC(cc, true);
|
||||
}
|
||||
else
|
||||
@ -314,12 +285,7 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely)
|
||||
js.inDelaySlot = true;
|
||||
if (!likely)
|
||||
{
|
||||
if (!delaySlotIsNice)
|
||||
SAVE_FLAGS; // preserve flag around the delay slot!
|
||||
CompileAt(js.compilerPC + 4);
|
||||
FlushAll();
|
||||
if (!delaySlotIsNice)
|
||||
LOAD_FLAGS; // restore flag!
|
||||
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
|
||||
ptr = J_CC(cc, true);
|
||||
}
|
||||
else
|
||||
|
@ -25,9 +25,35 @@
|
||||
#include "RegCache.h"
|
||||
#include "Jit.h"
|
||||
|
||||
#include "../../Host.h"
|
||||
#include "../../Debugger/Breakpoints.h"
|
||||
|
||||
namespace MIPSComp
|
||||
{
|
||||
|
||||
#ifdef _M_IX86
|
||||
|
||||
#define SAVE_FLAGS PUSHF();
|
||||
#define LOAD_FLAGS POPF();
|
||||
|
||||
#else
|
||||
|
||||
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
|
||||
|
||||
void JitBreakpoint()
|
||||
{
|
||||
Core_EnableStepping(true);
|
||||
host->SetDebugMode(true);
|
||||
|
||||
if (CBreakPoints::IsTempBreakPoint(currentMIPS->pc))
|
||||
CBreakPoints::RemoveBreakPoint(currentMIPS->pc);
|
||||
}
|
||||
|
||||
Jit::Jit(MIPSState *mips) : blocks(mips), mips_(mips)
|
||||
{
|
||||
blocks.Init();
|
||||
@ -49,8 +75,31 @@ void Jit::ClearCache()
|
||||
ClearCodeSpace();
|
||||
}
|
||||
|
||||
void Jit::ClearCacheAt(u32 em_address)
|
||||
{
|
||||
// TODO: Properly.
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
void Jit::CompileDelaySlot(u32 addr, bool saveFlags)
|
||||
{
|
||||
// TODO: If we ever support conditional breakpoints, we need to handle the flags more carefully.
|
||||
CheckJitBreakpoint(addr);
|
||||
|
||||
if (saveFlags)
|
||||
SAVE_FLAGS; // preserve flag around the delay slot!
|
||||
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
MIPSCompileOp(op);
|
||||
|
||||
FlushAll();
|
||||
if (saveFlags)
|
||||
LOAD_FLAGS; // restore flag!
|
||||
}
|
||||
|
||||
void Jit::CompileAt(u32 addr)
|
||||
{
|
||||
CheckJitBreakpoint(addr);
|
||||
u32 op = Memory::Read_Instruction(addr);
|
||||
MIPSCompileOp(op);
|
||||
}
|
||||
@ -105,6 +154,9 @@ const u8 *Jit::DoJit(u32 em_address, JitBlock *b)
|
||||
u32 inst = Memory::Read_Instruction(js.compilerPC);
|
||||
js.downcountAmount += MIPSGetInstructionCycleEstimate(inst);
|
||||
|
||||
// Jit breakpoints are quite fast, so let's do them in release too.
|
||||
CheckJitBreakpoint(js.compilerPC);
|
||||
|
||||
MIPSCompileOp(inst);
|
||||
|
||||
js.compilerPC += 4;
|
||||
@ -171,4 +223,19 @@ void Jit::WriteSyscallExit()
|
||||
JMP(asm_.dispatcherCheckCoreState, true);
|
||||
}
|
||||
|
||||
bool Jit::CheckJitBreakpoint(u32 addr)
|
||||
{
|
||||
if (CBreakPoints::IsAddressBreakPoint(addr))
|
||||
{
|
||||
FlushAll();
|
||||
MOV(32, M(&mips_->pc), Imm32(js.compilerPC));
|
||||
CALL(&JitBreakpoint);
|
||||
WriteSyscallExit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -31,6 +31,9 @@
|
||||
namespace MIPSComp
|
||||
{
|
||||
|
||||
// This is called when Jit hits a breakpoint.
|
||||
void JitBreakpoint();
|
||||
|
||||
struct JitOptions
|
||||
{
|
||||
JitOptions()
|
||||
@ -67,6 +70,7 @@ public:
|
||||
void Compile(u32 em_address); // Compiles a block at current MIPS PC
|
||||
const u8 *DoJit(u32 em_address, JitBlock *b);
|
||||
|
||||
void CompileDelaySlot(u32 addr, bool saveFlags = false);
|
||||
void CompileAt(u32 addr);
|
||||
void Comp_RunBlock(u32 op);
|
||||
|
||||
@ -95,6 +99,7 @@ public:
|
||||
AsmRoutineManager &Asm() { return asm_; }
|
||||
|
||||
void ClearCache();
|
||||
void ClearCacheAt(u32 em_address);
|
||||
private:
|
||||
void FlushAll();
|
||||
|
||||
@ -102,6 +107,7 @@ private:
|
||||
void WriteExitDestInEAX();
|
||||
// void WriteRfiExitDestInEAX();
|
||||
void WriteSyscallExit();
|
||||
bool CheckJitBreakpoint(u32 addr);
|
||||
|
||||
// Utility compilation functions
|
||||
void BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely);
|
||||
|
@ -62,7 +62,7 @@ using namespace Gen;
|
||||
|
||||
bool JitBlock::ContainsAddress(u32 em_address)
|
||||
{
|
||||
// WARNING - THIS DOES NOT WORK WITH INLINING ENABLED.
|
||||
// WARNING - THIS DOES NOT WORK WITH JIT INLINING ENABLED.
|
||||
return (em_address >= originalAddress && em_address < originalAddress + 4 * originalSize);
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ public:
|
||||
int GetBlockNumberFromStartAddress(u32 em_address);
|
||||
|
||||
// slower, but can get numbers from within blocks, not just the first instruction.
|
||||
// WARNING! WILL NOT WORK WITH INLINING ENABLED (not yet a feature but will be soon)
|
||||
// WARNING! WILL NOT WORK WITH JIT INLINING ENABLED (not yet a feature but will be soon)
|
||||
// Returns a list of block numbers - only one block can start at a particular address, but they CAN overlap.
|
||||
// This one is slow so should only be used for one-shots from the debugger UI, not for anything during runtime.
|
||||
void GetBlockNumbersFromAddress(u32 em_address, std::vector<int> *block_numbers);
|
||||
@ -126,7 +126,7 @@ public:
|
||||
u32 GetOriginalFirstOp(int block_num);
|
||||
CompiledCode GetCompiledCodeFromBlock(int block_num);
|
||||
|
||||
// DOES NOT WORK CORRECTLY WITH INLINING
|
||||
// DOES NOT WORK CORRECTLY WITH JIT INLINING
|
||||
void InvalidateICache(u32 address, const u32 length);
|
||||
void DestroyBlock(int block_num, bool invalidate);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user