[ARM] Add support for IMMs to the GPR reg cache. Not yet using it since it doesn't quite work

This commit is contained in:
Ryan Houdek 2013-08-05 05:26:21 +00:00
parent f485d96b0b
commit f2e43f47a4
4 changed files with 156 additions and 67 deletions

View File

@ -48,13 +48,8 @@ void JitArm::Init()
AllocCodeSpace(CODE_SIZE);
blocks.Init();
asm_routines.Init();
// TODO: Investigate why the register cache crashes when only doing Init with
// the pointer to this. Seems for some reason it doesn't set the emitter pointer
// In the class for some reason?
gpr.Init(this);
gpr.SetEmitter(this);
fpr.Init(this);
fpr.SetEmitter(this);
jo.enableBlocklink = true;
jo.optimizeGatherPipe = false;
}

View File

@ -33,7 +33,6 @@ void JitArm::mtspr(UGeckoInstruction inst)
JITDISABLE(SystemRegisters)
u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
ARMReg RD = gpr.R(inst.RD);
switch (iIndex)
{
@ -70,6 +69,7 @@ void JitArm::mtspr(UGeckoInstruction inst)
}
// OK, this is easy.
ARMReg RD = gpr.R(inst.RD);
STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4);
}
void JitArm::mftb(UGeckoInstruction inst)
@ -115,7 +115,6 @@ void JitArm::mfmsr(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(SystemRegisters)
Default(inst); return;
LDR(gpr.R(inst.RD), R9, PPCSTATE_OFF(msr));
}

View File

@ -28,13 +28,7 @@ void ArmRegCache::Init(ARMXEmitter *emitter)
emit = emitter;
ARMReg *PPCRegs = GetPPCAllocationOrder(NUMPPCREG);
ARMReg *Regs = GetAllocationOrder(NUMARMREG);
for(u8 a = 0; a < 32; ++a)
{
// This gives us the memory locations of the gpr registers so we can
// load them.
regs[a].location = (u8*)&PowerPC::ppcState.gpr[a];
regs[a].UsesLeft = 0;
}
for(u8 a = 0; a < NUMPPCREG; ++a)
{
ArmCRegs[a].PPCReg = 33;
@ -49,14 +43,8 @@ void ArmRegCache::Init(ARMXEmitter *emitter)
}
void ArmRegCache::Start(PPCAnalyst::BlockRegStats &stats)
{
for(u8 a = 0; a < NUMPPCREG; ++a)
{
ArmCRegs[a].PPCReg = 33;
ArmCRegs[a].LastLoad = 0;
}
for(u8 a = 0; a < 32; ++a)
regs[a].UsesLeft = stats.GetTotalNumAccesses(a);
}
ARMReg *ArmRegCache::GetPPCAllocationOrder(int &count)
{
// This will return us the allocation order of the registers we can use on
@ -94,16 +82,7 @@ ARMReg ArmRegCache::GetReg(bool AutoLock)
_assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb");
return R0;
}
void ArmRegCache::Lock(ARMReg Reg)
{
for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum)
if(ArmRegs[RegNum].Reg == Reg)
{
_assert_msg_(_DYNA_REC, ArmRegs[RegNum].free, "This register is already locked");
ArmRegs[RegNum].free = false;
}
_assert_msg_(_DYNA_REC, false, "Register %d can't be used with lock", Reg);
}
void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3)
{
for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum)
@ -118,51 +97,115 @@ void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3)
if( R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3) ArmRegs[RegNum].free = true;
}
}
ARMReg ArmRegCache::R(u32 preg)
u32 ArmRegCache::GetLeastUsedRegister(bool increment)
{
u32 HighestUsed = 0;
u8 Num = 0;
u8 lastRegIndex = 0;
for(u8 a = 0; a < NUMPPCREG; ++a){
++ArmCRegs[a].LastLoad;
if (increment)
++ArmCRegs[a].LastLoad;
if (ArmCRegs[a].LastLoad > HighestUsed)
{
HighestUsed = ArmCRegs[a].LastLoad;
Num = a;
lastRegIndex = a;
}
}
// Check if already Loaded
for(u8 a = 0; a < NUMPPCREG; ++a)
if (ArmCRegs[a].PPCReg == preg)
{
ArmCRegs[a].LastLoad = 0;
return ArmCRegs[a].Reg;
}
// Check if we have a free register
return lastRegIndex;
}
bool ArmRegCache::FindFreeRegister(u32 &regindex)
{
for (u8 a = 0; a < NUMPPCREG; ++a)
if (ArmCRegs[a].PPCReg == 33)
{
emit->LDR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
ArmCRegs[a].PPCReg = preg;
ArmCRegs[a].LastLoad = 0;
return ArmCRegs[a].Reg;
regindex = a;
return true;
}
return false;
}
ARMReg ArmRegCache::R(u32 preg)
{
if (regs[preg].GetType() == REG_IMM)
{
return BindToRegister(preg);
//asm ("bkpt #1;");
}
u32 lastRegIndex = GetLeastUsedRegister(true);
// Check if already Loaded
if(regs[preg].GetType() == REG_REG)
{
u8 a = regs[preg].GetRegIndex();
ArmCRegs[a].LastLoad = 0;
return ArmCRegs[a].Reg;
}
// Check if we have a free register
u32 regindex;
if (FindFreeRegister(regindex))
{
emit->LDR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
ArmCRegs[regindex].PPCReg = preg;
ArmCRegs[regindex].LastLoad = 0;
regs[preg].LoadToReg(regindex);
return ArmCRegs[regindex].Reg;
}
// Alright, we couldn't get a free space, dump that least used register
emit->STR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[Num].PPCReg * 4);
emit->LDR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
ArmCRegs[Num].PPCReg = preg;
ArmCRegs[Num].LastLoad = 0;
return ArmCRegs[Num].Reg;
emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4);
emit->LDR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4);
regs[ArmCRegs[lastRegIndex].PPCReg].Flush();
ArmCRegs[lastRegIndex].PPCReg = preg;
ArmCRegs[lastRegIndex].LastLoad = 0;
regs[preg].LoadToReg(lastRegIndex);
return ArmCRegs[lastRegIndex].Reg;
}
ARMReg ArmRegCache::BindToRegister(u32 preg)
{
_assert_msg_(DYNA_REC, regs[preg].GetType() == REG_IMM, "Can't BindToRegister with a REG");
u32 lastRegIndex = GetLeastUsedRegister(false);
u32 freeRegIndex;
if (FindFreeRegister(freeRegIndex))
{
emit->MOVI2R(ArmCRegs[freeRegIndex].Reg, regs[preg].GetImm());
ArmCRegs[freeRegIndex].PPCReg = preg;
ArmCRegs[freeRegIndex].LastLoad = 0;
regs[preg].LoadToReg(freeRegIndex);
return ArmCRegs[freeRegIndex].Reg;
}
else
{
emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4);
emit->MOVI2R(ArmCRegs[lastRegIndex].Reg, regs[preg].GetImm());
ArmCRegs[lastRegIndex].PPCReg = preg;
ArmCRegs[lastRegIndex].LastLoad = 0;
regs[preg].LoadToReg(lastRegIndex);
return ArmCRegs[lastRegIndex].Reg;
}
}
void ArmRegCache::Flush()
{
for(u8 a = 0; a < NUMPPCREG; ++a)
if (ArmCRegs[a].PPCReg != 33)
for (u8 a = 0; a < 32; ++a)
{
if (regs[a].GetType() == REG_IMM)
BindToRegister(a);
if (regs[a].GetType() == REG_REG)
{
emit->STR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[a].PPCReg * 4);
ArmCRegs[a].PPCReg = 33;
ArmCRegs[a].LastLoad = 0;
u32 regindex = regs[a].GetRegIndex();
emit->STR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + a * 4);
ArmCRegs[regindex].PPCReg = 33;
ArmCRegs[regindex].LastLoad = 0;
}
regs[a].Flush();
}
}

View File

@ -35,11 +35,61 @@ using namespace ArmGen;
// it
// So we have R14, R12, R11, R10 to work with instructions
struct PPCCachedReg
enum RegType
{
const u8 *location;
u32 UsesLeft;
REG_NOTLOADED = 0,
REG_REG,
REG_IMM,
};
class OpArg
{
private:
class Reg{
public:
RegType m_type;
u8 m_reg; // index to register
u32 m_value;
Reg()
{
m_type = REG_NOTLOADED;
m_reg = 33;
m_value = 0;
}
} Reg;
public:
OpArg(){}
RegType GetType()
{
return Reg.m_type;
}
u8 GetRegIndex()
{
return Reg.m_reg;
}
u32 GetImm()
{
return Reg.m_value;
}
void LoadToReg(u8 reg)
{
Reg.m_type = REG_REG;
Reg.m_reg = reg;
}
void LoadToImm(u32 imm)
{
Reg.m_type = REG_IMM;
Reg.m_value = imm;
}
void Flush()
{
Reg.m_type = REG_NOTLOADED;
}
};
struct JRCPPC
{
u32 PPCReg; // Tied to which PPC Register
@ -55,7 +105,7 @@ struct JRCReg
class ArmRegCache
{
private:
PPCCachedReg regs[32];
OpArg regs[32];
JRCPPC ArmCRegs[ARMREGS];
JRCReg ArmRegs[ARMREGS]; // Four registers remaining
@ -64,7 +114,9 @@ private:
ARMReg *GetAllocationOrder(int &count);
ARMReg *GetPPCAllocationOrder(int &count);
u32 GetLeastUsedRegister(bool increment);
bool FindFreeRegister(u32 &regindex);
protected:
ARMXEmitter *emit;
@ -74,16 +126,16 @@ public:
void Init(ARMXEmitter *emitter);
void Start(PPCAnalyst::BlockRegStats &stats);
void SetEmitter(ARMXEmitter *emitter) {emit = emitter;}
ARMReg GetReg(bool AutoLock = true); // Return a ARM register we can use.
void Lock(ARMReg reg);
void Unlock(ARMReg R0, ARMReg R1 = INVALID_REG, ARMReg R2 = INVALID_REG, ARMReg R3 =
INVALID_REG);
void Flush();
ARMReg R(u32 preg); // Returns a cached register
bool IsImm(u32 preg) { return regs[preg].GetType() == REG_IMM; }
u32 GetImm(u32 preg) { return regs[preg].GetImm(); }
void SetImmediate(u32 preg, u32 imm) { regs[preg].LoadToImm(imm); }
ARMReg BindToRegister(u32 preg);
};