armjit: Flush regs using STMIA where possible.

This commit is contained in:
Unknown W. Brackets 2013-11-08 21:57:27 -08:00
parent e686ff59bf
commit 6038d96b46
4 changed files with 99 additions and 1 deletions

View file

@ -922,6 +922,15 @@ void ARMXEmitter::LDM(ARMReg dest, bool Add, bool Before, bool WriteBack, const
WriteRegStoreOp(0x80 | (Before << 4) | (Add << 3) | 1, dest, WriteBack, RegList); WriteRegStoreOp(0x80 | (Before << 4) | (Add << 3) | 1, dest, WriteBack, RegList);
} }
void ARMXEmitter::STMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack, const u16 RegList)
{
WriteRegStoreOp(0x80 | (Before << 4) | (Add << 3) | 0, dest, WriteBack, RegList);
}
void ARMXEmitter::LDMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack, const u16 RegList)
{
WriteRegStoreOp(0x80 | (Before << 4) | (Add << 3) | 1, dest, WriteBack, RegList);
}
#undef VA_TO_REGLIST #undef VA_TO_REGLIST
ARMReg ARMXEmitter::SubBase(ARMReg Reg) ARMReg ARMXEmitter::SubBase(ARMReg Reg)

View file

@ -528,6 +528,8 @@ public:
void LDMIA(ARMReg dest, bool WriteBack, const int Regnum, ...); void LDMIA(ARMReg dest, bool WriteBack, const int Regnum, ...);
void STM(ARMReg dest, bool Add, bool Before, bool WriteBack, const int Regnum, ...); void STM(ARMReg dest, bool Add, bool Before, bool WriteBack, const int Regnum, ...);
void LDM(ARMReg dest, bool Add, bool Before, bool WriteBack, const int Regnum, ...); void LDM(ARMReg dest, bool Add, bool Before, bool WriteBack, const int Regnum, ...);
void STMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack, const u16 RegList);
void LDMBitmask(ARMReg dest, bool Add, bool Before, bool WriteBack, const u16 RegList);
// Exclusive Access operations // Exclusive Access operations
void LDREX(ARMReg dest, ARMReg base); void LDREX(ARMReg dest, ARMReg base);

View file

@ -312,9 +312,95 @@ void ArmRegCache::FlushR(MIPSGPReg r) {
mr[r].imm = 0; mr[r].imm = 0;
} }
// Note: if allowFlushImm is set, this also flushes imms while checking the sequence.
int ArmRegCache::FlushGetSequential(MIPSGPReg startMipsReg, bool allowFlushImm) {
// Only start a sequence on a dirty armreg.
// TODO: Could also start with an imm?
const auto &startMipsInfo = mr[startMipsReg];
if (startMipsInfo.loc != ML_ARMREG || startMipsInfo.reg == INVALID_REG || !ar[startMipsInfo.reg].isDirty) {
return 0;
}
int allocCount;
const ARMReg *allocOrder = GetMIPSAllocationOrder(allocCount);
int c = 1;
// The sequence needs to have ascending arm regs for STMIA.
int lastArmReg = startMipsInfo.reg;
// Can't use HI/LO, only regs in the main r[] array.
for (int r = (int)startMipsReg + 1; r < 32; ++r) {
if (mr[r].loc == ML_ARMREG && mr[r].reg != INVALID_REG) {
if ((int)mr[r].reg > lastArmReg && ar[mr[r].reg].isDirty) {
++c;
lastArmReg = mr[r].reg;
continue;
}
// If we're not allowed to flush imms, don't even consider them.
} else if (allowFlushImm && mr[r].loc == ML_IMM && MIPSGPReg(r) != MIPS_REG_ZERO) {
// Okay, let's search for a free (and later) reg to put this imm into.
bool found = false;
for (int j = 0; j < allocCount; ++j) {
ARMReg immReg = allocOrder[j];
if ((int)immReg > lastArmReg && ar[immReg].mipsReg == MIPS_REG_INVALID) {
++c;
lastArmReg = immReg;
// Even if the sequence fails, we'll need it in a reg anyway, might as well be this one.
MapRegTo(immReg, MIPSGPReg(r), 0);
found = true;
break;
}
}
if (found) {
continue;
}
}
// If it didn't hit a continue above, the chain is over.
// There's no way to skip a slot with STMIA.
break;
}
return c;
}
void ArmRegCache::FlushAll() { void ArmRegCache::FlushAll() {
// Let's try to put things in order and use STMIA.
// First we have to save imms. We have to use a separate loop because otherwise
// we would overwrite existing regs, and other code assumes FlushAll() won't do that.
for (int i = 0; i < NUM_MIPSREG; i++) { for (int i = 0; i < NUM_MIPSREG; i++) {
FlushR(MIPSGPReg(i)); MIPSGPReg mipsReg = MIPSGPReg(i);
// This happens to also flush imms to regs as much as possible.
int c = FlushGetSequential(mipsReg, true);
if (c >= 2) {
i += c - 1;
}
}
// Okay, now the real deal: this time NOT flushing imms.
for (int i = 0; i < NUM_MIPSREG; i++) {
MIPSGPReg mipsReg = MIPSGPReg(i);
int c = FlushGetSequential(mipsReg, false);
// ADD + STMIA is probably better than STR + STR.
if (c >= 2) {
u16 regs = 0;
for (int j = 0; j < c; ++j) {
regs |= 1 << mr[i + j].reg;
}
emit_->ADD(R0, CTXREG, GetMipsRegOffset(mipsReg));
emit_->STMBitmask(R0, true, false, false, regs);
// Okay, those are all done now, discard them.
for (int j = 0; j < c; ++j) {
DiscardR(MIPSGPReg(i + j));
}
i += c - 1;
} else {
FlushR(mipsReg);
}
} }
// Sanity check // Sanity check
for (int i = 0; i < NUM_ARMREG; i++) { for (int i = 0; i < NUM_ARMREG; i++) {

View file

@ -117,6 +117,7 @@ public:
private: private:
const ARMReg *GetMIPSAllocationOrder(int &count); const ARMReg *GetMIPSAllocationOrder(int &count);
void MapRegTo(ARMReg reg, MIPSGPReg mipsReg, int mapFlags); void MapRegTo(ARMReg reg, MIPSGPReg mipsReg, int mapFlags);
int FlushGetSequential(MIPSGPReg startMipsReg, bool allowFlushImm);
MIPSState *mips_; MIPSState *mips_;
MIPSComp::ArmJitOptions *options_; MIPSComp::ArmJitOptions *options_;