void FPURegCache::FlushR(X64Reg reg) { if (reg >= NUM_X_FPREGS) PanicAlert("Flushing non existent reg"); if (xregs[reg].mipsReg != -1) { StoreFromRegister(xregs[reg].mipsReg); } }
void FPURegCache::MapReg(const int i, bool doLoad, bool makeDirty) { pendingFlush = true; _assert_msg_(JIT, !regs[i].location.IsImm(), "WTF - load - imm"); if (!regs[i].away) { // Reg is at home in the memory register file. Let's pull it out. X64Reg xr = GetFreeXReg(); _assert_msg_(JIT, xr >= 0 && xr < NUM_X_FPREGS, "WTF - load - invalid reg"); xregs[xr].mipsReg = i; xregs[xr].dirty = makeDirty; OpArg newloc = ::Gen::R(xr); if (doLoad) { if (!regs[i].location.IsImm() && (regs[i].location.offset & 0x3)) { PanicAlert("WARNING - misaligned fp register location %i", i); } emit->MOVSS(xr, regs[i].location); } regs[i].location = newloc; regs[i].lane = 0; regs[i].away = true; } else if (regs[i].lane != 0) { // Well, darn. This means we need to flush it. // TODO: This could be more optimal. Also check flags. StoreFromRegister(i); MapReg(i, doLoad, makeDirty); } else { // There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary. xregs[RX(i)].dirty |= makeDirty; _assert_msg_(JIT, regs[i].location.IsSimpleReg(), "not loaded and not simple."); } Invariant(); }
X64Reg FPURegCache::GetFreeXReg() { pendingFlush = true; int aCount; const int *aOrder = GetAllocationOrder(aCount); for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; if (xregs[xr].mipsReg == -1) { return (X64Reg)xr; } } //Okay, not found :( Force grab one //TODO - add a pass to grab xregs whose mipsreg is not used in the next 3 instructions for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; int preg = xregs[xr].mipsReg; if (!regs[preg].locked) { StoreFromRegister(preg); return xr; } } //Still no dice? Die! _assert_msg_(JIT, 0, "Regcache ran out of regs"); return (X64Reg) -1; }
void FPURegCache::Flush() { for (int i = 0; i < NUM_MIPS_FPRS; i++) { if (regs[i].locked) { PanicAlert("Somebody forgot to unlock MIPS reg %i.", i); } if (regs[i].away) { if (regs[i].location.IsSimpleReg()) { X64Reg xr = RX(i); StoreFromRegister(i); xregs[xr].dirty = false; } else if (regs[i].location.IsImm()) { StoreFromRegister(i); } else { _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc); } } } }
void WriteRegToAddr(int sbits, const void* ptr, u32 mask) { m_emit->MOVP2R(X0, ptr); // If we do not need to mask, we can do the sign extend while loading // from memory. If masking is required, we have to first zero extend, // then mask, then sign extend if needed (1 instr vs. ~4). u32 all_ones = (1ULL << sbits) - 1; if ((all_ones & mask) == all_ones) { StoreFromRegister(sbits, m_src_reg); } else { m_emit->ANDI2R(W1, m_src_reg, mask, W1); StoreFromRegister(sbits, W1); } }
int FPURegCache::GetFreeXRegs(X64Reg *res, int n, bool spill) { pendingFlush = true; int aCount; const int *aOrder = GetAllocationOrder(aCount); _dbg_assert_msg_(JIT, n <= NUM_X_FPREGS - 2, "Cannot obtain that many regs."); int r = 0; for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; if (xregs[xr].mipsReg == -1) { res[r++] = (X64Reg)xr; if (r >= n) { break; } } } if (r < n && spill) { // Okay, not found :(... Force grab one. // TODO - add a pass to grab xregs whose mipsreg is not used in the next 3 instructions. for (int i = 0; i < aCount; i++) { X64Reg xr = (X64Reg)aOrder[i]; int preg = xregs[xr].mipsReg; // We're only spilling here, so don't overlap. if (preg != -1 && !regs[preg].locked) { StoreFromRegister(preg); res[r++] = xr; if (r >= n) { break; } } } } for (int i = r; i < n; ++i) { res[i] = INVALID_REG; } return r; }