Merge pull request #459 from unknownbrackets/jit-branch

Jit branch debugging
This commit is contained in:
Henrik Rydgård 2013-01-21 00:21:00 -08:00
commit 65203f3833
6 changed files with 147 additions and 44 deletions

View file

@ -113,10 +113,10 @@ const MIPSInstruction tableImmediate[64] = //xxxxxx .....
ENCODING(Cop2), //cop2
INVALID, //copU
INSTR("beql", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT), //L = likely
INSTR("bnel", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT),
INSTR("blezl", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT),
INSTR("bgtzl", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT),
INSTR("beql", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT|LIKELY), //L = likely
INSTR("bnel", &Jit::Comp_RelBranch, Dis_RelBranch2, Int_RelBranch, IS_CONDBRANCH|IN_RS|IN_RT|DELAYSLOT|LIKELY),
INSTR("blezl", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT|LIKELY),
INSTR("bgtzl", &Jit::Comp_RelBranch, Dis_RelBranch, Int_RelBranch, IS_CONDBRANCH|IN_RS|DELAYSLOT|LIKELY),
//24
{VFPU0},
{VFPU1},
@ -178,8 +178,8 @@ const MIPSInstruction tableSpecial[64] = /// 000000 ...... ...... .......... xxx
INSTR("srav", &Jit::Comp_ShiftType, Dis_VarShiftType, Int_ShiftType, OUT_RD|IN_RT|IN_RS_SHIFT),
//8
INSTR("jr", &Jit::Comp_JumpReg, Dis_JumpRegType, Int_JumpRegType,0),
INSTR("jalr", &Jit::Comp_JumpReg, Dis_JumpRegType, Int_JumpRegType,0),
INSTR("jr", &Jit::Comp_JumpReg, Dis_JumpRegType, Int_JumpRegType, DELAYSLOT),
INSTR("jalr", &Jit::Comp_JumpReg, Dis_JumpRegType, Int_JumpRegType, DELAYSLOT),
INSTR("movz", &Jit::Comp_RType3, Dis_RType3, Int_RType3, OUT_RD|IN_RS|IN_RT),
INSTR("movn", &Jit::Comp_RType3, Dis_RType3, Int_RType3, OUT_RD|IN_RS|IN_RT),
INSTR("syscall", &Jit::Comp_Syscall, Dis_Syscall, Int_Syscall,0),
@ -327,10 +327,10 @@ const MIPSInstruction tableSpecial3[64] =
const MIPSInstruction tableRegImm[32] =
{
INSTR("bltz", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
INSTR("bgez", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
INSTR("bltzl", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
INSTR("bgezl", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS),
INSTR("bltz", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|DELAYSLOT),
INSTR("bgez", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|DELAYSLOT),
INSTR("bltzl", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|DELAYSLOT|LIKELY),
INSTR("bgezl", &Jit::Comp_RelBranchRI, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|DELAYSLOT|LIKELY),
{-2},
{-2},
{-2},
@ -345,10 +345,10 @@ const MIPSInstruction tableRegImm[32] =
INSTR("tnei", &Jit::Comp_Generic, Dis_Generic, 0, 0),
{-2},
INSTR("bltzal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
INSTR("bgezal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
INSTR("bltzall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA), //L = likely
INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA),
INSTR("bltzal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA|DELAYSLOT),
INSTR("bgezal", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA|DELAYSLOT),
INSTR("bltzall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA|DELAYSLOT|LIKELY), //L = likely
INSTR("bgezall", &Jit::Comp_Generic, Dis_RelBranch, Int_RelBranchRI, IS_CONDBRANCH|IN_RS|OUT_RA|DELAYSLOT|LIKELY),
{-2},
{-2},
{-2},
@ -384,10 +384,10 @@ const MIPSInstruction tableCop2[32] =
const MIPSInstruction tableCop2BC2[4] =
{
INSTR("bvf", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
INSTR("bvt", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
INSTR("bvfl", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
INSTR("bvtl", &Jit::Comp_VBranch, Dis_VBranch,Int_VBranch,IS_CONDBRANCH),
INSTR("bvf", &Jit::Comp_VBranch, Dis_VBranch, Int_VBranch, IS_CONDBRANCH|DELAYSLOT),
INSTR("bvt", &Jit::Comp_VBranch, Dis_VBranch, Int_VBranch, IS_CONDBRANCH|DELAYSLOT),
INSTR("bvfl", &Jit::Comp_VBranch, Dis_VBranch, Int_VBranch, IS_CONDBRANCH|DELAYSLOT|LIKELY),
INSTR("bvtl", &Jit::Comp_VBranch, Dis_VBranch, Int_VBranch, IS_CONDBRANCH|DELAYSLOT|LIKELY),
};
const MIPSInstruction tableCop0[32] =
@ -467,10 +467,10 @@ const MIPSInstruction tableCop1[32] =
const MIPSInstruction tableCop1BC[32] =
{
{-1,"bc1f", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
{-1,"bc1t", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
{-1,"bc1fl", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
{-1,"bc1tl", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch,IS_CONDBRANCH|IN_FPUFLAG},
{-1,"bc1f", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch, IS_CONDBRANCH|IN_FPUFLAG|DELAYSLOT},
{-1,"bc1t", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch, IS_CONDBRANCH|IN_FPUFLAG|DELAYSLOT},
{-1,"bc1fl", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch, IS_CONDBRANCH|IN_FPUFLAG|DELAYSLOT|LIKELY},
{-1,"bc1tl", &Jit::Comp_FPUBranch, Dis_FPUBranch, Int_FPUBranch, IS_CONDBRANCH|IN_FPUFLAG|DELAYSLOT|LIKELY},
{-2},{-2},{-2},{-2},
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},
{-2},{-2},{-2},{-2},{-2},{-2},{-2},{-2},

View file

@ -22,6 +22,7 @@
#define IS_CONDBRANCH 0x100
#define IS_JUMP 0x200
#define IS_VFPU 0x80000000
#define LIKELY 0x80
#define UNCONDITIONAL 0x40
#define BAD_INSTRUCTION 0x20
#define DELAYSLOT 0x10

View file

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "../../HLE/HLE.h"
#include "../../Host.h"
#include "../MIPS.h"
#include "../MIPSCodeUtils.h"
@ -42,11 +43,86 @@ using namespace MIPSAnalyst;
// NOTE: Can't use CONDITIONAL_DISABLE in this file, branches are so special
// that they cannot be interpreted in the context of the Jit.
// But we can at least log and compare.
// #define DO_CONDITIONAL_LOG 1
#define DO_CONDITIONAL_LOG 0
#if DO_CONDITIONAL_LOG
#define CONDITIONAL_LOG BranchLog(op);
#define CONDITIONAL_LOG_EXIT(addr) BranchLogExit(op, addr, false);
#define CONDITIONAL_LOG_EXIT_EAX() BranchLogExit(op, 0, true);
#else
#define CONDITIONAL_LOG ;
#define CONDITIONAL_LOG_EXIT(addr) ;
#define CONDITIONAL_LOG_EXIT_EAX() ;
#endif
namespace MIPSComp
{
static u32 intBranchExit;
static u32 jitBranchExit;
static void JitBranchLog(u32 op, u32 pc)
{
currentMIPS->pc = pc;
currentMIPS->inDelaySlot = false;
MIPSInterpretFunc func = MIPSGetInterpretFunc(op);
u32 info = MIPSGetInfo(op);
func(op);
// Branch taken, use nextPC.
if (currentMIPS->inDelaySlot)
intBranchExit = currentMIPS->nextPC;
else
{
// Branch not taken, likely delay slot skipped.
if (info & LIKELY)
intBranchExit = currentMIPS->pc;
// Branch not taken, so increment over delay slot.
else
intBranchExit = currentMIPS->pc + 4;
}
currentMIPS->pc = pc;
currentMIPS->inDelaySlot = false;
}
static void JitBranchLogMismatch(u32 op, u32 pc)
{
char temp[256];
MIPSDisAsm(op, pc, temp, true);
ERROR_LOG(JIT, "Bad jump: %s - int:%08x jit:%08x", temp, intBranchExit, jitBranchExit);
Core_EnableStepping(true);
host->SetDebugMode(true);
}
void Jit::BranchLog(u32 op)
{
FlushAll();
ABI_CallFunctionCC(thunks.ProtectFunction((void *) &JitBranchLog, 2), op, js.compilerPC);
}
void Jit::BranchLogExit(u32 op, u32 dest, bool useEAX)
{
OpArg destArg = useEAX ? R(EAX) : Imm32(dest);
CMP(32, M((void *) &intBranchExit), destArg);
FixupBranch skip = J_CC(CC_E);
MOV(32, M((void *) &jitBranchExit), destArg);
ABI_CallFunctionCC(thunks.ProtectFunction((void *) &JitBranchLogMismatch, 2), op, js.compilerPC);
// Restore EAX, we probably ruined it.
if (useEAX)
MOV(32, R(EAX), M((void *) &jitBranchExit));
SetJumpTarget(skip);
}
void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
{
CONDITIONAL_LOG;
if (js.inDelaySlot) {
ERROR_LOG(JIT, "Branch in delay slot at %08x", js.compilerPC);
return;
@ -82,29 +158,31 @@ void Jit::BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely)
Gen::FixupBranch ptr;
if (!likely)
{
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
CompileDelaySlot(!delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
{
ptr = J_CC(cc, true);
CompileAt(js.compilerPC + 4);
FlushAll();
CompileDelaySlot(false);
}
js.inDelaySlot = false;
// Take the branch
CONDITIONAL_LOG_EXIT(targetAddr);
WriteExit(targetAddr, 0);
SetJumpTarget(ptr);
// Not taken
WriteExit(js.compilerPC+8, 1);
CONDITIONAL_LOG_EXIT(js.compilerPC + 8);
WriteExit(js.compilerPC + 8, 1);
js.compiling = false;
}
void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool likely)
{
CONDITIONAL_LOG;
if (js.inDelaySlot) {
ERROR_LOG(JIT, "Branch in delay slot at %08x", js.compilerPC);
return;
@ -130,23 +208,25 @@ void Jit::BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool likely)
js.inDelaySlot = true;
if (!likely)
{
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
CompileDelaySlot(!delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
{
ptr = J_CC(cc, true);
CompileAt(js.compilerPC + 4);
FlushAll();
CompileDelaySlot(false);
}
js.inDelaySlot = false;
// Take the branch
CONDITIONAL_LOG_EXIT(targetAddr);
WriteExit(targetAddr, 0);
SetJumpTarget(ptr);
// Not taken
CONDITIONAL_LOG_EXIT(js.compilerPC + 8);
WriteExit(js.compilerPC + 8, 1);
js.compiling = false;
}
@ -193,6 +273,7 @@ void Jit::Comp_RelBranchRI(u32 op)
// If likely is set, discard the branch slot if NOT taken.
void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely)
{
CONDITIONAL_LOG;
if (js.inDelaySlot) {
ERROR_LOG(JIT, "Branch in delay slot at %08x", js.compilerPC);
return;
@ -217,22 +298,23 @@ void Jit::BranchFPFlag(u32 op, Gen::CCFlags cc, bool likely)
js.inDelaySlot = true;
if (!likely)
{
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
CompileDelaySlot(!delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
{
ptr = J_CC(cc, true);
CompileAt(js.compilerPC + 4);
FlushAll();
CompileDelaySlot(false);
}
js.inDelaySlot = false;
// Take the branch
CONDITIONAL_LOG_EXIT(targetAddr);
WriteExit(targetAddr, 0);
SetJumpTarget(ptr);
// Not taken
CONDITIONAL_LOG_EXIT(js.compilerPC + 8);
WriteExit(js.compilerPC + 8, 1);
js.compiling = false;
@ -257,6 +339,7 @@ void Jit::Comp_FPUBranch(u32 op)
// If likely is set, discard the branch slot if NOT taken.
void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely)
{
CONDITIONAL_LOG;
if (js.inDelaySlot) {
ERROR_LOG(JIT, "Branch in delay slot at %08x", js.compilerPC);
return;
@ -285,22 +368,23 @@ void Jit::BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely)
js.inDelaySlot = true;
if (!likely)
{
CompileDelaySlot(js.compilerPC + 4, !delaySlotIsNice);
CompileDelaySlot(!delaySlotIsNice);
ptr = J_CC(cc, true);
}
else
{
ptr = J_CC(cc, true);
CompileAt(js.compilerPC + 4);
FlushAll();
CompileDelaySlot(false);
}
js.inDelaySlot = false;
// Take the branch
CONDITIONAL_LOG_EXIT(targetAddr);
WriteExit(targetAddr, 0);
SetJumpTarget(ptr);
// Not taken
CONDITIONAL_LOG_EXIT(js.compilerPC + 8);
WriteExit(js.compilerPC + 8, 1);
js.compiling = false;
@ -324,23 +408,25 @@ void Jit::Comp_VBranch(u32 op)
void Jit::Comp_Jump(u32 op)
{
CONDITIONAL_LOG;
if (js.inDelaySlot) {
ERROR_LOG(JIT, "Branch in delay slot at %08x", js.compilerPC);
return;
}
u32 off = ((op & 0x3FFFFFF) << 2);
u32 targetAddr = (js.compilerPC & 0xF0000000) | off;
CompileAt(js.compilerPC + 4);
FlushAll();
CompileDelaySlot(false);
switch (op >> 26)
{
case 2: //j
CONDITIONAL_LOG_EXIT(targetAddr);
WriteExit(targetAddr, 0);
break;
case 3: //jal
MOV(32, M(&mips_->r[MIPS_REG_RA]), Imm32(js.compilerPC + 8)); // Save return address
CONDITIONAL_LOG_EXIT(targetAddr);
WriteExit(targetAddr, 0);
break;
@ -355,6 +441,7 @@ static u32 savedPC;
void Jit::Comp_JumpReg(u32 op)
{
CONDITIONAL_LOG;
if (js.inDelaySlot) {
ERROR_LOG(JIT, "Branch in delay slot at %08x", js.compilerPC);
return;
@ -378,8 +465,7 @@ void Jit::Comp_JumpReg(u32 op)
gpr.BindToRegister(rs, true, false);
MOV(32, M(&currentMIPS->pc), gpr.R(rs)); // for syscalls in delay slot - could be avoided
MOV(32, M(&savedPC), gpr.R(rs));
CompileAt(js.compilerPC + 4);
FlushAll();
CompileDelaySlot(false);
if (!js.compiling)
{
@ -402,6 +488,7 @@ void Jit::Comp_JumpReg(u32 op)
break;
}
CONDITIONAL_LOG_EXIT_EAX();
WriteExitDestInEAX();
js.compiling = false;
}

View file

@ -122,8 +122,10 @@ void Jit::ClearCacheAt(u32 em_address)
ClearCache();
}
void Jit::CompileDelaySlot(u32 addr, bool saveFlags)
void Jit::CompileDelaySlot(bool saveFlags)
{
const u32 addr = js.compilerPC + 4;
// TODO: If we ever support conditional breakpoints, we need to handle the flags more carefully.
CheckJitBreakpoint(addr);

View file

@ -71,7 +71,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 CompileDelaySlot(bool saveFlags = false);
void CompileAt(u32 addr);
void Comp_RunBlock(u32 op);
@ -115,6 +115,8 @@ private:
void BranchVFPUFlag(u32 op, Gen::CCFlags cc, bool likely);
void BranchRSZeroComp(u32 op, Gen::CCFlags cc, bool likely);
void BranchRSRTComp(u32 op, Gen::CCFlags cc, bool likely);
void BranchLog(u32 op);
void BranchLogExit(u32 op, u32 dest, bool useEAX);
// Utilities to reduce duplicated code
void CompImmLogic(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &));

View file

@ -51,7 +51,7 @@ RegCache::RegCache() : emit(0), mips(0) {
void RegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats)
{
this->mips = mips;
this->mips = mips;
for (int i = 0; i < NUMXREGS; i++)
{
xregs[i].free = true;
@ -211,6 +211,10 @@ void RegCache::DiscardRegContentsIfCached(int preg)
void GPRRegCache::SetImmediate32(int preg, u32 immValue)
{
// ZERO is always zero. Let's just make sure.
if (preg == 0)
immValue = 0;
DiscardRegContentsIfCached(preg);
regs[preg].away = true;
regs[preg].location = Imm32(immValue);
@ -282,7 +286,13 @@ void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
xregs[xr].dirty = makeDirty || regs[i].location.IsImm();
OpArg newloc = ::Gen::R(xr);
if (doLoad)
emit->MOV(32, newloc, regs[i].location);
{
// Force ZERO to be 0.
if (i == 0)
emit->MOV(32, newloc, Imm32(0));
else
emit->MOV(32, newloc, regs[i].location);
}
for (int j = 0; j < 32; j++)
{
if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
@ -324,7 +334,8 @@ void GPRRegCache::StoreFromRegister(int i)
doStore = true;
}
OpArg newLoc = GetDefaultLocation(i);
if (doStore)
// But never store to ZERO.
if (doStore && i != 0)
emit->MOV(32, newLoc, regs[i].location);
regs[i].location = newLoc;
regs[i].away = false;