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)) && (Core::GetStartupParameter().bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) &&
Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8) Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8)
{ {
// TODO(LinesPrower): // TODO(LinesPrower):
// - Fix idle skipping in JITIL!
// - Rewrite this! // - Rewrite this!
// It seems to be ugly and unefficient, but I don't know JIT stuff enough to make it right // It seems to be ugly and unefficient, but I don't know JIT stuff enough to make it right
// It only demonstrates the idea // It only demonstrates the idea
@ -164,8 +163,8 @@
ABI_CallFunctionC((void *)&PowerPC::OnIdle, PowerPC::ppcState.gpr[a] + (s32)(s16)inst.SIMM_16); 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 // ! 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)); //MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC));
JMP(asm_routines.testExceptions, true); JMP(asm_routines.testExceptions, true);
SetJumpTarget(noIdle); SetJumpTarget(noIdle);

View File

@ -514,6 +514,14 @@ InstLoc IRBuilder::FoldBranchCond(InstLoc Op1, InstLoc Op2) {
return EmitBiOp(BranchCond, Op1, 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) { InstLoc IRBuilder::FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2) {
if (isImm(*Op1)) { if (isImm(*Op1)) {
if (isImm(*Op2)) { if (isImm(*Op2)) {
@ -659,6 +667,7 @@ InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned
case Shrl: return FoldShrl(Op1, Op2); case Shrl: return FoldShrl(Op1, Op2);
case Rol: return FoldRol(Op1, Op2); case Rol: return FoldRol(Op1, Op2);
case BranchCond: return FoldBranchCond(Op1, Op2); case BranchCond: return FoldBranchCond(Op1, Op2);
case IdleBranch: return FoldIdleBranch(Op1, Op2);
case ICmpEq: case ICmpNe: case ICmpEq: case ICmpNe:
case ICmpUgt: case ICmpUlt: case ICmpUge: case ICmpUle: case ICmpUgt: case ICmpUlt: case ICmpUge: case ICmpUle:
case ICmpSgt: case ICmpSlt: case ICmpSge: case ICmpSle: case ICmpSgt: case ICmpSlt: case ICmpSge: case ICmpSle:
@ -1310,9 +1319,8 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
case InterpreterFallback: case InterpreterFallback:
case SystemCall: case SystemCall:
case RFIExit: case RFIExit:
case InterpreterBranch: case InterpreterBranch:
case IdleLoop: case ShortIdleLoop:
case ShortIdleLoop:
case Tramp: case Tramp:
// No liveness effects // No liveness effects
break; break;
@ -1419,6 +1427,9 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
if (!isImm(*getOp1(I))) if (!isImm(*getOp1(I)))
regMarkUse(RI, I, getOp1(I), 1); regMarkUse(RI, I, getOp1(I), 1);
break; break;
case IdleBranch:
regMarkUse(RI, I, getOp1(getOp1(I)), 1);
break;
case BranchCond: { case BranchCond: {
if (isICmp(*getOp1(I)) && if (isICmp(*getOp1(I)) &&
isImm(*getOp2(getOp1(I)))) { isImm(*getOp2(getOp1(I)))) {
@ -2112,6 +2123,26 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
case BlockStart: case BlockStart:
case BlockEnd: case BlockEnd:
break; 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: { case BranchCond: {
if (isICmp(*getOp1(I)) && if (isICmp(*getOp1(I)) &&
isImm(*getOp2(getOp1(I)))) { isImm(*getOp2(getOp1(I)))) {
@ -2151,15 +2182,7 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
regWriteExit(RI, getOp1(I)); regWriteExit(RI, getOp1(I));
regNormalRegClear(RI, I); regNormalRegClear(RI, I);
break; 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: { case ShortIdleLoop: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->ABI_CallFunction((void *)&CoreTiming::Idle); Jit->ABI_CallFunction((void *)&CoreTiming::Idle);

View File

@ -156,7 +156,9 @@ namespace IREmitter {
SystemCall, SystemCall,
RFIExit, RFIExit,
InterpreterBranch, 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, ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
// just a branch // just a branch
@ -220,6 +222,7 @@ namespace IREmitter {
InstLoc FoldShrl(InstLoc Op1, InstLoc Op2); InstLoc FoldShrl(InstLoc Op1, InstLoc Op2);
InstLoc FoldXor(InstLoc Op1, InstLoc Op2); InstLoc FoldXor(InstLoc Op1, InstLoc Op2);
InstLoc FoldBranchCond(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 FoldICmp(unsigned Opcode, InstLoc Op1, InstLoc Op2);
InstLoc FoldICmpCRSigned(InstLoc Op1, InstLoc Op2); InstLoc FoldICmpCRSigned(InstLoc Op1, InstLoc Op2);
InstLoc FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2); InstLoc FoldICmpCRUnsigned(InstLoc Op1, InstLoc Op2);
@ -246,6 +249,9 @@ namespace IREmitter {
InstLoc EmitBranchCond(InstLoc check, InstLoc dest) { InstLoc EmitBranchCond(InstLoc check, InstLoc dest) {
return FoldBiOp(BranchCond, check, dest); return FoldBiOp(BranchCond, check, dest);
} }
InstLoc EmitIdleBranch(InstLoc check, InstLoc dest) {
return FoldBiOp(IdleBranch, check, dest);
}
InstLoc EmitLoadCR(unsigned crreg) { InstLoc EmitLoadCR(unsigned crreg) {
return FoldZeroOp(LoadCR, crreg); return FoldZeroOp(LoadCR, crreg);
} }
@ -380,10 +386,7 @@ namespace IREmitter {
} }
InstLoc EmitRFIExit() { InstLoc EmitRFIExit() {
return FoldZeroOp(RFIExit, 0); return FoldZeroOp(RFIExit, 0);
} }
InstLoc EmitIdleLoop(InstLoc idleParam, InstLoc pc) {
return FoldBiOp(IdleLoop, idleParam, pc);
}
InstLoc EmitShortIdleLoop(InstLoc pc) { InstLoc EmitShortIdleLoop(InstLoc pc) {
return FoldUOp(ShortIdleLoop, pc); return FoldUOp(ShortIdleLoop, pc);
} }

View File

@ -27,6 +27,8 @@
#include "JitRegCache.h" #include "JitRegCache.h"
#include "JitAsm.h" #include "JitAsm.h"
#include "../../HW/Memmap.h"
// The branches are known good, or at least reasonably good. // The branches are known good, or at least reasonably good.
// No need for a disable-mechanism. // No need for a disable-mechanism.
@ -127,7 +129,19 @@ using namespace Gen;
else else
destination = js.compilerPC + SignExt16(inst.BD << 2); 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)); ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
} }

View File

@ -53,20 +53,7 @@ void Jit64::lhax(UGeckoInstruction inst)
void Jit64::lXz(UGeckoInstruction inst) void Jit64::lXz(UGeckoInstruction inst)
{ {
INSTRUCTION_START INSTRUCTION_START
JITDISABLE(LoadStore) 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;
}
IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16);
if (inst.RA) if (inst.RA)
addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA));

View File

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

View File

@ -92,6 +92,7 @@ void CompactCR();
void ExpandCR(); void ExpandCR();
void OnIdle(u32 _uThreadAddr); void OnIdle(u32 _uThreadAddr);
void OnIdleIL();
// Easy register access macros. // Easy register access macros.
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) #define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])