Permalink
Browse files

Merge pull request #10476 from unknownbrackets/arm64-jit

Statically allocate RA in arm64jit
  • Loading branch information...
hrydgard committed Dec 30, 2017
2 parents 5531afb + 9ff812b commit f3ba54007809125505e389e4915a6a9c19db15fb
View
@@ -3736,6 +3736,7 @@ void ARM64XEmitter::CMPI2R(ARM64Reg Rn, u64 imm, ARM64Reg scratch) {
}
bool ARM64XEmitter::TryADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) {
s64 negated = Is64Bit(Rn) ? -(s64)imm : -(s32)(u32)imm;
u32 val;
bool shift;
if (imm == 0) {
@@ -3745,12 +3746,16 @@ bool ARM64XEmitter::TryADDI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) {
} else if (IsImmArithmetic(imm, &val, &shift)) {
ADD(Rd, Rn, val, shift);
return true;
} else if (IsImmArithmetic((u64)negated, &val, &shift)) {
SUB(Rd, Rn, val, shift);
return true;
} else {
return false;
}
}
bool ARM64XEmitter::TrySUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) {
s64 negated = Is64Bit(Rn) ? -(s64)imm : -(s32)(u32)imm;
u32 val;
bool shift;
if (imm == 0) {
@@ -3760,6 +3765,9 @@ bool ARM64XEmitter::TrySUBI2R(ARM64Reg Rd, ARM64Reg Rn, u64 imm) {
} else if (IsImmArithmetic(imm, &val, &shift)) {
SUB(Rd, Rn, val, shift);
return true;
} else if (IsImmArithmetic((u64)negated, &val, &shift)) {
ADD(Rd, Rn, val, shift);
return true;
} else {
return false;
}
@@ -90,11 +90,7 @@ void Arm64Jit::Comp_IType(MIPSOpcode op) {
ARM64Reg r32 = gpr.RPtr(rs);
gpr.MarkDirty(r32);
ARM64Reg r = EncodeRegTo64(r32);
if (simm > 0) {
ADDI2R(r, r, simm);
} else {
SUBI2R(r, r, -simm);
}
ADDI2R(r, r, simm);
} else {
if (simm >= 0) {
CompImmLogic(rs, rt, simm, &ARM64XEmitter::ADD, &ARM64XEmitter::TryADDI2R, &EvalAdd);
@@ -536,7 +536,7 @@ void Arm64Jit::Comp_JumpReg(MIPSOpcode op)
delaySlotIsNice = false;
CONDITIONAL_NICE_DELAYSLOT;
ARM64Reg destReg = OTHERTEMPREG;
ARM64Reg destReg = INVALID_REG;
if (IsSyscall(delaySlotOp)) {
gpr.MapReg(rs);
MovToPC(gpr.R(rs)); // For syscall to be able to return.
@@ -574,7 +574,9 @@ void Arm64Jit::Comp_JumpReg(MIPSOpcode op)
destReg = gpr.R(rs); // Safe because FlushAll doesn't change any regs
FlushAll();
} else {
// Delay slot - this case is very rare, might be able to free up W24.
// Since we can't be in a delay slot, should be safe to steal FLAGTEMPREG for a temp reg.
// It will be saved, even if a function is called.
destReg = FLAGTEMPREG;
gpr.MapReg(rs);
MOV(destReg, gpr.R(rs));
if (andLink)
@@ -250,7 +250,7 @@ namespace MIPSComp {
SetJumpTarget(skip);
}
gpr.ReleaseSpillLocks();
gpr.ReleaseSpillLocksAndDiscardTemps();
}
void Arm64Jit::Comp_ITypeMem(MIPSOpcode op) {
@@ -311,7 +311,7 @@ namespace MIPSComp {
gpr.MapRegAsPointer(rs);
// For a store, try to avoid mapping a reg if not needed.
targetReg = load ? INVALID_REG : gpr.MapTempImm(rt);
targetReg = load ? INVALID_REG : gpr.TryMapTempImm(rt);
if (targetReg == INVALID_REG) {
gpr.MapReg(rt, load ? MAP_NOINIT : 0);
targetReg = gpr.R(rt);
@@ -327,20 +327,20 @@ namespace MIPSComp {
case 41: STRH(INDEX_UNSIGNED, targetReg, gpr.RPtr(rs), offset); break;
case 40: STRB(INDEX_UNSIGNED, targetReg, gpr.RPtr(rs), offset); break;
}
gpr.ReleaseSpillLocks();
gpr.ReleaseSpillLocksAndDiscardTemps();
break;
}
}
if (!load && gpr.IsImm(rt) && gpr.MapTempImm(rt) != INVALID_REG) {
if (!load && gpr.IsImm(rt) && gpr.TryMapTempImm(rt) != INVALID_REG) {
// We're storing an immediate value, let's see if we can optimize rt.
if (!gpr.IsImm(rs) || offset == 0) {
// In this case, we're always going to need rs mapped, which may flush the temp imm.
// We handle that in the cases below since targetReg is INVALID_REG.
gpr.MapIn(rs);
}
targetReg = gpr.MapTempImm(rt);
targetReg = gpr.TryMapTempImm(rt);
}
if (gpr.IsImm(rs) && Memory::IsValidAddress(iaddr)) {
@@ -69,10 +69,10 @@ void Arm64RegCache::Start(MIPSAnalyst::AnalysisResults &stats) {
const ARM64Reg *Arm64RegCache::GetMIPSAllocationOrder(int &count) {
// See register alloc remarks in Arm64Asm.cpp
// W19-W22 are most suitable for static allocation. Those that are chosen for static allocation
// W19-W23 are most suitable for static allocation. Those that are chosen for static allocation
// should be omitted here and added in GetStaticAllocations.
static const ARM64Reg allocationOrder[] = {
W19, W20, W21, W22, W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15,
W19, W20, W21, W22, W23, W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15,
};
static const ARM64Reg allocationOrderStaticAlloc[] = {
W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15,
@@ -93,6 +93,7 @@ const Arm64RegCache::StaticAllocation *Arm64RegCache::GetStaticAllocations(int &
{MIPS_REG_V0, W20},
{MIPS_REG_V1, W22},
{MIPS_REG_A0, W21},
{MIPS_REG_RA, W23},
};
if (jo_->useStaticAlloc) {
@@ -304,7 +305,7 @@ ARM64Reg Arm64RegCache::FindBestToSpill(bool unusedOnly, bool *clobbered) {
return INVALID_REG;
}
ARM64Reg Arm64RegCache::MapTempImm(MIPSGPReg r) {
ARM64Reg Arm64RegCache::TryMapTempImm(MIPSGPReg r) {
// If already mapped, no need for a temporary.
if (IsMapped(r)) {
return R(r);
@@ -459,15 +460,15 @@ void Arm64RegCache::MapInIn(MIPSGPReg rd, MIPSGPReg rs) {
SpillLock(rd, rs);
MapReg(rd);
MapReg(rs);
ReleaseSpillLocks();
ReleaseSpillLock(rd, rs);
}
void Arm64RegCache::MapDirtyIn(MIPSGPReg rd, MIPSGPReg rs, bool avoidLoad) {
SpillLock(rd, rs);
bool load = !avoidLoad || rd == rs;
MapReg(rd, load ? MAP_DIRTY : MAP_NOINIT);
MapReg(rs);
ReleaseSpillLocks();
ReleaseSpillLock(rd, rs);
}
void Arm64RegCache::MapDirtyInIn(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, bool avoidLoad) {
@@ -476,7 +477,7 @@ void Arm64RegCache::MapDirtyInIn(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, bool
MapReg(rd, load ? MAP_DIRTY : MAP_NOINIT);
MapReg(rt);
MapReg(rs);
ReleaseSpillLocks();
ReleaseSpillLock(rd, rs, rt);
}
void Arm64RegCache::MapDirtyDirtyIn(MIPSGPReg rd1, MIPSGPReg rd2, MIPSGPReg rs, bool avoidLoad) {
@@ -486,7 +487,7 @@ void Arm64RegCache::MapDirtyDirtyIn(MIPSGPReg rd1, MIPSGPReg rd2, MIPSGPReg rs,
MapReg(rd1, load1 ? MAP_DIRTY : MAP_NOINIT);
MapReg(rd2, load2 ? MAP_DIRTY : MAP_NOINIT);
MapReg(rs);
ReleaseSpillLocks();
ReleaseSpillLock(rd1, rd2, rs);
}
void Arm64RegCache::MapDirtyDirtyInIn(MIPSGPReg rd1, MIPSGPReg rd2, MIPSGPReg rs, MIPSGPReg rt, bool avoidLoad) {
@@ -497,7 +498,7 @@ void Arm64RegCache::MapDirtyDirtyInIn(MIPSGPReg rd1, MIPSGPReg rd2, MIPSGPReg rs
MapReg(rd2, load2 ? MAP_DIRTY : MAP_NOINIT);
MapReg(rt);
MapReg(rs);
ReleaseSpillLocks();
ReleaseSpillLock(rd1, rd2, rs, rt);
}
void Arm64RegCache::FlushArmReg(ARM64Reg r) {
@@ -872,7 +873,7 @@ void Arm64RegCache::SpillLock(MIPSGPReg r1, MIPSGPReg r2, MIPSGPReg r3, MIPSGPRe
if (r4 != MIPS_REG_INVALID) mr[r4].spillLock = true;
}
void Arm64RegCache::ReleaseSpillLocks() {
void Arm64RegCache::ReleaseSpillLocksAndDiscardTemps() {
for (int i = 0; i < NUM_MIPSREG; i++) {
if (!mr[i].isStatic)
mr[i].spillLock = false;
@@ -882,9 +883,15 @@ void Arm64RegCache::ReleaseSpillLocks() {
}
}
void Arm64RegCache::ReleaseSpillLock(MIPSGPReg reg) {
if (!mr[reg].isStatic)
mr[reg].spillLock = false;
void Arm64RegCache::ReleaseSpillLock(MIPSGPReg r1, MIPSGPReg r2, MIPSGPReg r3, MIPSGPReg r4) {
if (!mr[r1].isStatic)
mr[r1].spillLock = false;
if (r2 != MIPS_REG_INVALID && !mr[r2].isStatic)
mr[r2].spillLock = false;
if (r3 != MIPS_REG_INVALID && !mr[r3].isStatic)
mr[r3].spillLock = false;
if (r4 != MIPS_REG_INVALID && !mr[r4].isStatic)
mr[r4].spillLock = false;
}
ARM64Reg Arm64RegCache::R(MIPSGPReg mipsReg) {
@@ -23,8 +23,7 @@
namespace Arm64JitConstants {
const Arm64Gen::ARM64Reg DOWNCOUNTREG = Arm64Gen::W23;
const Arm64Gen::ARM64Reg OTHERTEMPREG = Arm64Gen::W24;
const Arm64Gen::ARM64Reg DOWNCOUNTREG = Arm64Gen::W24;
const Arm64Gen::ARM64Reg FLAGTEMPREG = Arm64Gen::X25;
const Arm64Gen::ARM64Reg JITBASEREG = Arm64Gen::X26;
const Arm64Gen::ARM64Reg CTXREG = Arm64Gen::X27;
@@ -92,8 +91,8 @@ class Arm64RegCache {
// Protect the arm register containing a MIPS register from spilling, to ensure that
// it's being kept allocated.
void SpillLock(MIPSGPReg reg, MIPSGPReg reg2 = MIPS_REG_INVALID, MIPSGPReg reg3 = MIPS_REG_INVALID, MIPSGPReg reg4 = MIPS_REG_INVALID);
void ReleaseSpillLock(MIPSGPReg reg);
void ReleaseSpillLocks();
void ReleaseSpillLock(MIPSGPReg reg, MIPSGPReg reg2 = MIPS_REG_INVALID, MIPSGPReg reg3 = MIPS_REG_INVALID, MIPSGPReg reg4 = MIPS_REG_INVALID);
void ReleaseSpillLocksAndDiscardTemps();
void SetImm(MIPSGPReg reg, u64 immVal);
bool IsImm(MIPSGPReg reg) const;
@@ -102,7 +101,8 @@ class Arm64RegCache {
// Optimally set a register to an imm value (possibly using another register.)
void SetRegImm(Arm64Gen::ARM64Reg reg, u64 imm);
Arm64Gen::ARM64Reg MapTempImm(MIPSGPReg);
// May fail and return INVALID_REG if it needs flushing.
Arm64Gen::ARM64Reg TryMapTempImm(MIPSGPReg);
// Returns an ARM register containing the requested MIPS register.
Arm64Gen::ARM64Reg MapReg(MIPSGPReg reg, int mapFlags = 0);
@@ -228,7 +228,8 @@ bool CtrlDisAsmView::getDisasmAddressText(u32 address, char* dest, bool abbrevia
}
} else {
if (showData) {
sprintf(dest, "%08X %08X", address, Memory::Read_Instruction(address, true).encoding);
u32 encoding = Memory::IsValidAddress(address) ? Memory::Read_Instruction(address, true).encoding : 0;
sprintf(dest, "%08X %08X", address, encoding);
} else {
sprintf(dest, "%08X", address);
}

0 comments on commit f3ba540

Please sign in to comment.