mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
armjit: Flush regs using STMIA where possible.
This commit is contained in:
parent
e686ff59bf
commit
6038d96b46
4 changed files with 99 additions and 1 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
Loading…
Add table
Reference in a new issue