mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-26 14:26:23 +02:00
Merge pull request #7859 from hrydgard/arm64-minor
Arm64 minor optimizations
This commit is contained in:
@@ -350,17 +350,25 @@ namespace MIPSComp {
|
||||
(dataSize == 1 || (offset & (dataSize - 1)) == 0)) { // Check that the offset is aligned to the access size as that's required for INDEX_UNSIGNED encodings. we can get here through fallback from lwl/lwr
|
||||
gpr.SpillLock(rs, rt);
|
||||
gpr.MapRegAsPointer(rs);
|
||||
gpr.MapReg(rt, load ? MAP_NOINIT : 0);
|
||||
|
||||
Arm64Gen::ARM64Reg ar;
|
||||
if (gpr.IsImm(rt) && gpr.GetImm(rt) == 0) {
|
||||
// Can just store from the zero register directly.
|
||||
ar = WZR;
|
||||
} else {
|
||||
gpr.MapReg(rt, load ? MAP_NOINIT : 0);
|
||||
ar = gpr.R(rt);
|
||||
}
|
||||
switch (o) {
|
||||
case 35: LDR(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 37: LDRH(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 33: LDRSH(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 36: LDRB(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 32: LDRSB(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 35: LDR(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
case 37: LDRH(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
case 33: LDRSH(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
case 36: LDRB(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
case 32: LDRSB(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
// Store
|
||||
case 43: STR(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 41: STRH(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 40: STRB(INDEX_UNSIGNED, gpr.R(rt), gpr.RPtr(rs), offset); break;
|
||||
case 43: STR(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
case 41: STRH(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
case 40: STRB(INDEX_UNSIGNED, ar, gpr.RPtr(rs), offset); break;
|
||||
}
|
||||
gpr.ReleaseSpillLocks();
|
||||
break;
|
||||
|
||||
@@ -929,9 +929,14 @@ namespace MIPSComp {
|
||||
// rt = 0, imm = 255 appears to be used as a CPU interlock by some games.
|
||||
if (rt != 0) {
|
||||
if (imm < 128) { //R(rt) = VI(imm);
|
||||
fpr.MapRegV(imm, 0);
|
||||
gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY);
|
||||
fp.FMOV(gpr.R(rt), fpr.V(imm));
|
||||
if (!fpr.IsInRAMV(imm)) {
|
||||
fpr.MapRegV(imm, 0);
|
||||
gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY);
|
||||
fp.FMOV(gpr.R(rt), fpr.V(imm));
|
||||
} else {
|
||||
gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY);
|
||||
LDR(INDEX_UNSIGNED, gpr.R(rt), CTXREG, fpr.GetMipsRegOffsetV(imm));
|
||||
}
|
||||
} else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc
|
||||
if (imm - 128 == VFPU_CTRL_CC) {
|
||||
if (gpr.IsImm(MIPS_REG_VFPUCC)) {
|
||||
@@ -955,9 +960,17 @@ namespace MIPSComp {
|
||||
|
||||
case 7: // mtv
|
||||
if (imm < 128) {
|
||||
gpr.MapReg(rt);
|
||||
fpr.MapRegV(imm, MAP_DIRTY | MAP_NOINIT);
|
||||
fp.FMOV(fpr.V(imm), gpr.R(rt));
|
||||
if (rt == MIPS_REG_ZERO) {
|
||||
fpr.MapRegV(imm, MAP_DIRTY | MAP_NOINIT);
|
||||
fp.MOVI2F(fpr.V(imm), 0.0f, SCRATCH1);
|
||||
} else if (!gpr.IsInRAM(rt)) {
|
||||
gpr.MapReg(rt);
|
||||
fpr.MapRegV(imm, MAP_DIRTY | MAP_NOINIT);
|
||||
fp.FMOV(fpr.V(imm), gpr.R(rt));
|
||||
} else {
|
||||
fpr.MapRegV(imm, MAP_DIRTY | MAP_NOINIT);
|
||||
fp.LDR(32, INDEX_UNSIGNED, fpr.V(imm), CTXREG, gpr.GetMipsRegOffset(rt));
|
||||
}
|
||||
} else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc //currentMIPS->vfpuCtrl[imm - 128] = R(rt);
|
||||
if (imm - 128 == VFPU_CTRL_CC) {
|
||||
if (gpr.IsImm(rt)) {
|
||||
|
||||
@@ -134,6 +134,10 @@ void Arm64RegCache::FlushBeforeCall() {
|
||||
FlushArmReg(W30);
|
||||
}
|
||||
|
||||
bool Arm64RegCache::IsInRAM(MIPSGPReg reg) {
|
||||
return mr[reg].loc == ML_MEM;
|
||||
}
|
||||
|
||||
bool Arm64RegCache::IsMapped(MIPSGPReg mipsReg) {
|
||||
return mr[mipsReg].loc == ML_ARMREG || mr[mipsReg].loc == ML_ARMREG_IMM;
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ public:
|
||||
|
||||
bool IsMapped(MIPSGPReg reg);
|
||||
bool IsMappedAsPointer(MIPSGPReg reg);
|
||||
bool IsInRAM(MIPSGPReg reg);
|
||||
|
||||
void MarkDirty(Arm64Gen::ARM64Reg reg);
|
||||
void MapIn(MIPSGPReg rs);
|
||||
|
||||
@@ -62,41 +62,33 @@ void Arm64RegCacheFPU::SetupInitialRegs() {
|
||||
}
|
||||
|
||||
const ARM64Reg *Arm64RegCacheFPU::GetMIPSAllocationOrder(int &count) {
|
||||
// VFP mapping
|
||||
// VFPU registers and regular FP registers are mapped interchangably on top of the standard
|
||||
// 16 FPU registers.
|
||||
// On ARM64, all 32 registers are fully 128-bit and fully interchangable so we don't
|
||||
// have to care about upper or lower registers. However, only S8-S15 are callee-save, and
|
||||
// only the bottom 64 bits of those. So we should allocate into these when we call
|
||||
// C functions, although we don't currently do so...
|
||||
|
||||
// NEON mapping
|
||||
// We map FPU and VFPU registers entirely separately. FPU is mapped to 12 of the bottom 16 S registers.
|
||||
// VFPU is mapped to the upper 48 regs, 32 of which can only be reached through NEON
|
||||
// (or D16-D31 as doubles, but not relevant).
|
||||
// Might consider shifting the split in the future, giving more regs to NEON allowing it to map more quads.
|
||||
|
||||
// We should attempt to map scalars to low Q registers and wider things to high registers,
|
||||
// as the NEON instructions are all 2-vector or 4-vector, they don't do scalar, we want to be
|
||||
// able to use regular VFP instructions too.
|
||||
static const ARM64Reg allocationOrder[] = {
|
||||
// Reserve four temp registers. Useful when building quads until we really figure out
|
||||
// how to do that best. Note that we avoid the callee-save registers for now.
|
||||
S4, S5, S6, S7, // Q1
|
||||
S16, S17, S18, S19, // Q4
|
||||
S20, S21, S22, S23, // Q5
|
||||
S24, S25, S26, S27, // Q6
|
||||
S28, S29, S30, S31, // Q7
|
||||
// Q8-Q15 free for NEON tricks
|
||||
// Reserve four full 128-bit temp registers, should be plenty.
|
||||
S4, S5, S6, S7,
|
||||
S8, S9, S10, S11, // Partially callee-save (bottom 64 bits)
|
||||
S12, S13, S14, S15, // Partially callee-save (bottom 64 bits)
|
||||
S16, S17, S18, S19,
|
||||
S20, S21, S22, S23,
|
||||
S24, S25, S26, S27,
|
||||
S28, S29, S30, S31,
|
||||
};
|
||||
|
||||
static const ARM64Reg allocationOrderNEONVFPU[] = {
|
||||
// Reserve four temp registers. Useful when building quads until we really figure out
|
||||
// how to do that best.
|
||||
S4, S5, S6, S7, // Q1
|
||||
S8, S9, S10, S11, // Q2
|
||||
S12, S13, S14, S15, // Q3
|
||||
// Q4-Q15 free for VFPU
|
||||
// Reserve four full 128-bit temp registers, should be plenty.
|
||||
|
||||
// Then let's use 12 register as singles
|
||||
S4, S5, S6, S7,
|
||||
S8, S9, S10, S11,
|
||||
S12, S13, S14, S15,
|
||||
|
||||
// And do quads in the rest? Or use a strategy more similar to what we do on x86?
|
||||
};
|
||||
|
||||
// NOTE: It's important that S2/S3 are not allocated with bNEON, even if !useNEONVFPU.
|
||||
// They are used by a few instructions, like vh2f.
|
||||
if (jo_->useASIMDVFPU) {
|
||||
count = sizeof(allocationOrderNEONVFPU) / sizeof(const ARM64Reg);
|
||||
return allocationOrderNEONVFPU;
|
||||
@@ -110,6 +102,10 @@ bool Arm64RegCacheFPU::IsMapped(MIPSReg r) {
|
||||
return mr[r].loc == ML_ARMREG;
|
||||
}
|
||||
|
||||
bool Arm64RegCacheFPU::IsInRAM(MIPSReg r) {
|
||||
return mr[r].loc == ML_MEM;
|
||||
}
|
||||
|
||||
ARM64Reg Arm64RegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) {
|
||||
// INFO_LOG(JIT, "FPR MapReg: %i flags=%i", mipsReg, mapFlags);
|
||||
if (jo_->useASIMDVFPU && mipsReg >= 32) {
|
||||
|
||||
@@ -114,6 +114,9 @@ public:
|
||||
void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true);
|
||||
void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
|
||||
bool IsMapped(MIPSReg r);
|
||||
bool IsMappedV(MIPSReg r) { return IsMapped((MIPSReg)(r + 32)); }
|
||||
bool IsInRAM(MIPSReg r);
|
||||
bool IsInRAMV(MIPSReg r) { return IsInRAM((MIPSReg)(r + 32)); }
|
||||
void FlushArmReg(Arm64Gen::ARM64Reg r);
|
||||
void FlushR(MIPSReg r);
|
||||
void DiscardR(MIPSReg r);
|
||||
@@ -145,14 +148,14 @@ public:
|
||||
void SetEmitter(Arm64Gen::ARM64XEmitter *emitter, Arm64Gen::ARM64FloatEmitter *fp) { emit_ = emitter; fp_ = fp; }
|
||||
|
||||
int GetMipsRegOffset(MIPSReg r);
|
||||
int GetMipsRegOffsetV(MIPSReg r) {
|
||||
return GetMipsRegOffset(r + 32);
|
||||
}
|
||||
|
||||
private:
|
||||
Arm64Gen::ARM64Reg ARM64RegForFlush(int r);
|
||||
MIPSReg GetTempR();
|
||||
const Arm64Gen::ARM64Reg *GetMIPSAllocationOrder(int &count);
|
||||
int GetMipsRegOffsetV(MIPSReg r) {
|
||||
return GetMipsRegOffset(r + 32);
|
||||
}
|
||||
|
||||
void SetupInitialRegs();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user