summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorhrydgard <hrydgard@gmail.com>2008-12-20 11:20:47 +0000
committerhrydgard <hrydgard@gmail.com>2008-12-20 11:20:47 +0000
commitf0bb8f430af0c480dca20199756ba9be87ba7cd8 (patch)
tree31bdac06b31fee6127c741d31b2014f2aa3e890c /Source/Core
parent4f4edc05a094ab8d833fdbb7dcff770712301437 (diff)
small build fix in debug mode, misc cleanup
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1604 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp7
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit.h9
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/JitCache.cpp1
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.cpp578
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/JitRegCache.h237
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp28
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit_Util.cpp15
-rw-r--r--Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp2
-rw-r--r--Source/Core/Core/Src/PowerPC/PPCAnalyst.h1
9 files changed, 451 insertions, 427 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)
- {
- 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
- }
-
- // these are powerpc reg indices
- void RegCache::Lock(int p1, int p2, int p3, int p4)
+void RegCache::Start(PPCAnalyst::BlockRegStats &stats)
+{
+ for (int i = 0; i < NUMXREGS; i++)
{
- locks[p1] = true;
- if (p2 != 0xFF) locks[p2] = true;
- if (p3 != 0xFF) locks[p3] = true;
- if (p4 != 0xFF) locks[p4] = true;
+ xregs[i].free = true;
+ xregs[i].dirty = false;
+ xlocks[i] = false;
}
-
- // these are x64 reg indices
- void RegCache::LockX(int x1, int x2, int x3, int x4)
+ for (int i = 0; i < 32; i++)
{
- 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++)
- {
- X64Reg xr = (X64Reg)aOrder[i];
- if (!xlocks[xr] && xregs[xr].free)
- {
- return (X64Reg)xr;
- }
- }
- //Okay, not found :( Force grab one
-
- //TODO - add a pass to grab xregs whose ppcreg is not used in the next 3 instructions
- for (int i = 0; i < aCount; i++)
+ if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2)
{
- X64Reg xr = (X64Reg)aOrder[i];
- if (xlocks[xr])
- continue;
- int preg = xregs[xr].ppcReg;
- if (!locks[preg])
- {
- StoreFromX64(preg);
- return xr;
- }
+ LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false);
+ maxPreload--;
+ if (!maxPreload)
+ break;
}
- //Still no dice? Die!
- _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs");
- return (X64Reg) -1;
+ }*/
+ //Find top regs - preload them (load bursts ain't bad)
+ //But only preload IF written OR reads >= 3
+}
+
+// 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!");
}
-
- void RegCache::SaveState()
+ 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++)
{
- memcpy(saved_locks, locks, sizeof(locks));
- memcpy(saved_xlocks, xlocks, sizeof(xlocks));
- memcpy(saved_regs, regs, sizeof(regs));
- memcpy(saved_xregs, xregs, sizeof(xregs));
+ X64Reg xr = (X64Reg)aOrder[i];
+ if (!xlocks[xr] && xregs[xr].free)
+ {
+ return (X64Reg)xr;
+ }
}
+ //Okay, not found :( Force grab one
- 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)
+ //TODO - add a pass to grab xregs whose ppcreg is not used in the next 3 instructions
+ for (int i = 0; i < aCount; i++)
{
- if (reg >= NUMXREGS)
- PanicAlert("Flushing non existent reg");
- if (!xregs[reg].free)
+ X64Reg xr = (X64Reg)aOrder[i];
+ if (xlocks[xr])
+ continue;
+ int preg = xregs[xr].ppcReg;
+ if (!locks[preg])
{
- StoreFromX64(xregs[reg].ppcReg);
+ StoreFromX64(preg);
+ return xr;
}
}
-
- void RegCache::SanityCheck() const
+ //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)
{
- 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");
- }
+ 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)
- {
- DiscardRegContentsIfCached(preg);
- regs[preg].away = true;
- regs[preg].location = Imm32(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 GPRRegCache::Start(PPCAnalyst::BlockRegStats &stats)
+{
+ RegCache::Start(stats);
+}
- void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats)
- {
- RegCache::Start(stats);
- }
+void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats)
+{
+ RegCache::Start(stats);
+}
- const int *GPRRegCache::GetAllocationOrder(int &count)
+const int *GPRRegCache::GetAllocationOrder(int &count)
+{
+ static const int allocationOrder[] =
{
- 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;
- }
-
- const int *FPURegCache::GetAllocationOrder(int &count)
+ };
+ count = sizeof(allocationOrder) / sizeof(const int);
+ return allocationOrder;
+}
+
+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;
- }
-
- OpArg GPRRegCache::GetDefaultLocation(int reg) const
+ };
+ count = sizeof(allocationOrder) / sizeof(int);
+ return allocationOrder;
+}
+
+OpArg GPRRegCache::GetDefaultLocation(int reg) const
+{
+ return M(&ppcState.gpr[reg]);
+}
+
+OpArg FPURegCache::GetDefaultLocation(int reg) const
+{
+ return M(&ppcState.ps[reg][0]);
+}
+
+void RegCache::KillImmediate(int preg)
+{
+ if (regs[preg].away && regs[preg].location.IsImm())
{
- return M(&ppcState.gpr[reg]);
+ LoadToX64(preg, true, true);
}
+}
- OpArg FPURegCache::GetDefaultLocation(int reg) const
- {
- return M(&ppcState.ps[reg][0]);
- }
+void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
+{
+ if (!regs[i].away && regs[i].location.IsImm())
+ PanicAlert("Bad immedaite");
- void RegCache::KillImmediate(int preg)
+ if (!regs[i].away || (regs[i].away && regs[i].location.IsImm()))
{
- if (regs[preg].away && regs[preg].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);
+ if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
+ {
+ Crash();
+ }
}
+ regs[i].away = true;
+ regs[i].location = newloc;
}
-
- void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
+ else
{
- if (!regs[i].away && regs[i].location.IsImm())
- PanicAlert("Bad immedaite");
+ // 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");
+ }
+}
- if (!regs[i].away || (regs[i].away && regs[i].location.IsImm()))
+void GPRRegCache::StoreFromX64(int i)
+{
+ if (regs[i].away)
+ {
+ bool doStore;
+ if (regs[i].location.IsSimpleReg())
{
- 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)
- {
- Crash();
- }
- }
- regs[i].away = true;
- regs[i].location = newloc;
+ 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)
{
- 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)
{
- bool doStore;
- if (regs[i].location.IsSimpleReg())
+ if (!regs[i].location.IsImm() && (regs[i].location.offset & 0xF))
{
- X64Reg xr = RX(i);
- xregs[xr].free = true;
- xregs[xr].ppcReg = -1;
- doStore = xregs[xr].dirty;
- xregs[xr].dirty = false;
- }
- else
- {
- //must be immediate - do nothing
- doStore = true;
+ PanicAlert("WARNING - misaligned fp register location %i", i);
}
- OpArg newLoc = GetDefaultLocation(i);
- // if (doStore) //<-- Breaks JIT compilation
- emit->MOV(32, newLoc, regs[i].location);
- regs[i].location = newLoc;
- regs[i].away = false;
+ 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::LoadToX64(int i, bool doLoad, bool makeDirty)
+void FPURegCache::StoreFromX64(int i)
+{
+ _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm");
+ if (regs[i].away)
{
- _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;
- }
+ 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;
}
-
- void FPURegCache::StoreFromX64(int i)
+ else
{
- _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");
- }
+ // _assert_msg_(DYNA_REC,0,"already stored");
}
+}
- void RegCache::Flush(FlushMode mode)
+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++)
{
- for (int i = 0; i < NUMXREGS; i++) {
- if (xlocks[i])
- PanicAlert("Somone forgot to unlock X64 reg %i.", i);
+ if (locks[i])
+ {
+ PanicAlert("Somebody forgot to unlock PPC reg %i.", i);
}
- for (int i = 0; i < 32; i++)
+ if (regs[i].away)
{
- if (locks[i])
+ if (regs[i].location.IsSimpleReg())
{
- PanicAlert("Somebody forgot to unlock PPC reg %i.", i);
+ X64Reg xr = RX(i);
+ StoreFromX64(i);
+ xregs[xr].dirty = false;
}
- if (regs[i].away)
+ else if (regs[i].location.IsImm())
{
- 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);
- }
+ StoreFromX64(i);
+ }
+ else
+ {
+ _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
- };
-
- enum GrabMode
- {
- M_READ = 1,
- M_WRITE = 2,
- M_READWRITE = 3,
- };
-
- struct PPCCachedReg
- {
- OpArg location;
- bool away; // value not in source register
- };
-
- struct X64CachedReg
- {
- int ppcReg;
- bool dirty;
- bool free;
- };
-
- typedef int XReg;
- typedef int PReg;
+using namespace Gen;
+enum FlushMode
+{
+ FLUSH_ALL
+};
+
+enum GrabMode
+{
+ M_READ = 1,
+ M_WRITE = 2,
+ M_READWRITE = 3,
+};
+
+struct PPCCachedReg
+{
+ OpArg location;
+ bool away; // value not in source register
+};
+
+struct X64CachedReg
+{
+ int ppcReg;
+ bool dirty;
+ bool free;
+};
+
+typedef int XReg;
+typedef int PReg;
#ifdef _M_X64
#define NUMXREGS 16
@@ -55,97 +55,96 @@
#define NUMXREGS 8
#endif
- 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
- {
- 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 FPURegCache : public 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
{
- 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;
- };
+ 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 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;
+ CMP(32, gpr.R(a), comparand);
+ gpr.UnlockAll();
- u32 destination;
+ u32 destination1;
if (js.next_inst.AA)
- destination = SignExt16(js.next_inst.BD << 2);
+ destination1 = SignExt16(js.next_inst.BD << 2);
else
- destination = js.next_compilerPC + SignExt16(js.next_inst.BD << 2);
+ 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;
- CMP(32, gpr.R(a), comparand);
- gpr.UnlockAll();
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