Merge pull request #7859 from hrydgard/arm64-minor

Arm64 minor optimizations
This commit is contained in:
Henrik Rydgård
2015-07-15 21:29:37 +02:00
6 changed files with 71 additions and 46 deletions
+17 -9
View File
@@ -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;
+19 -6
View File
@@ -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)) {
+4
View File
@@ -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;
}
+1
View File
@@ -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);
+24 -28
View File
@@ -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) {
+6 -3
View File
@@ -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();