JitIL doesn't use JitRegCache; get rid of it.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3590 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
magumagu9 2009-06-29 01:21:55 +00:00
parent 449f075fd6
commit 188fa9b2cb
15 changed files with 5 additions and 569 deletions

View File

@ -46,7 +46,10 @@ The register allocation is just a simple forward greedy allocator.
#include "Jit.h"
#include "../../HW/GPFifo.h"
#include "../../Core.h"
#include "x64Emitter.h"
using namespace IREmitter;
using namespace Gen;
struct RegInfo {
Jit64* Jit;

View File

@ -34,7 +34,6 @@
#include "Jit.h"
#include "JitAsm.h"
#include "../JitCommon/JitCache.h"
#include "JitRegCache.h"
#if !defined JITTEST || ! JITTEST
#error JitIL needs JITTEST define
@ -197,9 +196,6 @@ void Jit64::Init()
jo.fastInterrupts = false;
jo.accurateSinglePrecision = false;
gpr.SetEmitter(this);
fpr.SetEmitter(this);
trampolines.Init();
AllocCodeSpace(CODE_SIZE);
@ -226,8 +222,6 @@ void Jit64::Shutdown()
void Jit64::WriteCallInterpreter(UGeckoInstruction inst)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
if (js.isLastInstruction)
{
MOV(32, M(&PC), Imm32(js.compilerPC));
@ -257,8 +251,6 @@ void Jit64::Default(UGeckoInstruction _inst)
void Jit64::HLEFunction(UGeckoInstruction _inst)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
MOV(32, R(EAX), M(&NPC));
WriteExitDestInEAX(0);

View File

@ -32,11 +32,6 @@
#include "../PPCAnalyst.h"
#include "../JitCommon/JitCache.h"
#if JITTEST
#include "../Jit64IL/JitRegCache.h"
#else
#include "../Jit64/JitRegCache.h"
#endif
#include "x64Emitter.h"
#include "x64Analyzer.h"
#include "IR.h"
@ -134,8 +129,6 @@ private:
JitBlockCache blocks;
TrampolineCache trampolines;
GPRRegCache gpr;
FPURegCache fpr;
// The default code buffer. We keep it around to not have to alloc/dealloc a
// large chunk of memory for each recompiled block.

View File

@ -1,394 +0,0 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// 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"
#include "Jit.h"
#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)
{
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)
{
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++)
{
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)
{
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;
}
}
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[] =
{
#ifdef _M_X64
#ifdef _WIN32
RSI, RDI, R13, R14, R8, R9, R10, R11 //, RCX
#else
RBP, R13, R14, R8, R9, R10, R11, //, RCX
#endif
#elif _M_IX86
ESI, EDI, EBX, EBP, EDX, ECX,
#endif
};
count = sizeof(allocationOrder) / sizeof(const int);
return allocationOrder;
}
const int *FPURegCache::GetAllocationOrder(int &count)
{
static const int allocationOrder[] =
{
#ifdef _M_X64
XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5
#elif _M_IX86
XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
#endif
};
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())
{
LoadToX64(preg, true, true);
}
}
void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
{
PanicAlert("BADNESS!");
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)
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;
}
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
{
//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);
}
}
}
}

View File

@ -1,150 +0,0 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _JITREGCACHE_H
#define _JITREGCACHE_H
#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;
#ifdef _M_X64
#define NUMXREGS 16
#elif _M_IX86
#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
{
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

View File

@ -24,7 +24,6 @@
#include "x64Emitter.h"
#include "Jit.h"
#include "JitRegCache.h"
#include "JitAsm.h"
#include "../../HW/Memmap.h"

View File

@ -23,7 +23,6 @@
#include "x64Emitter.h"
#include "Jit.h"
#include "JitRegCache.h"
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

View File

@ -25,7 +25,6 @@
#include "x64Emitter.h"
#include "Jit.h"
#include "JitRegCache.h"
#include "JitAsm.h"
//#define INSTRUCTION_START Default(inst); return;

View File

@ -33,7 +33,6 @@
#include "Jit.h"
#include "JitAsm.h"
#include "JitRegCache.h"
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

View File

@ -33,7 +33,6 @@
#include "Jit.h"
#include "JitAsm.h"
#include "JitRegCache.h"
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

View File

@ -34,7 +34,6 @@
#include "Jit.h"
#include "JitAsm.h"
#include "JitRegCache.h"
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

View File

@ -24,7 +24,6 @@
#include "../../HW/GPFifo.h"
#include "Jit.h"
#include "JitRegCache.h"
void Jit64::ps_mr(UGeckoInstruction inst)
{

View File

@ -27,7 +27,6 @@
#include "Thunk.h"
#include "Jit.h"
#include "JitRegCache.h"
//#define INSTRUCTION_START Default(inst); return;
#define INSTRUCTION_START

View File

@ -32,7 +32,6 @@
#include "../Jit64IL/Jit.h"
#include "JitCache.h"
#include "../Jit64IL/JitAsm.h"
#include "../Jit64IL/JitRegCache.h"
#else
#include "../Jit64/Jit.h"
#include "JitCache.h"
@ -40,6 +39,8 @@
#include "../Jit64/JitRegCache.h"
#endif
using namespace Gen;
void Jit64::JitClearCA()
{
AND(32, M(&PowerPC::ppcState.spr[SPR_XER]), Imm32(~XER_CA_MASK)); //XER.CA = 0

View File

@ -92,7 +92,6 @@ files = ["ActionReplay.cpp",
if env['JITTEST']:
files += ["PowerPC/Jit64IL/Jit.cpp",
"PowerPC/Jit64IL/JitRegCache.cpp",
"PowerPC/Jit64IL/JitAsm.cpp",
"PowerPC/Jit64IL/Jit_Branch.cpp",
"PowerPC/Jit64IL/Jit_Integer.cpp",