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:
LinesPrower 2009-05-31 09:22:29 +00:00
parent 71e895ddf7
commit 4c19fa7e5f
7 changed files with 68 additions and 36 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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));

View File

@ -348,4 +348,9 @@ void OnIdle(u32 _uThreadAddr)
CoreTiming::Idle();
}
void OnIdleIL()
{
CoreTiming::Idle();
}
} // namespace

View File

@ -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])