mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-13 14:30:27 +02:00
riscv: Centralize IR reg cache metadata checks.
These are all largely the same between backends.
This commit is contained in:
1 parent
ebab0e1591
commit
4e41f83ecc
12 files changed
+268
-309
No files matched your search
+158
-2
@@ -130,6 +130,158 @@ void IRNativeRegCacheBase::SetupInitialRegs() {
|
||||
mrInitial_[MIPS_REG_ZERO].imm = 0;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPRInRAM(IRReg gpr) {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
return mr[gpr].loc == MIPSLoc::MEM;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsFPRInRAM(IRReg fpr) {
|
||||
_dbg_assert_(IsValidFPR(fpr));
|
||||
return mr[fpr + 32].loc == MIPSLoc::MEM;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPRMapped(IRReg gpr) {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
return mr[gpr].loc == MIPSLoc::REG || mr[gpr].loc == MIPSLoc::REG_IMM;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsFPRMapped(IRReg fpr) {
|
||||
_dbg_assert_(IsValidFPR(fpr));
|
||||
return mr[fpr + 32].loc == MIPSLoc::FREG || mr[fpr + 32].loc == MIPSLoc::VREG;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPRMappedAsPointer(IRReg gpr) {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
if (mr[gpr].loc == MIPSLoc::REG) {
|
||||
return nr[mr[gpr].nReg].pointerified;
|
||||
} else if (mr[gpr].loc == MIPSLoc::REG_IMM) {
|
||||
_assert_msg_(!nr[mr[gpr].nReg].pointerified, "Really shouldn't be pointerified here");
|
||||
} else if (mr[gpr].loc == MIPSLoc::REG_AS_PTR) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPRMappedAsStaticPointer(IRReg gpr) {
|
||||
if (IsGPRMappedAsPointer(gpr)) {
|
||||
return mr[gpr].isStatic;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPRImm(IRReg gpr) {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
if (gpr == MIPS_REG_ZERO)
|
||||
return true;
|
||||
return mr[gpr].loc == MIPSLoc::IMM || mr[gpr].loc == MIPSLoc::REG_IMM;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPR2Imm(IRReg base) {
|
||||
return IsGPRImm(base) && IsGPRImm(base + 1);
|
||||
}
|
||||
|
||||
uint32_t IRNativeRegCacheBase::GetGPRImm(IRReg gpr) {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
if (gpr == MIPS_REG_ZERO)
|
||||
return 0;
|
||||
if (mr[gpr].loc != MIPSLoc::IMM && mr[gpr].loc != MIPSLoc::REG_IMM) {
|
||||
_assert_msg_(mr[gpr].loc == MIPSLoc::IMM || mr[gpr].loc == MIPSLoc::REG_IMM, "GPR %d not in an imm", gpr);
|
||||
}
|
||||
return mr[gpr].imm;
|
||||
}
|
||||
|
||||
uint64_t IRNativeRegCacheBase::GetGPR2Imm(IRReg base) {
|
||||
return (uint64_t)GetGPRImm(base) | ((uint64_t)GetGPRImm(base + 1) << 32);
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::SetGPRImm(IRReg gpr, uint32_t immVal) {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
if (gpr == MIPS_REG_ZERO && immVal != 0) {
|
||||
ERROR_LOG_REPORT(JIT, "Trying to set immediate %08x to r0", immVal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mr[gpr].loc == MIPSLoc::REG_IMM && mr[gpr].imm == immVal) {
|
||||
// Already have that value, let's keep it in the reg.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mr[gpr].nReg != -1) {
|
||||
// Zap existing value if cached in a reg.
|
||||
_assert_msg_(mr[gpr].lane == -1, "Should not be a multilane reg");
|
||||
DiscardNativeReg(mr[gpr].nReg);
|
||||
}
|
||||
|
||||
mr[gpr].loc = MIPSLoc::IMM;
|
||||
mr[gpr].imm = immVal;
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::SetGPR2Imm(IRReg base, uint64_t immVal) {
|
||||
_dbg_assert_(IsValidGPRNoZero(base));
|
||||
uint32_t imm0 = (uint32_t)(immVal & 0xFFFFFFFF);
|
||||
uint32_t imm1 = (uint32_t)(immVal >> 32);
|
||||
|
||||
if (IsGPRImm(base) && IsGPRImm(base + 1) && GetGPRImm(base) == imm0 && GetGPRImm(base + 1) == imm1) {
|
||||
// Already set to this, don't bother.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mr[base].nReg != -1) {
|
||||
// Zap existing value if cached in a reg.
|
||||
DiscardNativeReg(mr[base].nReg);
|
||||
if (mr[base + 1].nReg != -1)
|
||||
DiscardNativeReg(mr[base + 1].nReg);
|
||||
}
|
||||
|
||||
mr[base].loc = MIPSLoc::IMM;
|
||||
mr[base].imm = imm0;
|
||||
mr[base + 1].loc = MIPSLoc::IMM;
|
||||
mr[base + 1].imm = imm1;
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::SpillLockGPR(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidGPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidGPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidGPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidGPR(r4));
|
||||
SetSpillLockIRIndex(r1, r2, r3, r4, 0, irIndex_);
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::SpillLockFPR(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidFPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidFPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidFPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidFPR(r4));
|
||||
SetSpillLockIRIndex(r1, r2, r3, r4, 32, irIndex_);
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::ReleaseSpillLockGPR(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidGPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidGPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidGPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidGPR(r4));
|
||||
SetSpillLockIRIndex(r1, r2, r3, r4, 0, -1);
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::ReleaseSpillLockFPR(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidFPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidFPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidFPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidFPR(r4));
|
||||
SetSpillLockIRIndex(r1, r2, r3, r4, 32, -1);
|
||||
}
|
||||
|
||||
void IRNativeRegCacheBase::SetSpillLockIRIndex(IRReg r1, IRReg r2, IRReg r3, IRReg r4, int offset, int index) {
|
||||
if (!mr[r1 + offset].isStatic)
|
||||
mr[r1 + offset].spillLockIRIndex = index;
|
||||
if (r2 != IRREG_INVALID && !mr[r2 + offset].isStatic)
|
||||
mr[r2 + offset].spillLockIRIndex = index;
|
||||
if (r3 != IRREG_INVALID && !mr[r3 + offset].isStatic)
|
||||
mr[r3 + offset].spillLockIRIndex = index;
|
||||
if (r4 != IRREG_INVALID && !mr[r4 + offset].isStatic)
|
||||
mr[r4 + offset].spillLockIRIndex = index;
|
||||
}
|
||||
|
||||
IRNativeReg IRNativeRegCacheBase::AllocateReg(MIPSLoc type) {
|
||||
_dbg_assert_(type == MIPSLoc::REG || type == MIPSLoc::FREG || type == MIPSLoc::VREG);
|
||||
|
||||
@@ -248,7 +400,7 @@ void IRNativeRegCacheBase::DiscardNativeReg(IRNativeReg nreg) {
|
||||
|
||||
// If it's not currently marked as in a reg, throw it away.
|
||||
for (IRReg m = nr[nreg].mipsReg; m < nr[nreg].mipsReg + lanes; ++m) {
|
||||
_assert_msg_(!mr[m].isStatic, "Reg in lane %d mismatched static status", m - nr[nreg].mipsReg);
|
||||
_assert_msg_(mr[m].isStatic, "Reg in lane %d mismatched static status", m - nr[nreg].mipsReg);
|
||||
for (int i = 0; i < numStatics; i++) {
|
||||
if (m == statics[i].mr)
|
||||
mr[m].loc = statics[i].loc;
|
||||
@@ -259,6 +411,7 @@ void IRNativeRegCacheBase::DiscardNativeReg(IRNativeReg nreg) {
|
||||
mr[m].loc = MIPSLoc::MEM;
|
||||
mr[m].nReg = -1;
|
||||
mr[m].imm = 0;
|
||||
mr[m].lane = -1;
|
||||
_assert_msg_(!mr[m].isStatic, "Reg in lane %d mismatched static status", m - nr[nreg].mipsReg);
|
||||
}
|
||||
|
||||
@@ -289,7 +442,9 @@ void IRNativeRegCacheBase::FlushNativeReg(IRNativeReg nreg) {
|
||||
bool isDirty = nr[nreg].isDirty;
|
||||
int8_t lanes = 0;
|
||||
for (IRReg m = nr[nreg].mipsReg; mr[m].nReg == nreg && m < IRREG_INVALID; ++m) {
|
||||
_dbg_assert_(!mr[m].isStatic);
|
||||
_assert_(!mr[m].isStatic);
|
||||
// If we're flushing a native reg, better not be partially in mem or an imm.
|
||||
_assert_(mr[m].loc != MIPSLoc::MEM && mr[m].loc != MIPSLoc::IMM);
|
||||
lanes++;
|
||||
}
|
||||
|
||||
@@ -310,6 +465,7 @@ void IRNativeRegCacheBase::FlushNativeReg(IRNativeReg nreg) {
|
||||
// Note that it loses its imm status, because imms are always dirty.
|
||||
mreg.loc = MIPSLoc::MEM;
|
||||
mreg.imm = 0;
|
||||
mreg.lane = -1;
|
||||
}
|
||||
|
||||
nr[nreg].mipsReg = IRREG_INVALID;
|
||||
|
||||
@@ -102,7 +102,7 @@ protected:
|
||||
// If in a register, what index (into nr array)?
|
||||
IRNativeReg nReg = -1;
|
||||
// If a known immediate value, what value?
|
||||
uint64_t imm = 0;
|
||||
uint32_t imm = 0;
|
||||
// Locked from spilling (i.e. used by current instruction) as of what IR instruction?
|
||||
int spillLockIRIndex = -1;
|
||||
// If in a multipart reg (vector or HI/LO), which lane?
|
||||
@@ -145,6 +145,27 @@ public:
|
||||
irIndex_ = index;
|
||||
}
|
||||
|
||||
bool IsGPRInRAM(IRReg gpr);
|
||||
bool IsFPRInRAM(IRReg fpr);
|
||||
bool IsGPRMapped(IRReg gpr);
|
||||
bool IsFPRMapped(IRReg fpr);
|
||||
bool IsGPRMappedAsPointer(IRReg gpr);
|
||||
bool IsGPRMappedAsStaticPointer(IRReg gpr);
|
||||
|
||||
bool IsGPRImm(IRReg gpr);
|
||||
bool IsGPR2Imm(IRReg base);
|
||||
uint32_t GetGPRImm(IRReg gpr);
|
||||
uint64_t GetGPR2Imm(IRReg first);
|
||||
void SetGPRImm(IRReg gpr, uint32_t immval);
|
||||
void SetGPR2Imm(IRReg first, uint64_t immval);
|
||||
|
||||
// Protect the native registers containing register froms spilling, to ensure that
|
||||
// it's being kept allocated.
|
||||
void SpillLockGPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
void SpillLockFPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
void ReleaseSpillLockGPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
void ReleaseSpillLockFPR(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
|
||||
protected:
|
||||
virtual void SetupInitialRegs();
|
||||
virtual const int *GetAllocationOrder(MIPSLoc type, int &count, int &base) const = 0;
|
||||
@@ -161,6 +182,8 @@ protected:
|
||||
virtual void AdjustNativeRegAsPtr(IRNativeReg nreg, bool state);
|
||||
virtual void StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) = 0;
|
||||
|
||||
void SetSpillLockIRIndex(IRReg reg, IRReg reg2, IRReg reg3, IRReg reg4, int offset, int index);
|
||||
|
||||
bool IsValidGPR(IRReg r) const;
|
||||
bool IsValidGPRNoZero(IRReg r) const;
|
||||
bool IsValidFPR(IRReg r) const;
|
||||
|
||||
@@ -65,7 +65,7 @@ void RiscVJitBackend::CompIR_Arith(IRInst inst) {
|
||||
case IROp::AddConst:
|
||||
if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) {
|
||||
// Typical of stack pointer updates.
|
||||
if (gpr.IsMappedAsPointer(inst.src1) && inst.dest == inst.src1 && allowPtrMath) {
|
||||
if (gpr.IsGPRMappedAsPointer(inst.src1) && inst.dest == inst.src1 && allowPtrMath) {
|
||||
gpr.MarkPtrDirty(gpr.RPtr(inst.dest));
|
||||
ADDI(gpr.RPtr(inst.dest), gpr.RPtr(inst.dest), inst.constant);
|
||||
} else {
|
||||
@@ -127,7 +127,7 @@ void RiscVJitBackend::CompIR_Logic(IRInst inst) {
|
||||
|
||||
case IROp::Xor:
|
||||
if (inst.src1 == inst.src2) {
|
||||
gpr.SetImm(inst.dest, 0);
|
||||
gpr.SetGPRImm(inst.dest, 0);
|
||||
} else {
|
||||
gpr.MapDirtyInIn(inst.dest, inst.src1, inst.src2);
|
||||
XOR(gpr.R(inst.dest), gpr.R(inst.src1), gpr.R(inst.src2));
|
||||
@@ -334,7 +334,7 @@ void RiscVJitBackend::CompIR_Shift(IRInst inst) {
|
||||
case IROp::ShlImm:
|
||||
// Shouldn't happen, but let's be safe of any passes that modify the ops.
|
||||
if (inst.src2 >= 32) {
|
||||
gpr.SetImm(inst.dest, 0);
|
||||
gpr.SetGPRImm(inst.dest, 0);
|
||||
} else if (inst.src2 == 0) {
|
||||
if (inst.dest != inst.src1) {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||
@@ -350,7 +350,7 @@ void RiscVJitBackend::CompIR_Shift(IRInst inst) {
|
||||
case IROp::ShrImm:
|
||||
// Shouldn't happen, but let's be safe of any passes that modify the ops.
|
||||
if (inst.src2 >= 32) {
|
||||
gpr.SetImm(inst.dest, 0);
|
||||
gpr.SetGPRImm(inst.dest, 0);
|
||||
} else if (inst.src2 == 0) {
|
||||
if (inst.dest != inst.src1) {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1);
|
||||
@@ -408,12 +408,11 @@ void RiscVJitBackend::CompIR_Compare(IRInst inst) {
|
||||
RiscVReg rhs = INVALID_REG;
|
||||
switch (inst.op) {
|
||||
case IROp::Slt:
|
||||
gpr.SpillLock(inst.dest, inst.src1, inst.src2);
|
||||
gpr.SpillLockGPR(inst.dest, inst.src1, inst.src2);
|
||||
gpr.MapReg(inst.src1);
|
||||
gpr.MapReg(inst.src2);
|
||||
NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);
|
||||
gpr.MapReg(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32);
|
||||
gpr.ReleaseSpillLock(inst.dest, inst.src1, inst.src2);
|
||||
|
||||
SLT(gpr.R(inst.dest), lhs, rhs);
|
||||
break;
|
||||
@@ -424,11 +423,10 @@ void RiscVJitBackend::CompIR_Compare(IRInst inst) {
|
||||
gpr.MapDirtyIn(inst.dest, inst.src1, MapType::AVOID_LOAD_MARK_NORM32);
|
||||
SRLIW(gpr.R(inst.dest), gpr.R(inst.src1), 31);
|
||||
} else {
|
||||
gpr.SpillLock(inst.dest, inst.src1);
|
||||
gpr.SpillLockGPR(inst.dest, inst.src1);
|
||||
gpr.MapReg(inst.src1);
|
||||
NormalizeSrc1(inst, &lhs, SCRATCH1, false);
|
||||
gpr.MapReg(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32);
|
||||
gpr.ReleaseSpillLock(inst.dest, inst.src1);
|
||||
|
||||
if ((int32_t)inst.constant >= -2048 && (int32_t)inst.constant <= 2047) {
|
||||
SLTI(gpr.R(inst.dest), lhs, (int32_t)inst.constant);
|
||||
@@ -441,26 +439,24 @@ void RiscVJitBackend::CompIR_Compare(IRInst inst) {
|
||||
break;
|
||||
|
||||
case IROp::SltU:
|
||||
gpr.SpillLock(inst.dest, inst.src1, inst.src2);
|
||||
gpr.SpillLockGPR(inst.dest, inst.src1, inst.src2);
|
||||
gpr.MapReg(inst.src1);
|
||||
gpr.MapReg(inst.src2);
|
||||
// It's still fine to sign extend, the biggest just get even bigger.
|
||||
NormalizeSrc12(inst, &lhs, &rhs, SCRATCH1, SCRATCH2, true);
|
||||
gpr.MapReg(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32);
|
||||
gpr.ReleaseSpillLock(inst.dest, inst.src1, inst.src2);
|
||||
|
||||
SLTU(gpr.R(inst.dest), lhs, rhs);
|
||||
break;
|
||||
|
||||
case IROp::SltUConst:
|
||||
if (inst.constant == 0) {
|
||||
gpr.SetImm(inst.dest, 0);
|
||||
gpr.SetGPRImm(inst.dest, 0);
|
||||
} else {
|
||||
gpr.SpillLock(inst.dest, inst.src1);
|
||||
gpr.SpillLockGPR(inst.dest, inst.src1);
|
||||
gpr.MapReg(inst.src1);
|
||||
NormalizeSrc1(inst, &lhs, SCRATCH1, false);
|
||||
gpr.MapReg(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32);
|
||||
gpr.ReleaseSpillLock(inst.dest, inst.src1);
|
||||
|
||||
// We sign extend because we're comparing against something normalized.
|
||||
// It's also the most efficient to set.
|
||||
|
||||
@@ -346,7 +346,7 @@ void RiscVJitBackend::CompIR_FCompare(IRInst inst) {
|
||||
case IROp::FCmp:
|
||||
switch (inst.dest) {
|
||||
case IRFpCompareMode::False:
|
||||
gpr.SetImm(IRREG_FPCOND, 0);
|
||||
gpr.SetGPRImm(IRREG_FPCOND, 0);
|
||||
break;
|
||||
|
||||
case IRFpCompareMode::EitherUnordered:
|
||||
@@ -584,7 +584,7 @@ void RiscVJitBackend::CompIR_FSpecial(IRInst inst) {
|
||||
gpr.FlushBeforeCall();
|
||||
fpr.FlushBeforeCall();
|
||||
// It might be in a non-volatile register.
|
||||
if (fpr.IsMapped(inst.src1)) {
|
||||
if (fpr.IsFPRMapped(inst.src1)) {
|
||||
FMV(32, F10, fpr.R(inst.src1));
|
||||
} else {
|
||||
int offset = offsetof(MIPSState, f) + inst.src1 * 4;
|
||||
|
||||
@@ -66,7 +66,7 @@ int32_t RiscVJitBackend::AdjustForAddressOffset(RiscVGen::RiscVReg *reg, int32_t
|
||||
void RiscVJitBackend::CompIR_Load(IRInst inst) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
gpr.SpillLock(inst.dest, inst.src1);
|
||||
gpr.SpillLockGPR(inst.dest, inst.src1);
|
||||
RiscVReg addrReg = INVALID_REG;
|
||||
if (inst.src1 == MIPS_REG_ZERO) {
|
||||
// This will get changed by AdjustForAddressOffset.
|
||||
@@ -74,7 +74,7 @@ void RiscVJitBackend::CompIR_Load(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if (jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) {
|
||||
} else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
@@ -82,7 +82,6 @@ void RiscVJitBackend::CompIR_Load(IRInst inst) {
|
||||
}
|
||||
// With NOINIT, MapReg won't subtract MEMBASEREG even if dest == src1.
|
||||
gpr.MapReg(inst.dest, MIPSMap::NOINIT | MIPSMap::MARK_NORM32);
|
||||
gpr.ReleaseSpillLock(inst.dest, inst.src1);
|
||||
|
||||
s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);
|
||||
|
||||
@@ -112,7 +111,7 @@ void RiscVJitBackend::CompIR_Load(IRInst inst) {
|
||||
case IROp::Load32Linked:
|
||||
if (inst.dest != MIPS_REG_ZERO)
|
||||
LW(gpr.R(inst.dest), addrReg, imm);
|
||||
gpr.SetImm(IRREG_LLBIT, 1);
|
||||
gpr.SetGPRImm(IRREG_LLBIT, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -147,7 +146,7 @@ void RiscVJitBackend::CompIR_FLoad(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if (jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) {
|
||||
} else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
@@ -180,7 +179,7 @@ void RiscVJitBackend::CompIR_VecLoad(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if (jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) {
|
||||
} else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
@@ -210,7 +209,7 @@ void RiscVJitBackend::CompIR_VecLoad(IRInst inst) {
|
||||
void RiscVJitBackend::CompIR_Store(IRInst inst) {
|
||||
CONDITIONAL_DISABLE;
|
||||
|
||||
gpr.SpillLock(inst.src3, inst.src1);
|
||||
gpr.SpillLockGPR(inst.src3, inst.src1);
|
||||
RiscVReg addrReg = INVALID_REG;
|
||||
if (inst.src1 == MIPS_REG_ZERO) {
|
||||
// This will get changed by AdjustForAddressOffset.
|
||||
@@ -218,7 +217,7 @@ void RiscVJitBackend::CompIR_Store(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if ((jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {
|
||||
} else if ((jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
@@ -227,7 +226,6 @@ void RiscVJitBackend::CompIR_Store(IRInst inst) {
|
||||
RiscVReg valueReg = gpr.TryMapTempImm(inst.src3);
|
||||
if (valueReg == INVALID_REG)
|
||||
valueReg = gpr.MapReg(inst.src3);
|
||||
gpr.ReleaseSpillLock(inst.src3, inst.src1);
|
||||
|
||||
s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);
|
||||
|
||||
@@ -257,7 +255,7 @@ void RiscVJitBackend::CompIR_CondStore(IRInst inst) {
|
||||
if (inst.op != IROp::Store32Conditional)
|
||||
INVALIDOP;
|
||||
|
||||
gpr.SpillLock(IRREG_LLBIT, inst.src3, inst.src1);
|
||||
gpr.SpillLockGPR(IRREG_LLBIT, inst.src3, inst.src1);
|
||||
RiscVReg addrReg = INVALID_REG;
|
||||
if (inst.src1 == MIPS_REG_ZERO) {
|
||||
// This will get changed by AdjustForAddressOffset.
|
||||
@@ -265,7 +263,7 @@ void RiscVJitBackend::CompIR_CondStore(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if ((jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {
|
||||
} else if ((jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) && inst.src3 != inst.src1) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
@@ -273,7 +271,6 @@ void RiscVJitBackend::CompIR_CondStore(IRInst inst) {
|
||||
}
|
||||
gpr.MapReg(inst.src3, inst.dest == MIPS_REG_ZERO ? MIPSMap::INIT : MIPSMap::DIRTY);
|
||||
gpr.MapReg(IRREG_LLBIT);
|
||||
gpr.ReleaseSpillLock(IRREG_LLBIT, inst.src3, inst.src1);
|
||||
|
||||
s32 imm = AdjustForAddressOffset(&addrReg, inst.constant);
|
||||
|
||||
@@ -320,7 +317,7 @@ void RiscVJitBackend::CompIR_FStore(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if (jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) {
|
||||
} else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
@@ -353,7 +350,7 @@ void RiscVJitBackend::CompIR_VecStore(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
inst.constant &= Memory::MEMVIEW32_MASK;
|
||||
#endif
|
||||
} else if (jo.cachePointers || gpr.IsMappedAsPointer(inst.src1)) {
|
||||
} else if (jo.cachePointers || gpr.IsGPRMappedAsPointer(inst.src1)) {
|
||||
addrReg = gpr.MapRegAsPointer(inst.src1);
|
||||
} else {
|
||||
SetScratch1ToSrc1Address(inst.src1);
|
||||
|
||||
@@ -45,7 +45,7 @@ void RiscVJitBackend::CompIR_Basic(IRInst inst) {
|
||||
case IROp::SetConst:
|
||||
// Sign extend all constants. We get 0xFFFFFFFF sometimes, and it's more work to truncate.
|
||||
// The register only holds 32 bits in the end anyway.
|
||||
gpr.SetImm(inst.dest, (int32_t)inst.constant);
|
||||
gpr.SetGPRImm(inst.dest, (int32_t)inst.constant);
|
||||
break;
|
||||
|
||||
case IROp::SetConstF:
|
||||
@@ -90,7 +90,7 @@ void RiscVJitBackend::CompIR_Transfer(IRInst inst) {
|
||||
|
||||
switch (inst.op) {
|
||||
case IROp::SetCtrlVFPU:
|
||||
gpr.SetImm(IRREG_VFPU_CTRL_BASE + inst.dest, (int32_t)inst.constant);
|
||||
gpr.SetGPRImm(IRREG_VFPU_CTRL_BASE + inst.dest, (int32_t)inst.constant);
|
||||
break;
|
||||
|
||||
case IROp::SetCtrlVFPUReg:
|
||||
@@ -158,7 +158,7 @@ void RiscVJitBackend::CompIR_Transfer(IRInst inst) {
|
||||
|
||||
case IROp::FMovFromGPR:
|
||||
fpr.MapReg(inst.dest, MIPSMap::NOINIT);
|
||||
if (gpr.IsImm(inst.src1) && gpr.GetImm(inst.src1) == 0) {
|
||||
if (gpr.IsGPRImm(inst.src1) && gpr.GetGPRImm(inst.src1) == 0) {
|
||||
FCVT(FConv::S, FConv::W, fpr.R(inst.dest), R_ZERO);
|
||||
} else {
|
||||
gpr.MapReg(inst.src1);
|
||||
|
||||
@@ -41,11 +41,9 @@ void RiscVJitBackend::CompIR_VecAssign(IRInst inst) {
|
||||
switch (inst.op) {
|
||||
case IROp::Vec4Init:
|
||||
for (int i = 0; i < 4; ++i)
|
||||
fpr.SpillLock(inst.dest + i);
|
||||
fpr.SpillLockFPR(inst.dest + i);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
fpr.MapReg(inst.dest + i, MIPSMap::NOINIT);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
fpr.ReleaseSpillLock(inst.dest + i);
|
||||
|
||||
// TODO: Check if FCVT/FMV/FL is better.
|
||||
switch ((Vec4Init)inst.src1) {
|
||||
@@ -220,10 +218,9 @@ void RiscVJitBackend::CompIR_VecArith(IRInst inst) {
|
||||
break;
|
||||
|
||||
case IROp::Vec4Scale:
|
||||
fpr.SpillLock(inst.src2);
|
||||
fpr.SpillLockFPR(inst.src2);
|
||||
fpr.MapReg(inst.src2);
|
||||
fpr.Map4DirtyIn(inst.dest, inst.src1);
|
||||
fpr.ReleaseSpillLock(inst.src2);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
FMUL(32, fpr.R(inst.dest + i), fpr.R(inst.src1 + i), fpr.R(inst.src2));
|
||||
break;
|
||||
@@ -252,21 +249,16 @@ void RiscVJitBackend::CompIR_VecHoriz(IRInst inst) {
|
||||
switch (inst.op) {
|
||||
case IROp::Vec4Dot:
|
||||
// TODO: Maybe some option to call the slow accurate mode?
|
||||
fpr.SpillLock(inst.dest);
|
||||
fpr.SpillLockFPR(inst.dest);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
fpr.SpillLock(inst.src1 + i);
|
||||
fpr.SpillLock(inst.src2 + i);
|
||||
fpr.SpillLockFPR(inst.src1 + i);
|
||||
fpr.SpillLockFPR(inst.src2 + i);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
fpr.MapReg(inst.src1 + i);
|
||||
fpr.MapReg(inst.src2 + i);
|
||||
}
|
||||
fpr.MapReg(inst.dest, MIPSMap::NOINIT);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
fpr.ReleaseSpillLock(inst.src1 + i);
|
||||
fpr.ReleaseSpillLock(inst.src2 + i);
|
||||
}
|
||||
fpr.ReleaseSpillLock(inst.dest);
|
||||
|
||||
if ((inst.dest < inst.src1 + 4 && inst.dest >= inst.src1) || (inst.dest < inst.src2 + 4 && inst.dest >= inst.src2)) {
|
||||
// This means inst.dest overlaps one of src1 or src2. We have to do that one first.
|
||||
@@ -303,9 +295,9 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) {
|
||||
break;
|
||||
|
||||
case IROp::Vec4Unpack8To32:
|
||||
fpr.SpillLock(inst.src1);
|
||||
fpr.SpillLockFPR(inst.src1);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
fpr.SpillLock(inst.dest + i);
|
||||
fpr.SpillLockFPR(inst.dest + i);
|
||||
fpr.MapReg(inst.src1);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
fpr.MapReg(inst.dest + i, MIPSMap::NOINIT);
|
||||
@@ -324,9 +316,9 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) {
|
||||
break;
|
||||
|
||||
case IROp::Vec2Unpack16To32:
|
||||
fpr.SpillLock(inst.src1);
|
||||
fpr.SpillLockFPR(inst.src1);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
fpr.SpillLock(inst.dest + i);
|
||||
fpr.SpillLockFPR(inst.dest + i);
|
||||
fpr.MapReg(inst.src1);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
fpr.MapReg(inst.dest + i, MIPSMap::NOINIT);
|
||||
@@ -353,9 +345,9 @@ void RiscVJitBackend::CompIR_VecPack(IRInst inst) {
|
||||
break;
|
||||
|
||||
case IROp::Vec4Pack31To8:
|
||||
fpr.SpillLock(inst.dest);
|
||||
fpr.SpillLockFPR(inst.dest);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
fpr.SpillLock(inst.src1 + i);
|
||||
fpr.SpillLockFPR(inst.src1 + i);
|
||||
fpr.MapReg(inst.src1 + i);
|
||||
}
|
||||
fpr.MapReg(inst.dest, MIPSMap::NOINIT);
|
||||
|
||||
@@ -355,9 +355,9 @@ void RiscVJitBackend::NormalizeSrc12(IRInst inst, RiscVReg *lhs, RiscVReg *rhs,
|
||||
RiscVReg RiscVJitBackend::NormalizeR(IRReg rs, IRReg rd, RiscVReg tempReg) {
|
||||
// For proper compare, we must sign extend so they both match or don't match.
|
||||
// But don't change pointers, in case one is SP (happens in LittleBigPlanet.)
|
||||
if (gpr.IsImm(rs) && gpr.GetImm(rs) == 0) {
|
||||
if (gpr.IsGPRImm(rs) && gpr.GetGPRImm(rs) == 0) {
|
||||
return R_ZERO;
|
||||
} else if (gpr.IsMappedAsPointer(rs) || rs == rd) {
|
||||
} else if (gpr.IsGPRMappedAsPointer(rs) || rs == rd) {
|
||||
return gpr.Normalize32(rs, tempReg);
|
||||
} else {
|
||||
return gpr.Normalize32(rs);
|
||||
|
||||
@@ -127,37 +127,6 @@ void RiscVRegCache::FlushBeforeCall() {
|
||||
}
|
||||
}
|
||||
|
||||
bool RiscVRegCache::IsInRAM(IRReg reg) {
|
||||
_dbg_assert_(IsValidGPR(reg));
|
||||
return mr[reg].loc == MIPSLoc::MEM;
|
||||
}
|
||||
|
||||
bool RiscVRegCache::IsMapped(IRReg mipsReg) {
|
||||
_dbg_assert_(IsValidGPR(mipsReg));
|
||||
return mr[mipsReg].loc == MIPSLoc::REG || mr[mipsReg].loc == MIPSLoc::REG_IMM;
|
||||
}
|
||||
|
||||
bool RiscVRegCache::IsMappedAsPointer(IRReg mipsReg) {
|
||||
_dbg_assert_(IsValidGPR(mipsReg));
|
||||
if (mr[mipsReg].loc == MIPSLoc::REG) {
|
||||
return nr[mr[mipsReg].nReg].pointerified;
|
||||
} else if (mr[mipsReg].loc == MIPSLoc::REG_IMM) {
|
||||
if (nr[mr[mipsReg].nReg].pointerified) {
|
||||
ERROR_LOG(JIT, "Really shouldn't be pointerified here");
|
||||
}
|
||||
} else if (mr[mipsReg].loc == MIPSLoc::REG_AS_PTR) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RiscVRegCache::IsMappedAsStaticPointer(IRReg reg) {
|
||||
if (IsMappedAsPointer(reg)) {
|
||||
return mr[reg].isStatic;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RiscVRegCache::IsNormalized32(IRReg mipsReg) {
|
||||
_dbg_assert_(IsValidGPR(mipsReg));
|
||||
if (XLEN == 32)
|
||||
@@ -321,7 +290,7 @@ void RiscVRegCache::MapRegTo(RiscVReg reg, IRReg mipsReg, MIPSMap mapFlags) {
|
||||
RiscVReg RiscVRegCache::TryMapTempImm(IRReg r) {
|
||||
_dbg_assert_(IsValidGPR(r));
|
||||
// If already mapped, no need for a temporary.
|
||||
if (IsMapped(r)) {
|
||||
if (IsGPRMapped(r)) {
|
||||
return R(r);
|
||||
}
|
||||
|
||||
@@ -513,44 +482,44 @@ void RiscVRegCache::MapIn(IRReg rs) {
|
||||
}
|
||||
|
||||
void RiscVRegCache::MapInIn(IRReg rd, IRReg rs) {
|
||||
SpillLock(rd, rs);
|
||||
SpillLockGPR(rd, rs);
|
||||
MapReg(rd);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd, rs);
|
||||
ReleaseSpillLockGPR(rd, rs);
|
||||
}
|
||||
|
||||
void RiscVRegCache::MapDirtyIn(IRReg rd, IRReg rs, MapType type) {
|
||||
SpillLock(rd, rs);
|
||||
SpillLockGPR(rd, rs);
|
||||
bool load = type == MapType::ALWAYS_LOAD || rd == rs;
|
||||
MIPSMap norm32 = type == MapType::AVOID_LOAD_MARK_NORM32 ? MIPSMap::MARK_NORM32 : MIPSMap::INIT;
|
||||
MapReg(rd, (load ? MIPSMap::DIRTY : MIPSMap::NOINIT) | norm32);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd, rs);
|
||||
ReleaseSpillLockGPR(rd, rs);
|
||||
}
|
||||
|
||||
void RiscVRegCache::MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt, MapType type) {
|
||||
SpillLock(rd, rs, rt);
|
||||
SpillLockGPR(rd, rs, rt);
|
||||
bool load = type == MapType::ALWAYS_LOAD || (rd == rs || rd == rt);
|
||||
MIPSMap norm32 = type == MapType::AVOID_LOAD_MARK_NORM32 ? MIPSMap::MARK_NORM32 : MIPSMap::INIT;
|
||||
MapReg(rd, (load ? MIPSMap::DIRTY : MIPSMap::NOINIT) | norm32);
|
||||
MapReg(rt);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd, rs, rt);
|
||||
ReleaseSpillLockGPR(rd, rs, rt);
|
||||
}
|
||||
|
||||
void RiscVRegCache::MapDirtyDirtyIn(IRReg rd1, IRReg rd2, IRReg rs, MapType type) {
|
||||
SpillLock(rd1, rd2, rs);
|
||||
SpillLockGPR(rd1, rd2, rs);
|
||||
bool load1 = type == MapType::ALWAYS_LOAD || rd1 == rs;
|
||||
bool load2 = type == MapType::ALWAYS_LOAD || rd2 == rs;
|
||||
MIPSMap norm32 = type == MapType::AVOID_LOAD_MARK_NORM32 ? MIPSMap::MARK_NORM32 : MIPSMap::INIT;
|
||||
MapReg(rd1, (load1 ? MIPSMap::DIRTY : MIPSMap::NOINIT) | norm32);
|
||||
MapReg(rd2, (load2 ? MIPSMap::DIRTY : MIPSMap::NOINIT) | norm32);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd1, rd2, rs);
|
||||
ReleaseSpillLockGPR(rd1, rd2, rs);
|
||||
}
|
||||
|
||||
void RiscVRegCache::MapDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt, MapType type) {
|
||||
SpillLock(rd1, rd2, rs, rt);
|
||||
SpillLockGPR(rd1, rd2, rs, rt);
|
||||
bool load1 = type == MapType::ALWAYS_LOAD || (rd1 == rs || rd1 == rt);
|
||||
bool load2 = type == MapType::ALWAYS_LOAD || (rd2 == rs || rd2 == rt);
|
||||
MIPSMap norm32 = type == MapType::AVOID_LOAD_MARK_NORM32 ? MIPSMap::MARK_NORM32 : MIPSMap::INIT;
|
||||
@@ -558,7 +527,7 @@ void RiscVRegCache::MapDirtyDirtyInIn(IRReg rd1, IRReg rd2, IRReg rs, IRReg rt,
|
||||
MapReg(rd2, (load2 ? MIPSMap::DIRTY : MIPSMap::NOINIT) | norm32);
|
||||
MapReg(rt);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd1, rd2, rs, rt);
|
||||
ReleaseSpillLockGPR(rd1, rd2, rs, rt);
|
||||
}
|
||||
|
||||
void RiscVRegCache::AdjustNativeRegAsPtr(IRNativeReg nreg, bool state) {
|
||||
@@ -579,9 +548,14 @@ void RiscVRegCache::StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) {
|
||||
_dbg_assert_(r > X0 && r <= X31);
|
||||
_dbg_assert_(first != MIPS_REG_ZERO);
|
||||
// Multilane not yet supported.
|
||||
_assert_(lanes == 1);
|
||||
_assert_(lanes == 1 || (lanes == 2 && first == IRREG_LO));
|
||||
_assert_(mr[first].loc == MIPSLoc::REG || mr[first].loc == MIPSLoc::REG_IMM);
|
||||
emit_->SW(r, CTXREG, GetMipsRegOffset(first));
|
||||
if (lanes == 1)
|
||||
emit_->SW(r, CTXREG, GetMipsRegOffset(first));
|
||||
else if (lanes == 2)
|
||||
emit_->SD(r, CTXREG, GetMipsRegOffset(first));
|
||||
else
|
||||
_assert_(false);
|
||||
}
|
||||
|
||||
void RiscVRegCache::DiscardR(IRReg mipsReg) {
|
||||
@@ -625,20 +599,7 @@ RiscVReg RiscVRegCache::RiscVRegForFlush(IRReg r) {
|
||||
|
||||
case MIPSLoc::REG:
|
||||
case MIPSLoc::REG_IMM:
|
||||
if (mr[r].nReg == INVALID_REG) {
|
||||
ERROR_LOG_REPORT(JIT, "RiscVRegForFlush: MipsReg %d had bad riscvReg", r);
|
||||
return INVALID_REG;
|
||||
}
|
||||
// No need to flush if it's zero or not dirty.
|
||||
if (r == MIPS_REG_ZERO || !nr[mr[r].nReg].isDirty) {
|
||||
return INVALID_REG;
|
||||
}
|
||||
// TODO: Lo/hi optimization?
|
||||
return (RiscVReg)mr[r].nReg;
|
||||
|
||||
case MIPSLoc::REG_AS_PTR:
|
||||
return INVALID_REG;
|
||||
|
||||
case MIPSLoc::MEM:
|
||||
return INVALID_REG;
|
||||
|
||||
@@ -667,28 +628,21 @@ void RiscVRegCache::FlushR(IRReg r) {
|
||||
storeReg = SCRATCH1;
|
||||
}
|
||||
emit_->SW(storeReg, CTXREG, GetMipsRegOffset(r));
|
||||
mr[r].loc = MIPSLoc::MEM;
|
||||
mr[r].nReg = (int)INVALID_REG;
|
||||
mr[r].imm = -1;
|
||||
} else {
|
||||
mr[r].loc = MIPSLoc::REG_IMM;
|
||||
mr[r].nReg = R_ZERO;
|
||||
mr[r].imm = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case MIPSLoc::REG:
|
||||
case MIPSLoc::REG_IMM:
|
||||
if (nr[mr[r].nReg].isDirty) {
|
||||
StoreNativeReg(mr[r].nReg, r, 1);
|
||||
nr[mr[r].nReg].isDirty = false;
|
||||
}
|
||||
nr[mr[r].nReg].mipsReg = IRREG_INVALID;
|
||||
nr[mr[r].nReg].pointerified = false;
|
||||
break;
|
||||
|
||||
case MIPSLoc::REG_AS_PTR:
|
||||
if (nr[mr[r].nReg].isDirty) {
|
||||
AdjustNativeRegAsPtr(mr[r].nReg, false);
|
||||
// We set this so StoreNativeReg knows it's no longer a pointer.
|
||||
mr[r].loc = MIPSLoc::REG;
|
||||
StoreNativeReg(mr[r].nReg, r, 1);
|
||||
nr[mr[r].nReg].isDirty = false;
|
||||
}
|
||||
nr[mr[r].nReg].mipsReg = IRREG_INVALID;
|
||||
// Might be in a native reg with multiple IR regs, flush together.
|
||||
FlushNativeReg(mr[r].nReg);
|
||||
break;
|
||||
|
||||
case MIPSLoc::MEM:
|
||||
@@ -699,15 +653,6 @@ void RiscVRegCache::FlushR(IRReg r) {
|
||||
ERROR_LOG_REPORT(JIT, "FlushR: MipsReg %d with invalid location %d", r, (int)mr[r].loc);
|
||||
break;
|
||||
}
|
||||
if (r == MIPS_REG_ZERO) {
|
||||
mr[r].loc = MIPSLoc::REG_IMM;
|
||||
mr[r].nReg = R_ZERO;
|
||||
mr[r].imm = 0;
|
||||
} else {
|
||||
mr[r].loc = MIPSLoc::MEM;
|
||||
mr[r].nReg = (int)INVALID_REG;
|
||||
mr[r].imm = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void RiscVRegCache::FlushAll() {
|
||||
@@ -772,91 +717,11 @@ void RiscVRegCache::FlushAll() {
|
||||
}
|
||||
}
|
||||
|
||||
void RiscVRegCache::SetImm(IRReg r, u64 immVal) {
|
||||
_dbg_assert_(IsValidGPR(r));
|
||||
if (r == MIPS_REG_ZERO && immVal != 0) {
|
||||
ERROR_LOG_REPORT(JIT, "Trying to set immediate %08x to r0", (u32)immVal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mr[r].loc == MIPSLoc::REG_IMM && mr[r].imm == immVal) {
|
||||
// Already have that value, let's keep it in the reg.
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: HI/LO optimization?
|
||||
// All regs on the PSP are 32 bit, but LO we treat as HI:LO so is 64 full bits.
|
||||
immVal = immVal & 0xFFFFFFFF;
|
||||
|
||||
if (mr[r].isStatic) {
|
||||
mr[r].loc = MIPSLoc::IMM;
|
||||
mr[r].imm = immVal;
|
||||
nr[mr[r].nReg].pointerified = false;
|
||||
nr[mr[r].nReg].normalized32 = false;
|
||||
// We do not change reg to INVALID_REG for obvious reasons..
|
||||
} else {
|
||||
// Zap existing value if cached in a reg
|
||||
if (mr[r].nReg != INVALID_REG) {
|
||||
nr[mr[r].nReg].mipsReg = IRREG_INVALID;
|
||||
nr[mr[r].nReg].isDirty = false;
|
||||
nr[mr[r].nReg].pointerified = false;
|
||||
nr[mr[r].nReg].normalized32 = false;
|
||||
}
|
||||
mr[r].loc = MIPSLoc::IMM;
|
||||
mr[r].imm = immVal;
|
||||
mr[r].nReg = (int)INVALID_REG;
|
||||
}
|
||||
}
|
||||
|
||||
bool RiscVRegCache::IsImm(IRReg r) const {
|
||||
_dbg_assert_(IsValidGPR(r));
|
||||
if (r == MIPS_REG_ZERO)
|
||||
return true;
|
||||
else
|
||||
return mr[r].loc == MIPSLoc::IMM || mr[r].loc == MIPSLoc::REG_IMM;
|
||||
}
|
||||
|
||||
u64 RiscVRegCache::GetImm(IRReg r) const {
|
||||
_dbg_assert_(IsValidGPR(r));
|
||||
if (r == MIPS_REG_ZERO)
|
||||
return 0;
|
||||
if (mr[r].loc != MIPSLoc::IMM && mr[r].loc != MIPSLoc::REG_IMM) {
|
||||
ERROR_LOG_REPORT(JIT, "Trying to get imm from non-imm register %i", r);
|
||||
}
|
||||
return mr[r].imm;
|
||||
}
|
||||
|
||||
int RiscVRegCache::GetMipsRegOffset(IRReg r) {
|
||||
_dbg_assert_(IsValidGPR(r));
|
||||
return r * 4;
|
||||
}
|
||||
|
||||
void RiscVRegCache::SpillLock(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidGPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidGPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidGPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidGPR(r4));
|
||||
mr[r1].spillLockIRIndex = irIndex_;
|
||||
if (r2 != IRREG_INVALID) mr[r2].spillLockIRIndex = irIndex_;
|
||||
if (r3 != IRREG_INVALID) mr[r3].spillLockIRIndex = irIndex_;
|
||||
if (r4 != IRREG_INVALID) mr[r4].spillLockIRIndex = irIndex_;
|
||||
}
|
||||
|
||||
void RiscVRegCache::ReleaseSpillLock(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidGPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidGPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidGPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidGPR(r4));
|
||||
if (!mr[r1].isStatic)
|
||||
mr[r1].spillLockIRIndex = -1;
|
||||
if (r2 != IRREG_INVALID && !mr[r2].isStatic)
|
||||
mr[r2].spillLockIRIndex = -1;
|
||||
if (r3 != IRREG_INVALID && !mr[r3].isStatic)
|
||||
mr[r3].spillLockIRIndex = -1;
|
||||
if (r4 != IRREG_INVALID && !mr[r4].isStatic)
|
||||
mr[r4].spillLockIRIndex = -1;
|
||||
}
|
||||
|
||||
RiscVReg RiscVRegCache::R(IRReg mipsReg) {
|
||||
_dbg_assert_(IsValidGPR(mipsReg));
|
||||
_dbg_assert_(mr[mipsReg].loc == MIPSLoc::REG || mr[mipsReg].loc == MIPSLoc::REG_IMM);
|
||||
|
||||
@@ -63,15 +63,6 @@ public:
|
||||
|
||||
void Init(RiscVGen::RiscVEmitter *emitter);
|
||||
|
||||
// Protect the arm register containing a MIPS register from spilling, to ensure that
|
||||
// it's being kept allocated.
|
||||
void SpillLock(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
void ReleaseSpillLock(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
|
||||
void SetImm(IRReg reg, u64 immVal);
|
||||
bool IsImm(IRReg reg) const;
|
||||
u64 GetImm(IRReg reg) const;
|
||||
|
||||
// May fail and return INVALID_REG if it needs flushing.
|
||||
RiscVGen::RiscVReg TryMapTempImm(IRReg);
|
||||
|
||||
@@ -79,10 +70,6 @@ public:
|
||||
RiscVGen::RiscVReg MapReg(IRReg reg, RiscVJitConstants::MIPSMap mapFlags = RiscVJitConstants::MIPSMap::INIT);
|
||||
RiscVGen::RiscVReg MapRegAsPointer(IRReg reg);
|
||||
|
||||
bool IsMapped(IRReg reg);
|
||||
bool IsMappedAsPointer(IRReg reg);
|
||||
bool IsMappedAsStaticPointer(IRReg reg);
|
||||
bool IsInRAM(IRReg reg);
|
||||
bool IsNormalized32(IRReg reg);
|
||||
|
||||
void MarkDirty(RiscVGen::RiscVReg reg, bool andNormalized32 = false);
|
||||
|
||||
@@ -53,16 +53,6 @@ const int *RiscVRegCacheFPU::GetAllocationOrder(MIPSLoc type, int &count, int &b
|
||||
return allocationOrder;
|
||||
}
|
||||
|
||||
bool RiscVRegCacheFPU::IsInRAM(IRReg reg) {
|
||||
_dbg_assert_(IsValidFPR(reg));
|
||||
return mr[reg + 32].loc == MIPSLoc::MEM;
|
||||
}
|
||||
|
||||
bool RiscVRegCacheFPU::IsMapped(IRReg mipsReg) {
|
||||
_dbg_assert_(IsValidFPR(mipsReg));
|
||||
return mr[mipsReg + 32].loc == MIPSLoc::FREG;
|
||||
}
|
||||
|
||||
RiscVReg RiscVRegCacheFPU::MapReg(IRReg mipsReg, MIPSMap mapFlags) {
|
||||
_dbg_assert_(IsValidFPR(mipsReg));
|
||||
_dbg_assert_(mr[mipsReg + 32].loc == MIPSLoc::MEM || mr[mipsReg + 32].loc == MIPSLoc::FREG);
|
||||
@@ -100,54 +90,54 @@ RiscVReg RiscVRegCacheFPU::MapReg(IRReg mipsReg, MIPSMap mapFlags) {
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::MapInIn(IRReg rd, IRReg rs) {
|
||||
SpillLock(rd, rs);
|
||||
SpillLockFPR(rd, rs);
|
||||
MapReg(rd);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd, rs);
|
||||
ReleaseSpillLockFPR(rd, rs);
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::MapDirtyIn(IRReg rd, IRReg rs, bool avoidLoad) {
|
||||
SpillLock(rd, rs);
|
||||
SpillLockFPR(rd, rs);
|
||||
bool load = !avoidLoad || rd == rs;
|
||||
MapReg(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd, rs);
|
||||
ReleaseSpillLockFPR(rd, rs);
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt, bool avoidLoad) {
|
||||
SpillLock(rd, rs, rt);
|
||||
SpillLockFPR(rd, rs, rt);
|
||||
bool load = !avoidLoad || (rd == rs || rd == rt);
|
||||
MapReg(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
|
||||
MapReg(rt);
|
||||
MapReg(rs);
|
||||
ReleaseSpillLock(rd, rs, rt);
|
||||
ReleaseSpillLockFPR(rd, rs, rt);
|
||||
}
|
||||
|
||||
RiscVReg RiscVRegCacheFPU::MapDirtyInTemp(IRReg rd, IRReg rs, bool avoidLoad) {
|
||||
SpillLock(rd, rs);
|
||||
SpillLockFPR(rd, rs);
|
||||
bool load = !avoidLoad || rd == rs;
|
||||
MapReg(rd, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
|
||||
MapReg(rs);
|
||||
RiscVReg temp = (RiscVReg)(F0 + AllocateReg(MIPSLoc::FREG));
|
||||
ReleaseSpillLock(rd, rs);
|
||||
ReleaseSpillLockFPR(rd, rs);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::Map4DirtyIn(IRReg rdbase, IRReg rsbase, bool avoidLoad) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
SpillLock(rdbase + i, rsbase + i);
|
||||
SpillLockFPR(rdbase + i, rsbase + i);
|
||||
bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
MapReg(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
MapReg(rsbase + i);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ReleaseSpillLock(rdbase + i, rsbase + i);
|
||||
ReleaseSpillLockFPR(rdbase + i, rsbase + i);
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::Map4DirtyInIn(IRReg rdbase, IRReg rsbase, IRReg rtbase, bool avoidLoad) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
SpillLock(rdbase + i, rsbase + i, rtbase + i);
|
||||
SpillLockFPR(rdbase + i, rsbase + i, rtbase + i);
|
||||
bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase) || (rdbase < rtbase + 4 && rdbase + 4 > rtbase);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
MapReg(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
|
||||
@@ -156,12 +146,12 @@ void RiscVRegCacheFPU::Map4DirtyInIn(IRReg rdbase, IRReg rsbase, IRReg rtbase, b
|
||||
for (int i = 0; i < 4; ++i)
|
||||
MapReg(rtbase + i);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ReleaseSpillLock(rdbase + i, rsbase + i, rtbase + i);
|
||||
ReleaseSpillLockFPR(rdbase + i, rsbase + i, rtbase + i);
|
||||
}
|
||||
|
||||
RiscVReg RiscVRegCacheFPU::Map4DirtyInTemp(IRReg rdbase, IRReg rsbase, bool avoidLoad) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
SpillLock(rdbase + i, rsbase + i);
|
||||
SpillLockFPR(rdbase + i, rsbase + i);
|
||||
bool load = !avoidLoad || (rdbase < rsbase + 4 && rdbase + 4 > rsbase);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
MapReg(rdbase + i, load ? MIPSMap::DIRTY : MIPSMap::NOINIT);
|
||||
@@ -169,7 +159,7 @@ RiscVReg RiscVRegCacheFPU::Map4DirtyInTemp(IRReg rdbase, IRReg rsbase, bool avoi
|
||||
MapReg(rsbase + i);
|
||||
RiscVReg temp = (RiscVReg)(F0 + AllocateReg(MIPSLoc::FREG));
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ReleaseSpillLock(rdbase + i, rsbase + i);
|
||||
ReleaseSpillLockFPR(rdbase + i, rsbase + i);
|
||||
return temp;
|
||||
}
|
||||
|
||||
@@ -186,28 +176,20 @@ void RiscVRegCacheFPU::StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes)
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::FlushR(IRReg r) {
|
||||
_dbg_assert_(IsValidFPR(r));
|
||||
RiscVReg reg = RiscVRegForFlush(r);
|
||||
if (reg != INVALID_REG)
|
||||
FlushNativeReg((IRNativeReg)(reg - F0));
|
||||
}
|
||||
|
||||
RiscVReg RiscVRegCacheFPU::RiscVRegForFlush(IRReg r) {
|
||||
_dbg_assert_(IsValidFPR(r));
|
||||
switch (mr[r + 32].loc) {
|
||||
case MIPSLoc::FREG:
|
||||
_assert_msg_(mr[r + 32].nReg != INVALID_REG, "RiscVRegForFlush: IR %d had bad RiscVReg", r + 32);
|
||||
if (mr[r + 32].nReg == INVALID_REG) {
|
||||
return INVALID_REG;
|
||||
}
|
||||
return (RiscVReg)(F0 + mr[r + 32].nReg);
|
||||
case MIPSLoc::VREG:
|
||||
_assert_msg_(mr[r + 32].nReg != INVALID_REG, "FlushR: IR %d had bad RiscVReg", r + 32);
|
||||
FlushNativeReg(mr[r + 32].nReg);
|
||||
break;
|
||||
|
||||
case MIPSLoc::MEM:
|
||||
return INVALID_REG;
|
||||
break;
|
||||
|
||||
default:
|
||||
_assert_(false);
|
||||
return INVALID_REG;
|
||||
_assert_msg_(false, "Unexpected register location %d", (int)mr[r + 32].loc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,8 +261,6 @@ void RiscVRegCacheFPU::DiscardR(IRReg r) {
|
||||
_assert_(false);
|
||||
break;
|
||||
}
|
||||
mr[r + 32].loc = MIPSLoc::MEM;
|
||||
mr[r + 32].nReg = -1;
|
||||
mr[r + 32].spillLockIRIndex = -1;
|
||||
}
|
||||
|
||||
@@ -291,34 +271,6 @@ int RiscVRegCacheFPU::GetMipsRegOffset(IRReg r) {
|
||||
return (r) * 4;
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::SpillLock(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidFPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidFPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidFPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidFPR(r4));
|
||||
mr[r1 + 32].spillLockIRIndex = irIndex_;
|
||||
if (r2 != IRREG_INVALID)
|
||||
mr[r2 + 32].spillLockIRIndex = irIndex_;
|
||||
if (r3 != IRREG_INVALID)
|
||||
mr[r3 + 32].spillLockIRIndex = irIndex_;
|
||||
if (r4 != IRREG_INVALID)
|
||||
mr[r4 + 32].spillLockIRIndex = irIndex_;
|
||||
}
|
||||
|
||||
void RiscVRegCacheFPU::ReleaseSpillLock(IRReg r1, IRReg r2, IRReg r3, IRReg r4) {
|
||||
_dbg_assert_(IsValidFPR(r1));
|
||||
_dbg_assert_(r2 == IRREG_INVALID || IsValidFPR(r2));
|
||||
_dbg_assert_(r3 == IRREG_INVALID || IsValidFPR(r3));
|
||||
_dbg_assert_(r4 == IRREG_INVALID || IsValidFPR(r4));
|
||||
mr[r1 + 32].spillLockIRIndex = -1;
|
||||
if (r2 != IRREG_INVALID)
|
||||
mr[r2 + 32].spillLockIRIndex = -1;
|
||||
if (r3 != IRREG_INVALID)
|
||||
mr[r3 + 32].spillLockIRIndex = -1;
|
||||
if (r4 != IRREG_INVALID)
|
||||
mr[r4 + 32].spillLockIRIndex = -1;
|
||||
}
|
||||
|
||||
RiscVReg RiscVRegCacheFPU::R(IRReg mipsReg) {
|
||||
_dbg_assert_(IsValidFPR(mipsReg));
|
||||
_dbg_assert_(mr[mipsReg + 32].loc == MIPSLoc::FREG);
|
||||
|
||||
@@ -31,17 +31,9 @@ public:
|
||||
|
||||
void Init(RiscVGen::RiscVEmitter *emitter);
|
||||
|
||||
// Protect the RISC-V register containing a MIPS register from spilling, to ensure that
|
||||
// it's being kept allocated.
|
||||
void SpillLock(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
void ReleaseSpillLock(IRReg reg, IRReg reg2 = IRREG_INVALID, IRReg reg3 = IRREG_INVALID, IRReg reg4 = IRREG_INVALID);
|
||||
|
||||
// Returns a RISC-V register containing the requested MIPS register.
|
||||
RiscVGen::RiscVReg MapReg(IRReg reg, RiscVJitConstants::MIPSMap mapFlags = RiscVJitConstants::MIPSMap::INIT);
|
||||
|
||||
bool IsMapped(IRReg r);
|
||||
bool IsInRAM(IRReg r);
|
||||
|
||||
void MapInIn(IRReg rd, IRReg rs);
|
||||
void MapDirtyIn(IRReg rd, IRReg rs, bool avoidLoad = true);
|
||||
void MapDirtyInIn(IRReg rd, IRReg rs, IRReg rt, bool avoidLoad = true);
|
||||
@@ -62,7 +54,6 @@ protected:
|
||||
void StoreNativeReg(IRNativeReg nreg, IRReg first, int lanes) override;
|
||||
|
||||
private:
|
||||
RiscVGen::RiscVReg RiscVRegForFlush(IRReg r);
|
||||
int GetMipsRegOffset(IRReg r);
|
||||
|
||||
RiscVGen::RiscVEmitter *emit_ = nullptr;
|
||||
|
||||
Reference in new issue
Block a user