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
|
@ -137,7 +137,6 @@
|
||||||
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,7 +163,7 @@
|
||||||
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);
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -1311,7 +1320,6 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
|
||||||
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
|
||||||
|
@ -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)))) {
|
||||||
|
@ -2152,14 +2183,6 @@ static void DoWriteCode(IRBuilder* ibuild, Jit64* Jit, bool UseProfile) {
|
||||||
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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -381,9 +387,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
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.EmitBranchCond(Test, ibuild.EmitIntConst(destination));
|
||||||
|
}
|
||||||
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,19 +54,6 @@ 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));
|
||||||
|
|
|
@ -348,4 +348,9 @@ void OnIdle(u32 _uThreadAddr)
|
||||||
CoreTiming::Idle();
|
CoreTiming::Idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnIdleIL()
|
||||||
|
{
|
||||||
|
CoreTiming::Idle();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
|
@ -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])
|
||||||
|
|
Loading…
Reference in New Issue