ARM regcache: Add mechanism to keep registers converted to pointers around

This commit is contained in:
Henrik Rydgard 2013-11-09 15:24:06 +01:00
parent 5ad04a23f4
commit 58c39a38ee
2 changed files with 75 additions and 14 deletions

View file

@ -74,6 +74,32 @@ void ArmRegCache::FlushBeforeCall() {
FlushArmReg(R12);
}
ARMReg ArmRegCache::MapRegAsPointer(MIPSReg mipsReg) { // read-only, non-dirty.
// If already mapped as a pointer, bail.
if (mr[mipsReg].loc == ML_ARMREG_AS_PTR) {
return mr[mipsReg].reg;
}
// First, make sure the register is already mapped.
MapReg(mipsReg, 0);
// If it's dirty, flush it.
ARMReg armReg = mr[mipsReg].reg;
if (ar[armReg].isDirty) {
emit_->STR(armReg, CTXREG, GetMipsRegOffset(ar[armReg].mipsReg));
}
// Convert to a pointer by adding the base and clearing off the top bits.
// If SP, we can probably avoid the top bit clear, let's play with that later.
emit_->BIC(armReg, armReg, Operand2(0xC0, 4)); // &= 0x3FFFFFFF
emit_->ADD(armReg, R11, armReg);
ar[armReg].isDirty = false;
ar[armReg].mipsReg = mipsReg;
mr[mipsReg].loc = ML_ARMREG_AS_PTR;
return armReg;
}
bool ArmRegCache::IsMappedAsPointer(MIPSReg mipsReg) {
return mr[mipsReg].loc == ML_ARMREG_AS_PTR;
}
// TODO: Somewhat smarter spilling - currently simply spills the first available, should do
// round robin or FIFO or something.
ARMReg ArmRegCache::MapReg(MIPSReg mipsReg, int mapFlags) {
@ -81,11 +107,23 @@ ARMReg ArmRegCache::MapReg(MIPSReg mipsReg, int mapFlags) {
// We don't need to check for ML_NOINIT because we assume that anyone who maps
// with that flag immediately writes a "known" value to the register.
if (mr[mipsReg].loc == ML_ARMREG) {
if (ar[mr[mipsReg].reg].mipsReg != mipsReg) {
ARMReg armReg = mr[mipsReg].reg;
if (ar[armReg].mipsReg != mipsReg) {
ERROR_LOG(JIT, "Register mapping out of sync! %i", mipsReg);
}
if (mapFlags & MAP_DIRTY) {
ar[mr[mipsReg].reg].isDirty = true;
ar[armReg].isDirty = true;
}
return (ARMReg)mr[mipsReg].reg;
} else if (mr[mipsReg].loc == ML_ARMREG_AS_PTR) {
// Was mapped as pointer, now we want it mapped as a value, presumably to
// add or subtract stuff to it. Later we could allow such things but for now
// let's just convert back to a register value by reloading from the backing storage.
ARMReg armReg = mr[mipsReg].reg;
emit_->LDR(armReg, CTXREG, GetMipsRegOffset(mipsReg));
mr[mipsReg].loc = ML_ARMREG;
if (mapFlags & MAP_DIRTY) {
ar[armReg].isDirty = true;
}
return (ARMReg)mr[mipsReg].reg;
}
@ -200,14 +238,14 @@ void ArmRegCache::FlushArmReg(ARMReg r) {
ar[r].mipsReg = -1;
}
void ArmRegCache::DiscardR(MIPSReg r) {
if (mr[r].loc == ML_ARMREG) {
ARMReg a = mr[r].reg;
ar[a].isDirty = false;
ar[a].mipsReg = -1;
mr[r].reg = INVALID_REG;
mr[r].loc = ML_MEM;
mr[r].imm = 0;
void ArmRegCache::DiscardR(MIPSReg mipsReg) {
if (mr[mipsReg].loc == ML_ARMREG || mr[mipsReg].loc == ML_ARMREG_AS_PTR) {
ARMReg armReg = mr[mipsReg].reg;
ar[armReg].isDirty = false;
ar[armReg].mipsReg = -1;
mr[mipsReg].reg = INVALID_REG;
mr[mipsReg].loc = ML_MEM;
mr[mipsReg].imm = 0;
}
}
@ -234,6 +272,14 @@ void ArmRegCache::FlushR(MIPSReg r) {
ar[mr[r].reg].mipsReg = -1;
break;
case ML_ARMREG_AS_PTR:
// Never dirty.
if (ar[mr[r].reg].isDirty) {
ERROR_LOG(JIT, "ARMREG_AS_PTR cannot be dirty (yet)");
}
ar[mr[r].reg].mipsReg = -1;
break;
case ML_MEM:
// Already there, nothing to do.
break;
@ -264,7 +310,7 @@ void ArmRegCache::SetImm(MIPSReg r, u32 immVal) {
ERROR_LOG(JIT, "Trying to set immediate %08x to r0", immVal);
// Zap existing value if cached in a reg
if (mr[r].loc == ML_ARMREG) {
if (mr[r].loc == ML_ARMREG || mr[r].loc == ML_ARMREG_AS_PTR) {
ar[mr[r].reg].mipsReg = -1;
ar[mr[r].reg].isDirty = false;
}
@ -324,3 +370,13 @@ ARMReg ArmRegCache::R(int mipsReg) {
return INVALID_REG; // BAAAD
}
}
ARMReg ArmRegCache::RPtr(int mipsReg) {
if (mr[mipsReg].loc == ML_ARMREG_AS_PTR) {
return (ARMReg)mr[mipsReg].reg;
} else {
ERROR_LOG(JIT, "Reg %i not in arm reg as pointer. compilerPC = %08x", mipsReg, compilerPC_);
return INVALID_REG; // BAAAD
}
}

View file

@ -47,6 +47,7 @@ struct RegARM {
enum RegMIPSLoc {
ML_IMM,
ML_ARMREG,
ML_ARMREG_AS_PTR,
ML_MEM,
};
@ -72,8 +73,7 @@ namespace MIPSComp {
struct ArmJitOptions;
}
class ArmRegCache
{
class ArmRegCache {
public:
ArmRegCache(MIPSState *mips, MIPSComp::ArmJitOptions *options);
~ArmRegCache() {}
@ -93,6 +93,10 @@ public:
// Returns an ARM register containing the requested MIPS register.
ARMReg MapReg(MIPSReg reg, int mapFlags = 0);
ARMReg MapRegAsPointer(MIPSReg reg); // read-only, non-dirty.
bool IsMappedAsPointer(MIPSReg reg);
void MapInIn(MIPSReg rd, MIPSReg rs);
void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true);
void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
@ -103,7 +107,8 @@ public:
void FlushAll();
void DiscardR(MIPSReg r);
ARMReg R(int preg); // Returns a cached register
ARMReg R(int preg); // Returns a cached register, while checking that it's NOT mapped as a pointer
ARMReg RPtr(int preg); // Returns a cached register, while checking that it's mapped as a pointer
void SetEmitter(ARMXEmitter *emitter) { emit_ = emitter; }