Implemented correct idle skipping in JIT IL
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3300 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
71e895ddf7
commit
4c19fa7e5f
|
@ -136,8 +136,7 @@
|
|||
(Core::GetStartupParameter().bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
{
|
||||
// TODO(LinesPrower):
|
||||
// - Fix idle skipping in JITIL!
|
||||
// TODO(LinesPrower):
|
||||
// - Rewrite this!
|
||||
// It seems to be ugly and unefficient, but I don't know JIT stuff enough to make it right
|
||||
// It only demonstrates the idea
|
||||
|
@ -164,8 +163,8 @@
|
|||
ABI_CallFunctionC((void *)&PowerPC::OnIdle, PowerPC::ppcState.gpr[a] + (s32)(s16)inst.SIMM_16);
|
||||
|
||||
// ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0
|
||||
//MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC + 12));
|
||||
JMP(asm_routines.testExceptions, true);
|
||||
//MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC));
|
||||
JMP(asm_routines.testExceptions, true);
|
||||
|
||||
SetJumpTarget(noIdle);
|
||||
|
||||
|
|
|
@ -514,6 +514,14 @@ InstLoc IRBuilder::FoldBranchCond(InstLoc Op1, InstLoc Op2) {
|
|||
return EmitBiOp(BranchCond, Op1, Op2);
|
||||
}
|
||||
|
||||
InstLoc IRBuilder::FoldIdleBranch(InstLoc Op1, InstLoc Op2) {
|
||||
return EmitBiOp(
|
||||
IdleBranch,
|
||||
EmitICmpEq(getOp1(getOp1(Op1)),
|
||||
getOp2(getOp1(Op1))), Op2
|
||||
);
|
||||
}
|
||||
|
||||
InstLoc IRBuilder::FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2) {
|
||||
if (isImm(*Op1)) {
|
||||
if (isImm(*Op2)) {
|
||||
|
@ -659,6 +667,7 @@ InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned
|
|||
case Shrl: return FoldShrl(Op1, Op2);
|
||||
case Rol: return FoldRol(Op1, Op2);
|
||||
case BranchCond: return FoldBranchCond(Op1, Op2);
|
||||
case IdleBranch: return FoldIdleBranch(Op1, Op2);
|
||||
case ICmpEq: case ICmpNe:
|
||||
case ICmpUgt: case ICmpUlt: case ICmpUge: case ICmpUle:
|
||||
case ICmpSgt: case ICmpSlt: case ICmpSge: case ICmpSle:
|
||||
|
@ -1310,9 +1319,8 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
|
|||
case InterpreterFallback:
|
||||
case SystemCall:
|
||||
case RFIExit:
|
||||
case InterpreterBranch:
|
||||
case IdleLoop:
|
||||
case ShortIdleLoop:
|
||||
case InterpreterBranch:
|
||||
case ShortIdleLoop:
|
||||
case Tramp:
|
||||
// No liveness effects
|
||||
break;
|
||||
|
@ -1419,6 +1427,9 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
|
|||
if (!isImm(*getOp1(I)))
|
||||
regMarkUse(RI, I, getOp1(I), 1);
|
||||
break;
|
||||
case IdleBranch:
|
||||
regMarkUse(RI, I, getOp1(getOp1(I)), 1);
|
||||
break;
|
||||
case BranchCond: {
|
||||
if (isICmp(*getOp1(I)) &&
|
||||
isImm(*getOp2(getOp1(I)))) {
|
||||
|
@ -2112,6 +2123,26 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
|
|||
case BlockStart:
|
||||
case BlockEnd:
|
||||
break;
|
||||
|
||||
case IdleBranch: {
|
||||
Jit->CMP(32, regLocForInst(RI, getOp1(getOp1(I))),
|
||||
Imm32(RI.Build->GetImmValue(getOp2(getOp1(I)))));
|
||||
FixupBranch cont = Jit->J_CC(CC_NE);
|
||||
|
||||
RI.Jit->Cleanup(); // is it needed?
|
||||
Jit->ABI_CallFunction((void *)&PowerPC::OnIdleIL);
|
||||
|
||||
Jit->MOV(32, M(&PC), Imm32(ibuild->GetImmValue( getOp2(I) )));
|
||||
Jit->JMP(asm_routines.testExceptions, true);
|
||||
|
||||
Jit->SetJumpTarget(cont);
|
||||
if (RI.IInfo[I - RI.FirstI] & 4)
|
||||
regClearInst(RI, getOp1(getOp1(I)));
|
||||
if (RI.IInfo[I - RI.FirstI] & 8)
|
||||
regClearInst(RI, getOp2(I));
|
||||
break;
|
||||
}
|
||||
|
||||
case BranchCond: {
|
||||
if (isICmp(*getOp1(I)) &&
|
||||
isImm(*getOp2(getOp1(I)))) {
|
||||
|
@ -2151,15 +2182,7 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
|
|||
regWriteExit(RI, getOp1(I));
|
||||
regNormalRegClear(RI, I);
|
||||
break;
|
||||
}
|
||||
case IdleLoop: {
|
||||
unsigned IdleParam = ibuild->GetImmValue(getOp1(I));
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp2(I));
|
||||
Jit->ABI_CallFunctionC((void *)&PowerPC::OnIdle, IdleParam);
|
||||
Jit->MOV(32, M(&PC), Imm32(InstLoc + 12));
|
||||
Jit->JMP(asm_routines.testExceptions, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ShortIdleLoop: {
|
||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
||||
Jit->ABI_CallFunction((void *)&CoreTiming::Idle);
|
||||
|
|
|
@ -156,7 +156,9 @@ namespace IREmitter {
|
|||
SystemCall,
|
||||
RFIExit,
|
||||
InterpreterBranch,
|
||||
IdleLoop, // The "usual" idle loop, load+compare+branch
|
||||
|
||||
//IdleLoop, // The "usual" idle loop, load+compare+branch
|
||||
IdleBranch, // branch operation belonging to idle loop
|
||||
ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
|
||||
// just a branch
|
||||
|
||||
|
@ -220,6 +222,7 @@ namespace IREmitter {
|
|||
InstLoc FoldShrl(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldXor(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldBranchCond(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldIdleBranch(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldICmpCRSigned(InstLoc Op1, InstLoc Op2);
|
||||
InstLoc FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2);
|
||||
|
@ -246,6 +249,9 @@ namespace IREmitter {
|
|||
InstLoc EmitBranchCond(InstLoc check, InstLoc dest) {
|
||||
return FoldBiOp(BranchCond, check, dest);
|
||||
}
|
||||
InstLoc EmitIdleBranch(InstLoc check, InstLoc dest) {
|
||||
return FoldBiOp(IdleBranch, check, dest);
|
||||
}
|
||||
InstLoc EmitLoadCR(unsigned crreg) {
|
||||
return FoldZeroOp(LoadCR, crreg);
|
||||
}
|
||||
|
@ -380,10 +386,7 @@ namespace IREmitter {
|
|||
}
|
||||
InstLoc EmitRFIExit() {
|
||||
return FoldZeroOp(RFIExit, 0);
|
||||
}
|
||||
InstLoc EmitIdleLoop(InstLoc idleParam, InstLoc pc) {
|
||||
return FoldBiOp(IdleLoop, idleParam, pc);
|
||||
}
|
||||
}
|
||||
InstLoc EmitShortIdleLoop(InstLoc pc) {
|
||||
return FoldUOp(ShortIdleLoop, pc);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "JitRegCache.h"
|
||||
#include "JitAsm.h"
|
||||
|
||||
#include "../../HW/Memmap.h"
|
||||
|
||||
// The branches are known good, or at least reasonably good.
|
||||
// No need for a disable-mechanism.
|
||||
|
||||
|
@ -127,7 +129,19 @@ using namespace Gen;
|
|||
else
|
||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||
|
||||
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
|
||||
if (Core::GetStartupParameter().bSkipIdle &&
|
||||
inst.hex == 0x4182fff8 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 ||
|
||||
(Core::GetStartupParameter().bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000))
|
||||
)
|
||||
{
|
||||
ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination));
|
||||
}
|
||||
else
|
||||
{
|
||||
ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
|
||||
}
|
||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||
}
|
||||
|
||||
|
|
|
@ -53,20 +53,7 @@ void Jit64::lhax(UGeckoInstruction inst)
|
|||
void Jit64::lXz(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(LoadStore)
|
||||
if (Core::GetStartupParameter().bSkipIdle &&
|
||||
inst.OPCD == 32 &&
|
||||
(inst.hex & 0xFFFF0000) == 0x800D0000 &&
|
||||
(Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 ||
|
||||
(Core::GetStartupParameter().bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
|
||||
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
|
||||
{
|
||||
ibuild.EmitIdleLoop(ibuild.EmitIntConst(PowerPC::ppcState.gpr[inst.RA] + (s32)(s16)inst.SIMM_16),
|
||||
ibuild.EmitIntConst(js.compilerPC));
|
||||
js.compilerPC += 8;
|
||||
return;
|
||||
}
|
||||
|
||||
JITDISABLE(LoadStore)
|
||||
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
|
||||
if (inst.RA)
|
||||
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));
|
||||
|
|
|
@ -348,4 +348,9 @@ void OnIdle(u32 _uThreadAddr)
|
|||
CoreTiming::Idle();
|
||||
}
|
||||
|
||||
void OnIdleIL()
|
||||
{
|
||||
CoreTiming::Idle();
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -92,6 +92,7 @@ void CompactCR();
|
|||
void ExpandCR();
|
||||
|
||||
void OnIdle(u32 _uThreadAddr);
|
||||
void OnIdleIL();
|
||||
|
||||
// Easy register access macros.
|
||||
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])
|
||||
|
|
Loading…
Reference in New Issue