mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
x86jit: Retain old lanes when there's space.
This commit is contained in:
1 parent
46e704f879
commit
685d2acffe
3 files changed
+78
-19
No files matched your search
@@ -406,12 +406,12 @@ IRNativeReg IRNativeRegCacheBase::FindFreeReg(MIPSLoc type, MIPSMap flags) const
|
||||
|
||||
bool IRNativeRegCacheBase::IsGPRClobbered(IRReg gpr) const {
|
||||
_dbg_assert_(IsValidGPR(gpr));
|
||||
return IsRegClobbered(MIPSLoc::REG, MIPSMap::INIT, gpr);
|
||||
return IsRegClobbered(MIPSLoc::REG, gpr);
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsFPRClobbered(IRReg fpr) const {
|
||||
_dbg_assert_(IsValidFPR(fpr));
|
||||
return IsRegClobbered(MIPSLoc::FREG, MIPSMap::INIT, fpr + 32);
|
||||
return IsRegClobbered(MIPSLoc::FREG, fpr + 32);
|
||||
}
|
||||
|
||||
IRUsage IRNativeRegCacheBase::GetNextRegUsage(const IRSituation &info, MIPSLoc type, IRReg r) const {
|
||||
@@ -423,7 +423,7 @@ IRUsage IRNativeRegCacheBase::GetNextRegUsage(const IRSituation &info, MIPSLoc t
|
||||
return IRUsage::UNKNOWN;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsRegClobbered(MIPSLoc type, MIPSMap flags, IRReg r) const {
|
||||
bool IRNativeRegCacheBase::IsRegClobbered(MIPSLoc type, IRReg r) const {
|
||||
static const int UNUSED_LOOKAHEAD_OPS = 30;
|
||||
|
||||
IRSituation info;
|
||||
@@ -450,6 +450,21 @@ bool IRNativeRegCacheBase::IsRegClobbered(MIPSLoc type, MIPSMap flags, IRReg r)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRNativeRegCacheBase::IsRegRead(MIPSLoc type, IRReg first) const {
|
||||
static const int UNUSED_LOOKAHEAD_OPS = 30;
|
||||
|
||||
IRSituation info;
|
||||
info.lookaheadCount = UNUSED_LOOKAHEAD_OPS;
|
||||
// We look starting one ahead, unlike spilling.
|
||||
info.currentIndex = irIndex_ + 1;
|
||||
info.instructions = irBlock_->GetInstructions();
|
||||
info.numInstructions = irBlock_->GetNumInstructions();
|
||||
|
||||
// Note: this intentionally doesn't look at the full reg, only the lane.
|
||||
IRUsage usage = GetNextRegUsage(info, type, first);
|
||||
return usage == IRUsage::READ;
|
||||
}
|
||||
|
||||
IRNativeReg IRNativeRegCacheBase::FindBestToSpill(MIPSLoc type, MIPSMap flags, bool unusedOnly, bool *clobbered) const {
|
||||
int allocCount = 0, base = 0;
|
||||
const int *allocOrder = GetAllocationOrder(type, flags, allocCount, base);
|
||||
|
||||
@@ -239,7 +239,8 @@ protected:
|
||||
void SetSpillLockIRIndex(IRReg reg, int index);
|
||||
int GetMipsRegOffset(IRReg r);
|
||||
|
||||
bool IsRegClobbered(MIPSLoc type, MIPSMap flags, IRReg r) const;
|
||||
bool IsRegClobbered(MIPSLoc type, IRReg r) const;
|
||||
bool IsRegRead(MIPSLoc type, IRReg r) const;
|
||||
IRUsage GetNextRegUsage(const IRSituation &info, MIPSLoc type, IRReg r) const;
|
||||
|
||||
bool IsValidGPR(IRReg r) const;
|
||||
|
||||
@@ -480,12 +480,52 @@ bool X64IRRegCache::TransferNativeReg(IRNativeReg nreg, IRNativeReg dest, MIPSLo
|
||||
}
|
||||
|
||||
bool X64IRRegCache::TransferVecTo1(IRNativeReg nreg, IRNativeReg dest, IRReg first, int oldlanes) {
|
||||
// Okay, start by storing if dirty.
|
||||
// TODO: Consider moving the others to free regs if available? Likely will be wanted later.
|
||||
IRReg oldfirst = nr[nreg].mipsReg;
|
||||
if (nr[nreg].isDirty) {
|
||||
|
||||
// Is it worth preserving any of the old regs?
|
||||
int numKept = 0;
|
||||
for (int i = 0; i < oldlanes; ++i) {
|
||||
// Skip whichever one this is extracting.
|
||||
if (oldfirst + i == first)
|
||||
continue;
|
||||
// If 0 isn't being transfered, easy to keep in its original reg.
|
||||
if (i == 0 && dest != nreg) {
|
||||
numKept++;
|
||||
continue;
|
||||
}
|
||||
|
||||
IRNativeReg freeReg = FindFreeReg(MIPSLoc::FREG, MIPSMap::INIT);
|
||||
if (freeReg != -1 && IsRegRead(MIPSLoc::FREG, oldfirst + i)) {
|
||||
// If there's one free, use it. Don't modify nreg, though.
|
||||
u8 shuf = VFPU_SWIZZLE(i, i, i, i);
|
||||
if (i == 0) {
|
||||
emit_->MOVAPS(FromNativeReg(freeReg), ::R(FromNativeReg(nreg)));
|
||||
} else if (cpu_info.bAVX) {
|
||||
emit_->VPERMILPS(128, FromNativeReg(freeReg), ::R(FromNativeReg(nreg)), shuf);
|
||||
} else if (i == 2) {
|
||||
emit_->MOVHLPS(FromNativeReg(freeReg), FromNativeReg(nreg));
|
||||
} else {
|
||||
emit_->MOVAPS(FromNativeReg(freeReg), ::R(FromNativeReg(nreg)));
|
||||
emit_->SHUFPS(FromNativeReg(freeReg), ::R(FromNativeReg(freeReg)), shuf);
|
||||
}
|
||||
|
||||
// Update accounting.
|
||||
nr[freeReg].isDirty = nr[nreg].isDirty;
|
||||
nr[freeReg].mipsReg = oldfirst + i;
|
||||
mr[oldfirst + i].lane = -1;
|
||||
mr[oldfirst + i].nReg = freeReg;
|
||||
numKept++;
|
||||
}
|
||||
}
|
||||
|
||||
// Unless all other lanes were kept, store.
|
||||
if (nr[nreg].isDirty && numKept < oldlanes - 1) {
|
||||
StoreNativeReg(nreg, oldfirst, oldlanes);
|
||||
nr[nreg].isDirty = false;
|
||||
// Set false even for regs that were split out, since they were flushed too.
|
||||
for (int i = 0; i < oldlanes; ++i) {
|
||||
if (mr[oldfirst + i].nReg != -1)
|
||||
nr[mr[oldfirst + i].nReg].isDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Next, shuffle the desired element into first place.
|
||||
@@ -494,23 +534,24 @@ bool X64IRRegCache::TransferVecTo1(IRNativeReg nreg, IRNativeReg dest, IRReg fir
|
||||
emit_->VPERMILPS(128, FromNativeReg(dest), ::R(FromNativeReg(nreg)), shuf);
|
||||
} else if (mr[first].lane <= 0 && dest != nreg) {
|
||||
emit_->MOVAPS(FromNativeReg(dest), ::R(FromNativeReg(nreg)));
|
||||
} else if (mr[first].lane == 2) {
|
||||
emit_->MOVHLPS(FromNativeReg(dest), FromNativeReg(nreg));
|
||||
} else if (mr[first].lane > 0) {
|
||||
if (mr[first].lane == 2) {
|
||||
emit_->MOVHLPS(FromNativeReg(dest), FromNativeReg(nreg));
|
||||
} else {
|
||||
if (dest != nreg)
|
||||
emit_->MOVAPS(FromNativeReg(dest), ::R(FromNativeReg(nreg)));
|
||||
emit_->SHUFPS(FromNativeReg(dest), ::R(FromNativeReg(dest)), shuf);
|
||||
}
|
||||
if (dest != nreg)
|
||||
emit_->MOVAPS(FromNativeReg(dest), ::R(FromNativeReg(nreg)));
|
||||
emit_->SHUFPS(FromNativeReg(dest), ::R(FromNativeReg(dest)), shuf);
|
||||
}
|
||||
|
||||
// Now update accounting.
|
||||
for (int i = 0; i < oldlanes; ++i) {
|
||||
auto &mreg = mr[oldfirst + i];
|
||||
if (oldfirst + i == first) {
|
||||
mreg.lane = 0;
|
||||
mreg.lane = -1;
|
||||
mreg.nReg = dest;
|
||||
} else {
|
||||
} else if (mreg.nReg == nreg && i == 0 && nreg != dest) {
|
||||
// Still in the same register, but no longer a vec.
|
||||
mreg.lane = -1;
|
||||
} else if (mreg.nReg == nreg) {
|
||||
// No longer in a register.
|
||||
mreg.nReg = -1;
|
||||
mreg.lane = -1;
|
||||
@@ -520,8 +561,10 @@ bool X64IRRegCache::TransferVecTo1(IRNativeReg nreg, IRNativeReg dest, IRReg fir
|
||||
|
||||
if (dest != nreg) {
|
||||
nr[dest].isDirty = nr[nreg].isDirty;
|
||||
nr[nreg].mipsReg = -1;
|
||||
nr[nreg].isDirty = false;
|
||||
if (oldfirst == first) {
|
||||
nr[nreg].mipsReg = -1;
|
||||
nr[nreg].isDirty = false;
|
||||
}
|
||||
}
|
||||
nr[dest].mipsReg = first;
|
||||
|
||||
|
||||
Reference in new issue
Block a user