diff --git a/Core/MIPS/IR/IRRegCache.cpp b/Core/MIPS/IR/IRRegCache.cpp index 1f10205cea..c09a589f8d 100644 --- a/Core/MIPS/IR/IRRegCache.cpp +++ b/Core/MIPS/IR/IRRegCache.cpp @@ -159,6 +159,25 @@ bool IRNativeRegCacheBase::IsFPRMapped(IRReg fpr) { return mr[fpr + 32].loc == MIPSLoc::FREG || mr[fpr + 32].loc == MIPSLoc::VREG; } +int IRNativeRegCacheBase::GetFPRLaneCount(IRReg fpr) { + if (!IsFPRMapped(fpr) || mr[fpr].lane > 0) + return 0; + if (mr[fpr].lane == -1) + return 1; + + int c = 1; + for (int i = 1; i < 4; ++i) { + if (mr[fpr + i].nReg != mr[fpr].nReg || mr[fpr + i].loc != mr[fpr].loc) + return c; + if (mr[fpr + i].lane != i) + return c; + + c++; + } + + return c; +} + int IRNativeRegCacheBase::GetFPRLane(IRReg fpr) { _dbg_assert_(IsValidFPR(fpr)); if (mr[fpr + 32].loc == MIPSLoc::FREG || mr[fpr + 32].loc == MIPSLoc::VREG) { diff --git a/Core/MIPS/IR/IRRegCache.h b/Core/MIPS/IR/IRRegCache.h index 2504ad718d..4f14ba17f1 100644 --- a/Core/MIPS/IR/IRRegCache.h +++ b/Core/MIPS/IR/IRRegCache.h @@ -164,6 +164,7 @@ public: bool IsGPRMappedAsPointer(IRReg gpr); bool IsGPRMappedAsStaticPointer(IRReg gpr); int GetFPRLane(IRReg fpr); + int GetFPRLaneCount(IRReg fpr); bool IsGPRImm(IRReg gpr); bool IsGPR2Imm(IRReg base); diff --git a/Core/MIPS/x86/X64IRCompVec.cpp b/Core/MIPS/x86/X64IRCompVec.cpp index bd742403b8..26df74f635 100644 --- a/Core/MIPS/x86/X64IRCompVec.cpp +++ b/Core/MIPS/x86/X64IRCompVec.cpp @@ -212,7 +212,13 @@ void X64JitBackend::CompIR_VecAssign(IRInst inst) { break; case IROp::Vec4Shuffle: - regs_.Map(inst); + if (regs_.GetFPRLaneCount(inst.src1) == 1 && (inst.src1 & 3) == 0 && inst.src2 == 0) { + // This is a broadcast. If dest == src1, this won't clear it. + regs_.SpillLockFPR(inst.src1); + regs_.MapVec4(inst.dest, MIPSMap::NOINIT); + } else { + regs_.Map(inst); + } if (cpu_info.bAVX) { VPERMILPS(128, regs_.FX(inst.dest), regs_.F(inst.src1), inst.src2); } else {