mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-10 22:49:00 +01:00
small build fix in debug mode, misc cleanup
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1604 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
4f4edc05a0
commit
f0bb8f430a
@ -189,6 +189,7 @@ namespace CPUCompare
|
|||||||
jo.fpAccurateFlags = true;
|
jo.fpAccurateFlags = true;
|
||||||
jo.optimizeGatherPipe = true;
|
jo.optimizeGatherPipe = true;
|
||||||
jo.fastInterrupts = false;
|
jo.fastInterrupts = false;
|
||||||
|
jo.accurateSinglePrecision = true;
|
||||||
|
|
||||||
gpr.SetEmitter(this);
|
gpr.SetEmitter(this);
|
||||||
fpr.SetEmitter(this);
|
fpr.SetEmitter(this);
|
||||||
@ -328,6 +329,9 @@ namespace CPUCompare
|
|||||||
if (emaddress == 0)
|
if (emaddress == 0)
|
||||||
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
||||||
|
|
||||||
|
// if (emaddress == 0x800aa278)
|
||||||
|
// DebugBreak();
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
js.isLastInstruction = false;
|
js.isLastInstruction = false;
|
||||||
js.blockStart = emaddress;
|
js.blockStart = emaddress;
|
||||||
@ -433,7 +437,8 @@ namespace CPUCompare
|
|||||||
CALL(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
CALL(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
PPCTables::CompileInstruction(ops[i].inst);
|
if (!ops[i].skip)
|
||||||
|
PPCTables::CompileInstruction(ops[i].inst);
|
||||||
|
|
||||||
gpr.SanityCheck();
|
gpr.SanityCheck();
|
||||||
fpr.SanityCheck();
|
fpr.SanityCheck();
|
||||||
|
@ -19,6 +19,14 @@
|
|||||||
// See comments in Jit.cpp.
|
// 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
|
#ifndef _JIT_H
|
||||||
#define _JIT_H
|
#define _JIT_H
|
||||||
|
|
||||||
@ -128,6 +136,7 @@ private:
|
|||||||
bool enableFastMem;
|
bool enableFastMem;
|
||||||
bool optimizeGatherPipe;
|
bool optimizeGatherPipe;
|
||||||
bool fastInterrupts;
|
bool fastInterrupts;
|
||||||
|
bool accurateSinglePrecision;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +70,6 @@ using namespace Gen;
|
|||||||
{
|
{
|
||||||
LOG(DYNA_REC, "JIT Statistics =======================");
|
LOG(DYNA_REC, "JIT Statistics =======================");
|
||||||
LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks);
|
LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks);
|
||||||
LOG(DYNA_REC, "Code cache size: %i b", GetCodePtr() - codeCache);
|
|
||||||
LOG(DYNA_REC, "======================================");
|
LOG(DYNA_REC, "======================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "../PowerPC.h"
|
#include "../PowerPC.h"
|
||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
@ -22,374 +23,371 @@
|
|||||||
#include "JitAsm.h"
|
#include "JitAsm.h"
|
||||||
#include "JitRegCache.h"
|
#include "JitRegCache.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
using namespace PowerPC;
|
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;
|
||||||
xregs[i].free = true;
|
xlocks[i] = false;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
// these are powerpc reg indices
|
|
||||||
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
|
||||||
{
|
{
|
||||||
locks[p1] = true;
|
regs[i].location = GetDefaultLocation(i);
|
||||||
if (p2 != 0xFF) locks[p2] = true;
|
regs[i].away = false;
|
||||||
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()
|
// todo: sort to find the most popular regs
|
||||||
|
/*
|
||||||
|
int maxPreload = 2;
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
{
|
{
|
||||||
int aCount;
|
if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2)
|
||||||
const int *aOrder = GetAllocationOrder(aCount);
|
|
||||||
for (int i = 0; i < aCount; i++)
|
|
||||||
{
|
{
|
||||||
X64Reg xr = (X64Reg)aOrder[i];
|
LoadToX64(i, true, false); //stats.firstRead[i] <= stats.firstWrite[i], false);
|
||||||
if (!xlocks[xr] && xregs[xr].free)
|
maxPreload--;
|
||||||
{
|
if (!maxPreload)
|
||||||
return (X64Reg)xr;
|
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
|
// these are powerpc reg indices
|
||||||
for (int i = 0; i < aCount; i++)
|
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];
|
return (X64Reg)xr;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//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++) {
|
X64Reg xr = (X64Reg)aOrder[i];
|
||||||
if (regs[i].away) {
|
if (xlocks[xr])
|
||||||
if (regs[i].location.IsSimpleReg()) {
|
continue;
|
||||||
Gen::X64Reg simple = regs[i].location.GetSimpleReg();
|
int preg = xregs[xr].ppcReg;
|
||||||
if (xlocks[simple]) {
|
if (!locks[preg])
|
||||||
PanicAlert("%08x : PPC Reg %i is in locked x64 register %i", /*js.compilerPC*/ 0, i, regs[i].location.GetSimpleReg());
|
{
|
||||||
}
|
StoreFromX64(preg);
|
||||||
if (xregs[simple].ppcReg != i) {
|
return xr;
|
||||||
PanicAlert("%08x : Xreg/ppcreg mismatch");
|
}
|
||||||
}
|
}
|
||||||
|
//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;
|
||||||
xregs[regs[preg].location.GetSimpleReg()].free = true;
|
regs[preg].away = false;
|
||||||
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 _M_X64
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
RSI, RDI, R12, R13, R14, R8, R9, R10, R11 //, RCX
|
RSI, RDI, R12, R13, R14, R8, R9, R10, R11 //, RCX
|
||||||
#else
|
#else
|
||||||
RBP, R12, R13, R14, R8, R9, R10, R11, //, RCX
|
RBP, R12, R13, R14, R8, R9, R10, R11, //, RCX
|
||||||
#endif
|
#endif
|
||||||
#elif _M_IX86
|
#elif _M_IX86
|
||||||
ESI, EDI, EBX, EBP, EDX, ECX,
|
ESI, EDI, EBX, EBP, EDX, ECX,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
count = sizeof(allocationOrder) / sizeof(const int);
|
count = sizeof(allocationOrder) / sizeof(const int);
|
||||||
return allocationOrder;
|
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
|
#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
|
#elif _M_IX86
|
||||||
XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
count = sizeof(allocationOrder) / sizeof(int);
|
count = sizeof(allocationOrder) / sizeof(int);
|
||||||
return allocationOrder;
|
return allocationOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpArg GPRRegCache::GetDefaultLocation(int reg) const
|
OpArg GPRRegCache::GetDefaultLocation(int reg) const
|
||||||
{
|
{
|
||||||
return M(&ppcState.gpr[reg]);
|
return M(&ppcState.gpr[reg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
OpArg FPURegCache::GetDefaultLocation(int reg) const
|
OpArg FPURegCache::GetDefaultLocation(int reg) const
|
||||||
{
|
{
|
||||||
return M(&ppcState.ps[reg][0]);
|
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);
|
if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
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
|
else
|
||||||
{
|
{
|
||||||
// reg location must be simplereg; memory locations
|
//must be immediate - do nothing
|
||||||
// and immediates are taken care of above.
|
doStore = true;
|
||||||
xregs[RX(i)].dirty |= makeDirty;
|
|
||||||
}
|
|
||||||
if (xlocks[RX(i)]) {
|
|
||||||
PanicAlert("Seriously WTF, this reg should have been flushed");
|
|
||||||
}
|
}
|
||||||
|
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)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
bool doStore;
|
|
||||||
if (regs[i].location.IsSimpleReg())
|
if (regs[i].location.IsSimpleReg())
|
||||||
{
|
{
|
||||||
X64Reg xr = RX(i);
|
X64Reg xr = RX(i);
|
||||||
xregs[xr].free = true;
|
StoreFromX64(i);
|
||||||
xregs[xr].ppcReg = -1;
|
|
||||||
doStore = xregs[xr].dirty;
|
|
||||||
xregs[xr].dirty = false;
|
xregs[xr].dirty = false;
|
||||||
}
|
}
|
||||||
|
else if (regs[i].location.IsImm())
|
||||||
|
{
|
||||||
|
StoreFromX64(i);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//must be immediate - do nothing
|
_assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i", i);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -20,34 +20,34 @@
|
|||||||
|
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
enum FlushMode
|
enum FlushMode
|
||||||
{
|
{
|
||||||
FLUSH_ALL
|
FLUSH_ALL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GrabMode
|
enum GrabMode
|
||||||
{
|
{
|
||||||
M_READ = 1,
|
M_READ = 1,
|
||||||
M_WRITE = 2,
|
M_WRITE = 2,
|
||||||
M_READWRITE = 3,
|
M_READWRITE = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PPCCachedReg
|
struct PPCCachedReg
|
||||||
{
|
{
|
||||||
OpArg location;
|
OpArg location;
|
||||||
bool away; // value not in source register
|
bool away; // value not in source register
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X64CachedReg
|
struct X64CachedReg
|
||||||
{
|
{
|
||||||
int ppcReg;
|
int ppcReg;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool free;
|
bool free;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int XReg;
|
typedef int XReg;
|
||||||
typedef int PReg;
|
typedef int PReg;
|
||||||
|
|
||||||
#ifdef _M_X64
|
#ifdef _M_X64
|
||||||
#define NUMXREGS 16
|
#define NUMXREGS 16
|
||||||
@ -55,97 +55,96 @@
|
|||||||
#define NUMXREGS 8
|
#define NUMXREGS 8
|
||||||
#endif
|
#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:
|
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
||||||
bool locks[32];
|
return regs[preg].location.GetSimpleReg();
|
||||||
bool saved_locks[32];
|
PanicAlert("Not so simple - %i", preg);
|
||||||
bool saved_xlocks[NUMXREGS];
|
return (X64Reg)-1;
|
||||||
|
}
|
||||||
|
virtual OpArg GetDefaultLocation(int reg) const = 0;
|
||||||
|
|
||||||
protected:
|
// Register locking.
|
||||||
bool xlocks[NUMXREGS];
|
void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff);
|
||||||
PPCCachedReg regs[32];
|
void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff);
|
||||||
X64CachedReg xregs[NUMXREGS];
|
void UnlockAll();
|
||||||
|
void UnlockAllX();
|
||||||
|
|
||||||
PPCCachedReg saved_regs[32];
|
bool IsFreeX(int xreg) const;
|
||||||
X64CachedReg saved_xregs[NUMXREGS];
|
|
||||||
|
|
||||||
void DiscardRegContentsIfCached(int preg);
|
X64Reg GetFreeXReg();
|
||||||
virtual const int *GetAllocationOrder(int &count) = 0;
|
|
||||||
|
|
||||||
XEmitter *emit;
|
|
||||||
|
|
||||||
public:
|
void SaveState();
|
||||||
virtual ~RegCache() {}
|
void LoadState();
|
||||||
virtual void Start(PPCAnalyst::BlockRegStats &stats) = 0;
|
};
|
||||||
|
|
||||||
void SetEmitter(XEmitter *emitter) {emit = emitter;}
|
class GPRRegCache : public RegCache
|
||||||
|
{
|
||||||
void FlushR(X64Reg reg);
|
public:
|
||||||
void FlushR(X64Reg reg, X64Reg reg2) {FlushR(reg); FlushR(reg2);}
|
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||||
void FlushLockX(X64Reg reg) {
|
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
||||||
FlushR(reg);
|
void StoreFromX64(int preg);
|
||||||
LockX(reg);
|
OpArg GetDefaultLocation(int reg) const;
|
||||||
}
|
const int *GetAllocationOrder(int &count);
|
||||||
void FlushLockX(X64Reg reg1, X64Reg reg2) {
|
void SetImmediate32(int preg, u32 immValue);
|
||||||
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 FPURegCache : public RegCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Start(PPCAnalyst::BlockRegStats &stats);
|
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||||
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
||||||
void StoreFromX64(int preg);
|
void StoreFromX64(int preg);
|
||||||
const int *GetAllocationOrder(int &count);
|
const int *GetAllocationOrder(int &count);
|
||||||
OpArg GetDefaultLocation(int reg) const;
|
OpArg GetDefaultLocation(int reg) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -202,6 +202,7 @@
|
|||||||
if (!merge_branch) {
|
if (!merge_branch) {
|
||||||
// Keep the normal code separate for clarity.
|
// Keep the normal code separate for clarity.
|
||||||
CMP(32, gpr.R(a), comparand);
|
CMP(32, gpr.R(a), comparand);
|
||||||
|
|
||||||
FixupBranch pLesser = J_CC(less_than);
|
FixupBranch pLesser = J_CC(less_than);
|
||||||
FixupBranch pGreater = J_CC(greater_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)); // _x86Reg == 0
|
||||||
@ -216,42 +217,45 @@
|
|||||||
} else {
|
} else {
|
||||||
int test_bit = 8 >> (js.next_inst.BI & 3);
|
int test_bit = 8 >> (js.next_inst.BI & 3);
|
||||||
bool condition = (js.next_inst.BO & 8) ? false : true;
|
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);
|
CMP(32, gpr.R(a), comparand);
|
||||||
gpr.UnlockAll();
|
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);
|
gpr.Flush(FLUSH_ALL);
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush(FLUSH_ALL);
|
||||||
FixupBranch pLesser = J_CC(less_than);
|
FixupBranch pLesser = J_CC(less_than);
|
||||||
FixupBranch pGreater = J_CC(greater_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();
|
FixupBranch continue1 = J();
|
||||||
|
|
||||||
SetJumpTarget(pGreater);
|
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();
|
FixupBranch continue2 = J();
|
||||||
|
|
||||||
SetJumpTarget(pLesser);
|
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;
|
FixupBranch continue3;
|
||||||
if (!!(8 & test_bit) == condition) continue3 = J();
|
if (!!(8 & test_bit) == condition) continue3 = J();
|
||||||
|
|
||||||
//if (!!(8 & test_bit) != condition) SetJumpTarget(continue3);
|
|
||||||
if (!!(4 & test_bit) != condition) SetJumpTarget(continue2);
|
if (!!(4 & test_bit) != condition) SetJumpTarget(continue2);
|
||||||
if (!!(2 & test_bit) != condition) SetJumpTarget(continue1);
|
if (!!(2 & test_bit) != condition) SetJumpTarget(continue1);
|
||||||
|
|
||||||
WriteExit(destination, 0);
|
WriteExit(destination1, 0);
|
||||||
|
|
||||||
if (!!(8 & test_bit) == condition) SetJumpTarget(continue3);
|
if (!!(8 & test_bit) == condition) SetJumpTarget(continue3);
|
||||||
if (!!(4 & test_bit) == condition) SetJumpTarget(continue2);
|
if (!!(4 & test_bit) == condition) SetJumpTarget(continue2);
|
||||||
if (!!(2 & test_bit) == condition) SetJumpTarget(continue1);
|
if (!!(2 & test_bit) == condition) SetJumpTarget(continue1);
|
||||||
|
|
||||||
WriteExit(js.next_compilerPC + 4, 1);
|
WriteExit(destination2, 1);
|
||||||
|
|
||||||
js.cancel = true;
|
js.cancel = true;
|
||||||
}
|
}
|
||||||
|
@ -139,11 +139,18 @@ void Jit64::WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address)
|
|||||||
|
|
||||||
void Jit64::ForceSinglePrecisionS(X64Reg xmm) {
|
void Jit64::ForceSinglePrecisionS(X64Reg xmm) {
|
||||||
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
||||||
CVTSD2SS(xmm, R(xmm));
|
if (jo.accurateSinglePrecision)
|
||||||
CVTSS2SD(xmm, R(xmm));
|
{
|
||||||
|
CVTSD2SS(xmm, R(xmm));
|
||||||
|
CVTSS2SD(xmm, R(xmm));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::ForceSinglePrecisionP(X64Reg xmm) {
|
void Jit64::ForceSinglePrecisionP(X64Reg xmm) {
|
||||||
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
||||||
CVTPD2PS(xmm, R(xmm));
|
if (jo.accurateSinglePrecision)
|
||||||
CVTPS2PD(xmm, R(xmm));
|
{
|
||||||
|
CVTPD2PS(xmm, R(xmm));
|
||||||
|
CVTPS2PD(xmm, R(xmm));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +313,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
|
|||||||
code[i].inst = inst;
|
code[i].inst = inst;
|
||||||
code[i].branchTo = -1;
|
code[i].branchTo = -1;
|
||||||
code[i].branchToIndex = -1;
|
code[i].branchToIndex = -1;
|
||||||
|
code[i].skip = false;
|
||||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||||
if (opinfo)
|
if (opinfo)
|
||||||
numCycles += opinfo->numCyclesMinusOne + 1;
|
numCycles += opinfo->numCyclesMinusOne + 1;
|
||||||
@ -345,6 +346,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
code[i].skip = true;
|
||||||
address = destination;
|
address = destination;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ struct CodeOp //16B
|
|||||||
bool outputCR0;
|
bool outputCR0;
|
||||||
bool outputCR1;
|
bool outputCR1;
|
||||||
bool outputPS1;
|
bool outputPS1;
|
||||||
|
bool skip; // followed BL-s for example
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlockStats
|
struct BlockStats
|
||||||
|
Loading…
x
Reference in New Issue
Block a user