From f0bb8f430af0c480dca20199756ba9be87ba7cd8 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sat, 20 Dec 2008 11:20:47 +0000 Subject: [PATCH] small build fix in debug mode, misc cleanup git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1604 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 7 +- Source/Core/Core/Src/PowerPC/Jit64/Jit.h | 9 + .../Core/Core/Src/PowerPC/Jit64/JitCache.cpp | 1 - .../Core/Src/PowerPC/Jit64/JitRegCache.cpp | 612 +++++++++--------- .../Core/Core/Src/PowerPC/Jit64/JitRegCache.h | 215 +++--- .../Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 32 +- .../Core/Core/Src/PowerPC/Jit64/Jit_Util.cpp | 15 +- Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp | 2 + Source/Core/Core/Src/PowerPC/PPCAnalyst.h | 1 + 9 files changed, 459 insertions(+), 435 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 87ebd695e1..3f7d753a3a 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -189,6 +189,7 @@ namespace CPUCompare jo.fpAccurateFlags = true; jo.optimizeGatherPipe = true; jo.fastInterrupts = false; + jo.accurateSinglePrecision = true; gpr.SetEmitter(this); fpr.SetEmitter(this); @@ -328,6 +329,9 @@ namespace CPUCompare if (emaddress == 0) PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR); +// if (emaddress == 0x800aa278) +// DebugBreak(); + int size; js.isLastInstruction = false; js.blockStart = emaddress; @@ -433,7 +437,8 @@ namespace CPUCompare CALL(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0)); } - PPCTables::CompileInstruction(ops[i].inst); + if (!ops[i].skip) + PPCTables::CompileInstruction(ops[i].inst); gpr.SanityCheck(); fpr.SanityCheck(); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index 17d6e4fc15..ef858c94a9 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -19,6 +19,14 @@ // See comments in Jit.cpp. // ======================== +// Mystery: Capcom vs SNK 800aa278 + +// CR flags approach: +// * Store that "N+Z flag contains CR0" or "S+Z flag contains CR3". +// * All flag altering instructions flush this +// * A flush simply does a conditional write to the appropriate CRx. +// * If flag available, branch code can become absolutely trivial. + #ifndef _JIT_H #define _JIT_H @@ -128,6 +136,7 @@ private: bool enableFastMem; bool optimizeGatherPipe; bool fastInterrupts; + bool accurateSinglePrecision; }; diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp index 26a95f7cd7..1c03f52efe 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp @@ -70,7 +70,6 @@ using namespace Gen; { LOG(DYNA_REC, "JIT Statistics ======================="); LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks); - LOG(DYNA_REC, "Code cache size: %i b", GetCodePtr() - codeCache); LOG(DYNA_REC, "======================================"); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.cpp index 11080033df..9ef3550245 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.cpp @@ -14,6 +14,7 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ + #include "../PowerPC.h" #include "../PPCTables.h" #include "../PPCAnalyst.h" @@ -22,374 +23,371 @@ #include "JitAsm.h" #include "JitRegCache.h" - using namespace Gen; using namespace PowerPC; - - - void RegCache::Start(PPCAnalyst::BlockRegStats &stats) +void RegCache::Start(PPCAnalyst::BlockRegStats &stats) +{ + for (int i = 0; i < NUMXREGS; i++) { - for (int i = 0; i < NUMXREGS; i++) - { - xregs[i].free = true; - xregs[i].dirty = false; - xlocks[i] = false; - } - for (int i = 0; i < 32; i++) - { - regs[i].location = GetDefaultLocation(i); - regs[i].away = false; - } - - // todo: sort to find the most popular regs - /* - int maxPreload = 2; - for (int i = 0; i < 32; i++) - { - if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2) - { - LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false); - maxPreload--; - if (!maxPreload) - break; - } - }*/ - //Find top regs - preload them (load bursts ain't bad) - //But only preload IF written OR reads >= 3 + xregs[i].free = true; + xregs[i].dirty = false; + xlocks[i] = false; } - - // these are powerpc reg indices - void RegCache::Lock(int p1, int p2, int p3, int p4) + for (int i = 0; i < 32; i++) { - locks[p1] = true; - if (p2 != 0xFF) locks[p2] = true; - if (p3 != 0xFF) locks[p3] = true; - if (p4 != 0xFF) locks[p4] = true; - } - - // these are x64 reg indices - void RegCache::LockX(int x1, int x2, int x3, int x4) - { - if (xlocks[x1]) { - PanicAlert("RegCache: x %i already locked!"); - } - xlocks[x1] = true; - if (x2 != 0xFF) xlocks[x2] = true; - if (x3 != 0xFF) xlocks[x3] = true; - if (x4 != 0xFF) xlocks[x4] = true; - } - - bool RegCache::IsFreeX(int xreg) const - { - return xregs[xreg].free && !xlocks[xreg]; - } - - void RegCache::UnlockAll() - { - for (int i = 0; i < 32; i++) - locks[i] = false; - } - - void RegCache::UnlockAllX() - { - for (int i = 0; i < NUMXREGS; i++) - xlocks[i] = false; + regs[i].location = GetDefaultLocation(i); + regs[i].away = false; } - X64Reg RegCache::GetFreeXReg() + // todo: sort to find the most popular regs + /* + int maxPreload = 2; + for (int i = 0; i < 32; i++) { - int aCount; - const int *aOrder = GetAllocationOrder(aCount); - for (int i = 0; i < aCount; i++) + if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2) { - X64Reg xr = (X64Reg)aOrder[i]; - if (!xlocks[xr] && xregs[xr].free) - { - return (X64Reg)xr; - } + LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false); + maxPreload--; + if (!maxPreload) + break; } - //Okay, not found :( Force grab one + }*/ + //Find top regs - preload them (load bursts ain't bad) + //But only preload IF written OR reads >= 3 +} - //TODO - add a pass to grab xregs whose ppcreg is not used in the next 3 instructions - for (int i = 0; i < aCount; i++) +// these are powerpc reg indices +void RegCache::Lock(int p1, int p2, int p3, int p4) +{ + locks[p1] = true; + if (p2 != 0xFF) locks[p2] = true; + if (p3 != 0xFF) locks[p3] = true; + if (p4 != 0xFF) locks[p4] = true; +} + +// these are x64 reg indices +void RegCache::LockX(int x1, int x2, int x3, int x4) +{ + if (xlocks[x1]) { + PanicAlert("RegCache: x %i already locked!"); + } + xlocks[x1] = true; + if (x2 != 0xFF) xlocks[x2] = true; + if (x3 != 0xFF) xlocks[x3] = true; + if (x4 != 0xFF) xlocks[x4] = true; +} + +bool RegCache::IsFreeX(int xreg) const +{ + return xregs[xreg].free && !xlocks[xreg]; +} + +void RegCache::UnlockAll() +{ + for (int i = 0; i < 32; i++) + locks[i] = false; +} + +void RegCache::UnlockAllX() +{ + for (int i = 0; i < NUMXREGS; i++) + xlocks[i] = false; +} + +X64Reg RegCache::GetFreeXReg() +{ + int aCount; + const int *aOrder = GetAllocationOrder(aCount); + for (int i = 0; i < aCount; i++) + { + X64Reg xr = (X64Reg)aOrder[i]; + if (!xlocks[xr] && xregs[xr].free) { - X64Reg xr = (X64Reg)aOrder[i]; - if (xlocks[xr]) - continue; - int preg = xregs[xr].ppcReg; - if (!locks[preg]) - { - StoreFromX64(preg); - return xr; - } - } - //Still no dice? Die! - _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs"); - return (X64Reg) -1; - } - - void RegCache::SaveState() - { - memcpy(saved_locks, locks, sizeof(locks)); - memcpy(saved_xlocks, xlocks, sizeof(xlocks)); - memcpy(saved_regs, regs, sizeof(regs)); - memcpy(saved_xregs, xregs, sizeof(xregs)); - } - - void RegCache::LoadState() - { - memcpy(xlocks, saved_xlocks, sizeof(xlocks)); - memcpy(locks, saved_locks, sizeof(locks)); - memcpy(regs, saved_regs, sizeof(regs)); - memcpy(xregs, saved_xregs, sizeof(xregs)); - } - - void RegCache::FlushR(X64Reg reg) - { - if (reg >= NUMXREGS) - PanicAlert("Flushing non existent reg"); - if (!xregs[reg].free) - { - StoreFromX64(xregs[reg].ppcReg); + return (X64Reg)xr; } } + //Okay, not found :( Force grab one - void RegCache::SanityCheck() const + //TODO - add a pass to grab xregs whose ppcreg is not used in the next 3 instructions + for (int i = 0; i < aCount; i++) { - for (int i = 0; i < 32; i++) { - if (regs[i].away) { - if (regs[i].location.IsSimpleReg()) { - Gen::X64Reg simple = regs[i].location.GetSimpleReg(); - if (xlocks[simple]) { - PanicAlert("%08x : PPC Reg %i is in locked x64 register %i", /*js.compilerPC*/ 0, i, regs[i].location.GetSimpleReg()); - } - if (xregs[simple].ppcReg != i) { - PanicAlert("%08x : Xreg/ppcreg mismatch"); - } + X64Reg xr = (X64Reg)aOrder[i]; + if (xlocks[xr]) + continue; + int preg = xregs[xr].ppcReg; + if (!locks[preg]) + { + StoreFromX64(preg); + return xr; + } + } + //Still no dice? Die! + _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs"); + return (X64Reg) -1; +} + +void RegCache::SaveState() +{ + memcpy(saved_locks, locks, sizeof(locks)); + memcpy(saved_xlocks, xlocks, sizeof(xlocks)); + memcpy(saved_regs, regs, sizeof(regs)); + memcpy(saved_xregs, xregs, sizeof(xregs)); +} + +void RegCache::LoadState() +{ + memcpy(xlocks, saved_xlocks, sizeof(xlocks)); + memcpy(locks, saved_locks, sizeof(locks)); + memcpy(regs, saved_regs, sizeof(regs)); + memcpy(xregs, saved_xregs, sizeof(xregs)); +} + +void RegCache::FlushR(X64Reg reg) +{ + if (reg >= NUMXREGS) + PanicAlert("Flushing non existent reg"); + if (!xregs[reg].free) + { + StoreFromX64(xregs[reg].ppcReg); + } +} + +void RegCache::SanityCheck() const +{ + for (int i = 0; i < 32; i++) { + if (regs[i].away) { + if (regs[i].location.IsSimpleReg()) { + Gen::X64Reg simple = regs[i].location.GetSimpleReg(); + if (xlocks[simple]) { + PanicAlert("%08x : PPC Reg %i is in locked x64 register %i", /*js.compilerPC*/ 0, i, regs[i].location.GetSimpleReg()); + } + if (xregs[simple].ppcReg != i) { + PanicAlert("%08x : Xreg/ppcreg mismatch"); } } } } +} - void RegCache::DiscardRegContentsIfCached(int preg) +void RegCache::DiscardRegContentsIfCached(int preg) +{ + if (regs[preg].away && regs[preg].location.IsSimpleReg()) { - if (regs[preg].away && regs[preg].location.IsSimpleReg()) - { - xregs[regs[preg].location.GetSimpleReg()].free = true; - xregs[regs[preg].location.GetSimpleReg()].dirty = false; - regs[preg].away = false; - } + xregs[regs[preg].location.GetSimpleReg()].free = true; + xregs[regs[preg].location.GetSimpleReg()].dirty = false; + regs[preg].away = false; } +} - void GPRRegCache::SetImmediate32(int preg, u32 immValue) +void GPRRegCache::SetImmediate32(int preg, u32 immValue) +{ + DiscardRegContentsIfCached(preg); + regs[preg].away = true; + regs[preg].location = Imm32(immValue); +} + +void GPRRegCache::Start(PPCAnalyst::BlockRegStats &stats) +{ + RegCache::Start(stats); +} + +void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats) +{ + RegCache::Start(stats); +} + +const int *GPRRegCache::GetAllocationOrder(int &count) +{ + static const int allocationOrder[] = { - DiscardRegContentsIfCached(preg); - regs[preg].away = true; - regs[preg].location = Imm32(immValue); - } - - void GPRRegCache::Start(PPCAnalyst::BlockRegStats &stats) - { - RegCache::Start(stats); - } - - void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats) - { - RegCache::Start(stats); - } - - const int *GPRRegCache::GetAllocationOrder(int &count) - { - static const int allocationOrder[] = - { #ifdef _M_X64 #ifdef _WIN32 - RSI, RDI, R12, R13, R14, R8, R9, R10, R11 //, RCX + RSI, RDI, R12, R13, R14, R8, R9, R10, R11 //, RCX #else - RBP, R12, R13, R14, R8, R9, R10, R11, //, RCX + RBP, R12, R13, R14, R8, R9, R10, R11, //, RCX #endif #elif _M_IX86 - ESI, EDI, EBX, EBP, EDX, ECX, + ESI, EDI, EBX, EBP, EDX, ECX, #endif - }; - count = sizeof(allocationOrder) / sizeof(const int); - return allocationOrder; - } + }; + count = sizeof(allocationOrder) / sizeof(const int); + return allocationOrder; +} - const int *FPURegCache::GetAllocationOrder(int &count) +const int *FPURegCache::GetAllocationOrder(int &count) +{ + static const int allocationOrder[] = { - static const int allocationOrder[] = - { #ifdef _M_X64 - XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5 + XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5 #elif _M_IX86 - XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, + XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, #endif - }; - count = sizeof(allocationOrder) / sizeof(int); - return allocationOrder; - } + }; + count = sizeof(allocationOrder) / sizeof(int); + return allocationOrder; +} - OpArg GPRRegCache::GetDefaultLocation(int reg) const - { - return M(&ppcState.gpr[reg]); - } +OpArg GPRRegCache::GetDefaultLocation(int reg) const +{ + return M(&ppcState.gpr[reg]); +} - OpArg FPURegCache::GetDefaultLocation(int reg) const - { - return M(&ppcState.ps[reg][0]); - } +OpArg FPURegCache::GetDefaultLocation(int reg) const +{ + return M(&ppcState.ps[reg][0]); +} - void RegCache::KillImmediate(int preg) +void RegCache::KillImmediate(int preg) +{ + if (regs[preg].away && regs[preg].location.IsImm()) { - if (regs[preg].away && regs[preg].location.IsImm()) + LoadToX64(preg, true, true); + } +} + +void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty) +{ + if (!regs[i].away && regs[i].location.IsImm()) + PanicAlert("Bad immedaite"); + + if (!regs[i].away || (regs[i].away && regs[i].location.IsImm())) + { + X64Reg xr = GetFreeXReg(); + if (xregs[xr].dirty) PanicAlert("Xreg already dirty"); + if (xlocks[xr]) PanicAlert("GetFreeXReg returned locked register"); + xregs[xr].free = false; + xregs[xr].ppcReg = i; + xregs[xr].dirty = makeDirty || regs[i].location.IsImm(); + OpArg newloc = ::Gen::R(xr); + if (doLoad || regs[i].location.IsImm()) + emit->MOV(32, newloc, regs[i].location); + for (int j = 0; j < 32; j++) { - LoadToX64(preg, true, true); - } - } - - void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty) - { - if (!regs[i].away && regs[i].location.IsImm()) - PanicAlert("Bad immedaite"); - - if (!regs[i].away || (regs[i].away && regs[i].location.IsImm())) - { - X64Reg xr = GetFreeXReg(); - if (xregs[xr].dirty) PanicAlert("Xreg already dirty"); - if (xlocks[xr]) PanicAlert("GetFreeXReg returned locked register"); - xregs[xr].free = false; - xregs[xr].ppcReg = i; - xregs[xr].dirty = makeDirty || regs[i].location.IsImm(); - OpArg newloc = ::Gen::R(xr); - if (doLoad || regs[i].location.IsImm()) - 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) { - if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr) - { - Crash(); - } + Crash(); } - regs[i].away = true; - regs[i].location = newloc; + } + regs[i].away = true; + regs[i].location = newloc; + } + else + { + // reg location must be simplereg; memory locations + // and immediates are taken care of above. + xregs[RX(i)].dirty |= makeDirty; + } + if (xlocks[RX(i)]) { + PanicAlert("Seriously WTF, this reg should have been flushed"); + } +} + +void GPRRegCache::StoreFromX64(int i) +{ + if (regs[i].away) + { + bool doStore; + if (regs[i].location.IsSimpleReg()) + { + X64Reg xr = RX(i); + xregs[xr].free = true; + xregs[xr].ppcReg = -1; + doStore = xregs[xr].dirty; + xregs[xr].dirty = false; } else { - // reg location must be simplereg; memory locations - // and immediates are taken care of above. - xregs[RX(i)].dirty |= makeDirty; - } - if (xlocks[RX(i)]) { - PanicAlert("Seriously WTF, this reg should have been flushed"); + //must be immediate - do nothing + doStore = true; } + OpArg newLoc = GetDefaultLocation(i); + // if (doStore) //<-- Breaks JIT compilation + emit->MOV(32, newLoc, regs[i].location); + regs[i].location = newLoc; + regs[i].away = false; } +} - void GPRRegCache::StoreFromX64(int i) +void FPURegCache::LoadToX64(int i, bool doLoad, bool makeDirty) +{ + _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm"); + if (!regs[i].away) { + // Reg is at home in the memory register file. Let's pull it out. + X64Reg xr = GetFreeXReg(); + _assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - load - invalid reg"); + xregs[xr].ppcReg = i; + xregs[xr].free = false; + xregs[xr].dirty = makeDirty; + OpArg newloc = ::Gen::R(xr); + if (doLoad) + { + if (!regs[i].location.IsImm() && (regs[i].location.offset & 0xF)) + { + PanicAlert("WARNING - misaligned fp register location %i", i); + } + emit->MOVAPD(xr, regs[i].location); + } + regs[i].location = newloc; + regs[i].away = true; + } else { + // There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary. + xregs[RX(i)].dirty |= makeDirty; + } +} + +void FPURegCache::StoreFromX64(int i) +{ + _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm"); + if (regs[i].away) + { + X64Reg xr = regs[i].location.GetSimpleReg(); + _assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - store - invalid reg"); + xregs[xr].free = true; + xregs[xr].dirty = false; + xregs[xr].ppcReg = -1; + OpArg newLoc = GetDefaultLocation(i); + emit->MOVAPD(newLoc, xr); + regs[i].location = newLoc; + regs[i].away = false; + } + else + { + // _assert_msg_(DYNA_REC,0,"already stored"); + } +} + +void RegCache::Flush(FlushMode mode) +{ + for (int i = 0; i < NUMXREGS; i++) { + if (xlocks[i]) + PanicAlert("Somone forgot to unlock X64 reg %i.", i); + } + for (int i = 0; i < 32; i++) + { + if (locks[i]) + { + PanicAlert("Somebody forgot to unlock PPC reg %i.", i); + } if (regs[i].away) { - bool doStore; if (regs[i].location.IsSimpleReg()) { X64Reg xr = RX(i); - xregs[xr].free = true; - xregs[xr].ppcReg = -1; - doStore = xregs[xr].dirty; + StoreFromX64(i); xregs[xr].dirty = false; } + else if (regs[i].location.IsImm()) + { + StoreFromX64(i); + } else { - //must be immediate - do nothing - doStore = true; - } - OpArg newLoc = GetDefaultLocation(i); - // if (doStore) //<-- Breaks JIT compilation - emit->MOV(32, newLoc, regs[i].location); - regs[i].location = newLoc; - regs[i].away = false; - } - } - - void FPURegCache::LoadToX64(int i, bool doLoad, bool makeDirty) - { - _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm"); - if (!regs[i].away) - { - // Reg is at home in the memory register file. Let's pull it out. - X64Reg xr = GetFreeXReg(); - _assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - load - invalid reg"); - xregs[xr].ppcReg = i; - xregs[xr].free = false; - xregs[xr].dirty = makeDirty; - OpArg newloc = ::Gen::R(xr); - if (doLoad) - { - if (!regs[i].location.IsImm() && (regs[i].location.offset & 0xF)) - { - PanicAlert("WARNING - misaligned fp register location %i", i); - } - emit->MOVAPD(xr, regs[i].location); - } - regs[i].location = newloc; - regs[i].away = true; - } else { - // There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary. - xregs[RX(i)].dirty |= makeDirty; - } - } - - void FPURegCache::StoreFromX64(int i) - { - _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm"); - if (regs[i].away) - { - X64Reg xr = regs[i].location.GetSimpleReg(); - _assert_msg_(DYNA_REC, xr >= 0 && xr < NUMXREGS, "WTF - store - invalid reg"); - xregs[xr].free = true; - xregs[xr].dirty = false; - xregs[xr].ppcReg = -1; - OpArg newLoc = GetDefaultLocation(i); - emit->MOVAPD(newLoc, xr); - regs[i].location = newLoc; - regs[i].away = false; - } - else - { - // _assert_msg_(DYNA_REC,0,"already stored"); - } - } - - void RegCache::Flush(FlushMode mode) - { - for (int i = 0; i < NUMXREGS; i++) { - if (xlocks[i]) - PanicAlert("Somone forgot to unlock X64 reg %i.", i); - } - for (int i = 0; i < 32; i++) - { - if (locks[i]) - { - PanicAlert("Somebody forgot to unlock PPC reg %i.", i); - } - if (regs[i].away) - { - if (regs[i].location.IsSimpleReg()) - { - X64Reg xr = RX(i); - StoreFromX64(i); - xregs[xr].dirty = false; - } - else if (regs[i].location.IsImm()) - { - StoreFromX64(i); - } - else - { - _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i", i); - } + _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i", i); } } } +} diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.h b/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.h index 4888c7019c..fa65c596c5 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.h @@ -20,34 +20,34 @@ #include "x64Emitter.h" - using namespace Gen; - enum FlushMode - { - FLUSH_ALL - }; +using namespace Gen; +enum FlushMode +{ + FLUSH_ALL +}; - enum GrabMode - { - M_READ = 1, - M_WRITE = 2, - M_READWRITE = 3, - }; +enum GrabMode +{ + M_READ = 1, + M_WRITE = 2, + M_READWRITE = 3, +}; - struct PPCCachedReg - { - OpArg location; - bool away; // value not in source register - }; +struct PPCCachedReg +{ + OpArg location; + bool away; // value not in source register +}; - struct X64CachedReg - { - int ppcReg; - bool dirty; - bool free; - }; +struct X64CachedReg +{ + int ppcReg; + bool dirty; + bool free; +}; - typedef int XReg; - typedef int PReg; +typedef int XReg; +typedef int PReg; #ifdef _M_X64 #define NUMXREGS 16 @@ -55,97 +55,96 @@ #define NUMXREGS 8 #endif - class RegCache +class RegCache +{ +private: + bool locks[32]; + bool saved_locks[32]; + bool saved_xlocks[NUMXREGS]; + +protected: + bool xlocks[NUMXREGS]; + PPCCachedReg regs[32]; + X64CachedReg xregs[NUMXREGS]; + + PPCCachedReg saved_regs[32]; + X64CachedReg saved_xregs[NUMXREGS]; + + void DiscardRegContentsIfCached(int preg); + virtual const int *GetAllocationOrder(int &count) = 0; + + XEmitter *emit; + +public: + virtual ~RegCache() {} + virtual void Start(PPCAnalyst::BlockRegStats &stats) = 0; + + void SetEmitter(XEmitter *emitter) {emit = emitter;} + + void FlushR(X64Reg reg); + void FlushR(X64Reg reg, X64Reg reg2) {FlushR(reg); FlushR(reg2);} + void FlushLockX(X64Reg reg) { + FlushR(reg); + LockX(reg); + } + void FlushLockX(X64Reg reg1, X64Reg reg2) { + FlushR(reg1); FlushR(reg2); + LockX(reg1); LockX(reg2); + } + virtual void Flush(FlushMode mode); + virtual void Flush(PPCAnalyst::CodeOp *op) {Flush(FLUSH_ALL);} + void SanityCheck() const; + void KillImmediate(int preg); + + //TODO - instead of doload, use "read", "write" + //read only will not set dirty flag + virtual void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true) = 0; + virtual void StoreFromX64(int preg) = 0; + + const OpArg &R(int preg) const {return regs[preg].location;} + X64Reg RX(int preg) const { - private: - bool locks[32]; - bool saved_locks[32]; - bool saved_xlocks[NUMXREGS]; + if (regs[preg].away && regs[preg].location.IsSimpleReg()) + return regs[preg].location.GetSimpleReg(); + PanicAlert("Not so simple - %i", preg); + return (X64Reg)-1; + } + virtual OpArg GetDefaultLocation(int reg) const = 0; - protected: - bool xlocks[NUMXREGS]; - PPCCachedReg regs[32]; - X64CachedReg xregs[NUMXREGS]; + // Register locking. + void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff); + void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff); + void UnlockAll(); + void UnlockAllX(); - PPCCachedReg saved_regs[32]; - X64CachedReg saved_xregs[NUMXREGS]; + bool IsFreeX(int xreg) const; - void DiscardRegContentsIfCached(int preg); - virtual const int *GetAllocationOrder(int &count) = 0; - - XEmitter *emit; + X64Reg GetFreeXReg(); - public: - virtual ~RegCache() {} - virtual void Start(PPCAnalyst::BlockRegStats &stats) = 0; + void SaveState(); + void LoadState(); +}; - void SetEmitter(XEmitter *emitter) {emit = emitter;} - - void FlushR(X64Reg reg); - void FlushR(X64Reg reg, X64Reg reg2) {FlushR(reg); FlushR(reg2);} - void FlushLockX(X64Reg reg) { - FlushR(reg); - LockX(reg); - } - void FlushLockX(X64Reg reg1, X64Reg reg2) { - FlushR(reg1); FlushR(reg2); - LockX(reg1); LockX(reg2); - } - virtual void Flush(FlushMode mode); - virtual void Flush(PPCAnalyst::CodeOp *op) {Flush(FLUSH_ALL);} - void SanityCheck() const; - void KillImmediate(int preg); - - //TODO - instead of doload, use "read", "write" - //read only will not set dirty flag - virtual void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true) = 0; - virtual void StoreFromX64(int preg) = 0; - - const OpArg &R(int preg) const {return regs[preg].location;} - X64Reg RX(int preg) const - { - if (regs[preg].away && regs[preg].location.IsSimpleReg()) - return regs[preg].location.GetSimpleReg(); - PanicAlert("Not so simple - %i", preg); - return (X64Reg)-1; - } - virtual OpArg GetDefaultLocation(int reg) const = 0; - - // Register locking. - void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff); - void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff); - void UnlockAll(); - void UnlockAllX(); - - bool IsFreeX(int xreg) const; - - X64Reg GetFreeXReg(); - - void SaveState(); - void LoadState(); - }; - - class GPRRegCache : public RegCache - { - public: - void Start(PPCAnalyst::BlockRegStats &stats); - void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true); - void StoreFromX64(int preg); - OpArg GetDefaultLocation(int reg) const; - const int *GetAllocationOrder(int &count); - void SetImmediate32(int preg, u32 immValue); - }; +class GPRRegCache : public RegCache +{ +public: + void Start(PPCAnalyst::BlockRegStats &stats); + void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true); + void StoreFromX64(int preg); + OpArg GetDefaultLocation(int reg) const; + const int *GetAllocationOrder(int &count); + void SetImmediate32(int preg, u32 immValue); +}; - class FPURegCache : public RegCache - { - public: - void Start(PPCAnalyst::BlockRegStats &stats); - void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true); - void StoreFromX64(int preg); - const int *GetAllocationOrder(int &count); - OpArg GetDefaultLocation(int reg) const; - }; +class FPURegCache : public RegCache +{ +public: + void Start(PPCAnalyst::BlockRegStats &stats); + void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true); + void StoreFromX64(int preg); + const int *GetAllocationOrder(int &count); + OpArg GetDefaultLocation(int reg) const; +}; #endif - diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index a30bcdf71e..6891fe5987 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -202,6 +202,7 @@ if (!merge_branch) { // Keep the normal code separate for clarity. CMP(32, gpr.R(a), comparand); + FixupBranch pLesser = J_CC(less_than); FixupBranch pGreater = J_CC(greater_than); MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // _x86Reg == 0 @@ -216,42 +217,45 @@ } else { int test_bit = 8 >> (js.next_inst.BI & 3); bool condition = (js.next_inst.BO & 8) ? false : true; - - u32 destination; - if (js.next_inst.AA) - destination = SignExt16(js.next_inst.BD << 2); - else - destination = js.next_compilerPC + SignExt16(js.next_inst.BD << 2); - CMP(32, gpr.R(a), comparand); gpr.UnlockAll(); + + u32 destination1; + if (js.next_inst.AA) + destination1 = SignExt16(js.next_inst.BD << 2); + else + destination1 = js.next_compilerPC + SignExt16(js.next_inst.BD << 2); + u32 destination2 = js.next_compilerPC + 4; + + // Test swapping (in the future, will be used to inline across branches the right way) + // if (rand() & 1) + // std::swap(destination1, destination2), condition = !condition; + gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); FixupBranch pLesser = J_CC(less_than); FixupBranch pGreater = J_CC(greater_than); - MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // _x86Reg == 0 + MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // == 0 FixupBranch continue1 = J(); SetJumpTarget(pGreater); - MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x4)); // _x86Reg > 0 + MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x4)); // > 0 FixupBranch continue2 = J(); SetJumpTarget(pLesser); - MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x8)); // _x86Reg < 0 + MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x8)); // < 0 FixupBranch continue3; if (!!(8 & test_bit) == condition) continue3 = J(); - - //if (!!(8 & test_bit) != condition) SetJumpTarget(continue3); if (!!(4 & test_bit) != condition) SetJumpTarget(continue2); if (!!(2 & test_bit) != condition) SetJumpTarget(continue1); - WriteExit(destination, 0); + WriteExit(destination1, 0); if (!!(8 & test_bit) == condition) SetJumpTarget(continue3); if (!!(4 & test_bit) == condition) SetJumpTarget(continue2); if (!!(2 & test_bit) == condition) SetJumpTarget(continue1); - WriteExit(js.next_compilerPC + 4, 1); + WriteExit(destination2, 1); js.cancel = true; } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Util.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Util.cpp index 45d6721515..17b34afd34 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Util.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Util.cpp @@ -139,11 +139,18 @@ void Jit64::WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address) void Jit64::ForceSinglePrecisionS(X64Reg xmm) { // Most games don't need these. Zelda requires it though - some platforms get stuck without them. - CVTSD2SS(xmm, R(xmm)); - CVTSS2SD(xmm, R(xmm)); + if (jo.accurateSinglePrecision) + { + CVTSD2SS(xmm, R(xmm)); + CVTSS2SD(xmm, R(xmm)); + } } + void Jit64::ForceSinglePrecisionP(X64Reg xmm) { // Most games don't need these. Zelda requires it though - some platforms get stuck without them. - CVTPD2PS(xmm, R(xmm)); - CVTPS2PD(xmm, R(xmm)); + if (jo.accurateSinglePrecision) + { + CVTPD2PS(xmm, R(xmm)); + CVTPS2PD(xmm, R(xmm)); + } } diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp index 88ce8d74ea..f668bc9ee6 100644 --- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp @@ -313,6 +313,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo code[i].inst = inst; code[i].branchTo = -1; code[i].branchToIndex = -1; + code[i].skip = false; GekkoOPInfo *opinfo = GetOpInfo(inst); if (opinfo) numCycles += opinfo->numCyclesMinusOne + 1; @@ -345,6 +346,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo } else { + code[i].skip = true; address = destination; } } diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.h b/Source/Core/Core/Src/PowerPC/PPCAnalyst.h index f5732b06fe..1e0a72870c 100644 --- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.h @@ -49,6 +49,7 @@ struct CodeOp //16B bool outputCR0; bool outputCR1; bool outputPS1; + bool skip; // followed BL-s for example }; struct BlockStats