From 68991511ee18a81d2a63ad778aa42475c13489d4 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 25 Jan 2013 23:09:11 +0100 Subject: [PATCH] Split out the FPU reg cache into its own file too. --- CMakeLists.txt | 4 +- Core/Core.vcxproj | 14 +++ Core/Core.vcxproj.filters | 12 ++ Core/MIPS/ARM/ArmRegCache.cpp | 8 +- Core/MIPS/ARM/ArmRegCache.h | 8 +- Core/MIPS/ARM/ArmRegCacheFPU.cpp | 20 ++++ Core/MIPS/ARM/ArmRegCacheFPU.h | 29 +++++ Core/MIPS/x86/CompFPU.cpp | 32 +++--- Core/MIPS/x86/CompVFPU.cpp | 4 +- Core/MIPS/x86/Jit.cpp | 4 +- Core/MIPS/x86/Jit.h | 7 +- Core/MIPS/x86/RegCache.cpp | 192 ++----------------------------- Core/MIPS/x86/RegCache.h | 78 +------------ Core/MIPS/x86/RegCacheFPU.cpp | 192 +++++++++++++++++++++++++++++++ Core/MIPS/x86/RegCacheFPU.h | 107 +++++++++++++++++ Qt/Core.pro | 9 +- android/jni/Android.mk | 1 + ext/snappy/snappy-stubs-public.h | 2 + 18 files changed, 433 insertions(+), 290 deletions(-) create mode 100644 Core/MIPS/ARM/ArmRegCacheFPU.cpp create mode 100644 Core/MIPS/ARM/ArmRegCacheFPU.h create mode 100644 Core/MIPS/x86/RegCacheFPU.cpp create mode 100644 Core/MIPS/x86/RegCacheFPU.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 691997d997..7b28f37763 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -618,7 +618,9 @@ elseif(X86) Core/MIPS/x86/JitCache.cpp Core/MIPS/x86/JitCache.h Core/MIPS/x86/RegCache.cpp - Core/MIPS/x86/RegCache.h) + Core/MIPS/x86/RegCache.h + Core/MIPS/x86/RegCacheFPU.cpp + Core/MIPS/x86/RegCacheFPU.h) endif() # 'ppsspp_jni' on ANDROID, 'Core' everywhere else diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 142f3b401a..40ec87f5e0 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -222,6 +222,12 @@ true true + + true + true + true + true + true true @@ -257,6 +263,7 @@ + @@ -370,6 +377,12 @@ true true + + true + true + true + true + @@ -382,6 +395,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index c7baaebccd..aeafbe3ada 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -369,6 +369,12 @@ Ext + + MIPS\x86 + + + MIPS\ARM + @@ -683,6 +689,12 @@ Ext + + MIPS\x86 + + + MIPS\ARM + diff --git a/Core/MIPS/ARM/ArmRegCache.cpp b/Core/MIPS/ARM/ArmRegCache.cpp index 3b9122bb18..4b539787eb 100644 --- a/Core/MIPS/ARM/ArmRegCache.cpp +++ b/Core/MIPS/ARM/ArmRegCache.cpp @@ -1,8 +1,8 @@ -// Copyright (C) 2003 Dolphin Project. +// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. +// the Free Software Foundation, version 2.0 or later versions. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,8 +12,8 @@ // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "ArmRegCache.h" #include "ArmEmitter.h" diff --git a/Core/MIPS/ARM/ArmRegCache.h b/Core/MIPS/ARM/ArmRegCache.h index f05451218e..7a57d7a4d7 100644 --- a/Core/MIPS/ARM/ArmRegCache.h +++ b/Core/MIPS/ARM/ArmRegCache.h @@ -1,8 +1,8 @@ -// Copyright (C) 2003 Dolphin Project. +// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. +// the Free Software Foundation, version 2.0 or later versions. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,8 +12,8 @@ // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #pragma once diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.cpp b/Core/MIPS/ARM/ArmRegCacheFPU.cpp new file mode 100644 index 0000000000..59314f3d5f --- /dev/null +++ b/Core/MIPS/ARM/ArmRegCacheFPU.cpp @@ -0,0 +1,20 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Common/ArmEmitter.h" +#include "Core/MIPS/ARM/ArmRegCacheFPU.h" + diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.h b/Core/MIPS/ARM/ArmRegCacheFPU.h new file mode 100644 index 0000000000..6b9fef2345 --- /dev/null +++ b/Core/MIPS/ARM/ArmRegCacheFPU.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Common/ArmEmitter.h" + + +// The PSP has 160 FP registers: 32 FPRs + 128 VFPU registers. + + +class FPURegCache { +public: + +}; \ No newline at end of file diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index f017c4f5d0..59e4f28eb5 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -46,7 +46,7 @@ void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), boo int ft = _FT; int fs = _FS; int fd = _FD; - fpr.Lock(ft, fs, fd); + fpr.SpillLock(ft, fs, fd); if (false && fs == fd) { @@ -66,7 +66,7 @@ void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), boo (this->*arith)(XMM0, R(XMM1)); MOVSS(fpr.RX(fd), R(XMM0)); } - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); } void Jit::Comp_FPU3op(u32 op) @@ -97,7 +97,7 @@ void Jit::Comp_FPULS(u32 op) { case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 gpr.Lock(rs); - fpr.Lock(ft); + fpr.SpillLock(ft); fpr.BindToRegister(ft, false, true); if (gpr.R(rs).IsImm()) @@ -181,11 +181,11 @@ void Jit::Comp_FPULS(u32 op) } gpr.UnlockAll(); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); break; case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 gpr.Lock(rs); - fpr.Lock(ft); + fpr.SpillLock(ft); fpr.BindToRegister(ft, true, false); if (gpr.R(rs).IsImm()) @@ -263,7 +263,7 @@ void Jit::Comp_FPULS(u32 op) } gpr.UnlockAll(); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); break; default: @@ -285,28 +285,28 @@ void Jit::Comp_FPU2op(u32 op) switch (op & 0x3f) { case 5: //F(fd) = fabsf(F(fs)); break; //abs - fpr.Lock(fd, fs); + fpr.SpillLock(fd, fs); fpr.BindToRegister(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); PAND(fpr.RX(fd), M((void *)ssNoSignMask)); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); break; case 6: //F(fd) = F(fs); break; //mov if (fd != fs) { - fpr.Lock(fd, fs); + fpr.SpillLock(fd, fs); fpr.BindToRegister(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); } break; case 7: //F(fd) = -F(fs); break; //neg - fpr.Lock(fd, fs); + fpr.SpillLock(fd, fs); fpr.BindToRegister(fd, fd == fs, true); MOVSS(fpr.RX(fd), fpr.R(fs)); PXOR(fpr.RX(fd), M((void *)ssSignBits2)); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); break; case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s @@ -321,11 +321,11 @@ void Jit::Comp_FPU2op(u32 op) return; case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s - fpr.Lock(fs, fd); + fpr.SpillLock(fs, fd); fpr.StoreFromRegister(fd); CVTTSS2SI(EAX, fpr.R(fs)); MOV(32, fpr.R(fd), R(EAX)); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); break; case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s @@ -363,10 +363,10 @@ void Jit::Comp_mxc1(u32 op) case 4: //FI(fs) = R(rt); break; //mtc1 // Cross move! slightly tricky gpr.StoreFromRegister(rt); - fpr.Lock(fs); + fpr.SpillLock(fs); fpr.BindToRegister(fs, false, true); MOVSS(fpr.RX(fs), gpr.R(rt)); - fpr.UnlockAll(); + fpr.ReleaseSpillLocks(); return; case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1 diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index befb910367..7f08025c3d 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -58,7 +58,7 @@ void Jit::Comp_SVQ(u32 op) if (!g_Config.bFastMemory) { DISABLE; } - fpr.Flush(FLUSH_ALL); + fpr.Flush(); gpr.BindToRegister(rs, true, true); u8 vregs[4]; @@ -92,7 +92,7 @@ void Jit::Comp_SVQ(u32 op) if (!g_Config.bFastMemory) { DISABLE; } - fpr.Flush(FLUSH_ALL); + fpr.Flush(); gpr.BindToRegister(rs, true, true); u8 vregs[4]; diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 963cf8e0f5..84f0a9121a 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -106,8 +106,8 @@ Jit::Jit(MIPSState *mips) : blocks(mips), mips_(mips) void Jit::FlushAll() { - gpr.Flush(FLUSH_ALL); - fpr.Flush(FLUSH_ALL); + gpr.Flush(); + fpr.Flush(); } void Jit::WriteDowncount(int offset) diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 5b14dd768d..6599a54c71 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -17,17 +17,18 @@ #pragma once -#include "../../../Globals.h" -#include "../../../Common/Thunk.h" +#include "Globals.h" +#include "Common/Thunk.h" #include "Asm.h" #if defined(ARM) #error DO NOT BUILD X86 JIT ON ARM #endif -#include "x64Emitter.h" +#include "Common/x64Emitter.h" #include "JitCache.h" #include "RegCache.h" +#include "RegCacheFPU.h" namespace MIPSComp { diff --git a/Core/MIPS/x86/RegCache.cpp b/Core/MIPS/x86/RegCache.cpp index 02c447a488..cb863533ef 100644 --- a/Core/MIPS/x86/RegCache.cpp +++ b/Core/MIPS/x86/RegCache.cpp @@ -15,12 +15,12 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "../MIPS.h" -#include "../MIPSTables.h" -#include "../MIPSAnalyst.h" -#include "Jit.h" -#include "Asm.h" -#include "RegCache.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSTables.h" +#include "Core/MIPS/MIPSAnalyst.h" +#include "Core/MIPS/x86/Jit.h" +#include "Core/MIPS/x86/Asm.h" +#include "Core/MIPS/x86/RegCache.h" using namespace Gen; @@ -59,7 +59,7 @@ void GPRRegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) { // todo: sort to find the most popular regs /* int maxPreload = 2; - for (int i = 0; i < 32; i++) + for (int i = 0; i < NUM_MIPS_GPRS; i++) { if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2) { @@ -94,7 +94,7 @@ void GPRRegCache::LockX(int x1, int x2, int x3, int x4) { } void GPRRegCache::UnlockAll() { - for (int i = 0; i < 32; i++) + for (int i = 0; i < NUM_MIPS_GPRS; i++) regs[i].locked = false; } @@ -144,7 +144,7 @@ void GPRRegCache::FlushR(X64Reg reg) } int GPRRegCache::SanityCheck() const { - for (int i = 0; i < 32; i++) { + for (int i = 0; i < NUM_MIPS_GPRS; i++) { if (regs[i].away) { if (regs[i].location.IsSimpleReg()) { Gen::X64Reg simple = regs[i].location.GetSimpleReg(); @@ -276,13 +276,13 @@ void GPRRegCache::StoreFromRegister(int i) { } } -void GPRRegCache::Flush(FlushMode mode) +void GPRRegCache::Flush() { for (int i = 0; i < NUM_X_REGS; i++) { if (xregs[i].allocLocked) PanicAlert("Someone forgot to unlock X64 reg %i.", i); } - for (int i = 0; i < 32; i++) { + for (int i = 0; i < NUM_MIPS_GPRS; i++) { if (regs[i].locked) { PanicAlert("Somebody forgot to unlock MIPS reg %i.", i); } @@ -299,174 +299,4 @@ void GPRRegCache::Flush(FlushMode mode) } } } -} - -FPURegCache::FPURegCache() : emit(0), mips(0) { - memset(regs, 0, sizeof(regs)); - memset(xregs, 0, sizeof(xregs)); -} - -void FPURegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) { - this->mips = mips; - for (int i = 0; i < NUM_X_REGS; i++) { - xregs[i].free = true; - xregs[i].dirty = false; - xregs[i].allocLocked = false; - } - for (int i = 0; i < 32; i++) { - regs[i].location = GetDefaultLocation(i); - regs[i].away = false; - regs[i].locked = false; - } -} - -void FPURegCache::Lock(int p1, int p2, int p3, int p4) { - regs[p1].locked = true; - if (p2 != 0xFF) regs[p2].locked = true; - if (p3 != 0xFF) regs[p3].locked = true; - if (p4 != 0xFF) regs[p4].locked = true; -} - -void FPURegCache::UnlockAll() { - for (int i = 0; i < 32; i++) - regs[i].locked = false; -} - -void FPURegCache::UnlockAllX() { - for (int i = 0; i < NUM_X_REGS; i++) - xregs[i].allocLocked = false; -} - -void FPURegCache::BindToRegister(int i, bool doLoad, bool makeDirty) { - _assert_msg_(DYNA_REC, !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_(DYNA_REC, xr < NUM_X_REGS, "WTF - load - invalid reg"); - xregs[xr].mipsReg = i; - xregs[xr].free = false; - 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].away = true; - } 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; - } -} - -void FPURegCache::StoreFromRegister(int i) { - _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm"); - if (regs[i].away) { - X64Reg xr = regs[i].location.GetSimpleReg(); - _assert_msg_(DYNA_REC, xr < NUM_X_REGS, "WTF - store - invalid reg"); - xregs[xr].free = true; - xregs[xr].dirty = false; - xregs[xr].mipsReg = -1; - OpArg newLoc = GetDefaultLocation(i); - emit->MOVSS(newLoc, xr); - regs[i].location = newLoc; - regs[i].away = false; - } else { - // _assert_msg_(DYNA_REC,0,"already stored"); - } -} - -void FPURegCache::Flush(FlushMode mode) { - for (int i = 0; i < NUM_X_REGS; i++) { - if (xregs[i].allocLocked) - PanicAlert("Someone forgot to unlock X64 reg %i.", i); - } - for (int i = 0; i < 32; 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); - } - } - } -} - -OpArg FPURegCache::GetDefaultLocation(int reg) const { - return M(&mips->f[reg]); -} - -int FPURegCache::SanityCheck() const { - for (int i = 0; i < 32; i++) { - if (regs[i].away) { - if (regs[i].location.IsSimpleReg()) { - Gen::X64Reg simple = regs[i].location.GetSimpleReg(); - if (xregs[simple].allocLocked) - return 1; - if (xregs[simple].mipsReg != i) - return 2; - } - else if (regs[i].location.IsImm()) - return 3; - } - } - return 0; -} - -const int *FPURegCache::GetAllocationOrder(int &count) { - static const int allocationOrder[] = { -#ifdef _M_X64 - XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5 -#elif _M_IX86 - XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, -#endif - }; - count = sizeof(allocationOrder) / sizeof(int); - return allocationOrder; -} - -X64Reg FPURegCache::GetFreeXReg() { - int aCount; - const int *aOrder = GetAllocationOrder(aCount); - for (int i = 0; i < aCount; i++) { - X64Reg xr = (X64Reg)aOrder[i]; - if (!xregs[xr].allocLocked && xregs[xr].free) { - 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]; - if (xregs[xr].allocLocked) - continue; - int preg = xregs[xr].mipsReg; - if (!regs[preg].locked) { - StoreFromRegister(preg); - return xr; - } - } - //Still no dice? Die! - _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs"); - return (X64Reg) -1; -} - -void FPURegCache::FlushR(X64Reg reg) { - if (reg >= NUM_X_REGS) - PanicAlert("Flushing non existent reg"); - if (!xregs[reg].free) { - StoreFromRegister(xregs[reg].mipsReg); - } } \ No newline at end of file diff --git a/Core/MIPS/x86/RegCache.h b/Core/MIPS/x86/RegCache.h index 46c7a3b66e..c1a12b22d9 100644 --- a/Core/MIPS/x86/RegCache.h +++ b/Core/MIPS/x86/RegCache.h @@ -21,36 +21,20 @@ #include "../MIPSAnalyst.h" using namespace Gen; -enum FlushMode -{ - FLUSH_ALL -}; -enum GrabMode -{ - M_READ = 1, - M_WRITE = 2, - M_READWRITE = 3, -}; - -struct MIPSCachedReg -{ +struct MIPSCachedReg { OpArg location; bool away; // value not in source register bool locked; }; -struct X64CachedReg -{ +struct X64CachedReg { int mipsReg; bool dirty; bool free; bool allocLocked; }; -typedef int XReg; -typedef int PReg; - #ifdef _M_X64 #define NUM_X_REGS 16 #elif _M_IX86 @@ -59,12 +43,10 @@ typedef int PReg; // TODO: Add more cachable regs, like HI, LO #define NUM_MIPS_GPRS 32 -#define NUM_MIPS_FPRS 32 class GPRRegCache { public: - MIPSState *mips; GPRRegCache(); ~GPRRegCache() {} void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats); @@ -81,7 +63,7 @@ public: FlushR(reg1); FlushR(reg2); LockX(reg1); LockX(reg2); } - void Flush(FlushMode mode); + void Flush(); int SanityCheck() const; void KillImmediate(int preg, bool doLoad, bool makeDirty); @@ -104,69 +86,17 @@ public: void UnlockAll(); void UnlockAllX(); - X64Reg GetFreeXReg(); - void SetImmediate32(int preg, u32 immValue); bool IsImmediate(int preg) const; u32 GetImmediate32(int preg) const; -private: - MIPSCachedReg regs[NUM_MIPS_GPRS]; - X64CachedReg xregs[NUM_X_REGS]; - - const int *GetAllocationOrder(int &count); - - XEmitter *emit; -}; - - -// Now also with VFPU support! -class FPURegCache -{ -public: MIPSState *mips; - FPURegCache(); - ~FPURegCache() {} - - void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats); - void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true); - void StoreFromRegister(int preg); - OpArg GetDefaultLocation(int reg) const; - - void SetEmitter(XEmitter *emitter) {emit = emitter;} - - void FlushLockX(X64Reg reg) { - FlushR(reg); - LockX(reg); - } - void FlushLockX(X64Reg reg1, X64Reg reg2) { - FlushR(reg1); FlushR(reg2); - LockX(reg1); LockX(reg2); - } - void Flush(FlushMode mode); - int SanityCheck() const; - - const OpArg &R(int preg) const {return regs[preg].location;} - X64Reg RX(int preg) const - { - if (regs[preg].away && regs[preg].location.IsSimpleReg()) - return regs[preg].location.GetSimpleReg(); - PanicAlert("Not so simple - %i", preg); - return (X64Reg)-1; - } - - // Register locking. Prevents them from being spilled. - void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff); - void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff); - void UnlockAll(); - void UnlockAllX(); private: X64Reg GetFreeXReg(); - void FlushR(X64Reg reg); const int *GetAllocationOrder(int &count); - MIPSCachedReg regs[NUM_MIPS_FPRS]; + MIPSCachedReg regs[NUM_MIPS_GPRS]; X64CachedReg xregs[NUM_X_REGS]; XEmitter *emit; diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp new file mode 100644 index 0000000000..7625b486d9 --- /dev/null +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -0,0 +1,192 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Common/Log.h" +#include "Common/x64Emitter.h" +#include "Core/MIPS/MIPSAnalyst.h" +#include "Core/MIPS/x86/RegCacheFPU.h" + +FPURegCache::FPURegCache() : emit(0), mips(0) { + memset(regs, 0, sizeof(regs)); + memset(xregs, 0, sizeof(xregs)); + vregs = regs + 32; +} + +void FPURegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) { + this->mips = mips; + for (int i = 0; i < NUM_X_FPREGS; i++) { + xregs[i].mipsReg = -1; + xregs[i].dirty = false; + } + for (int i = 0; i < NUM_MIPS_FPRS; i++) { + regs[i].location = GetDefaultLocation(i); + regs[i].away = false; + regs[i].locked = false; + } +} + +void FPURegCache::SpillLock(int p1, int p2, int p3, int p4) { + regs[p1].locked = true; + if (p2 != 0xFF) regs[p2].locked = true; + if (p3 != 0xFF) regs[p3].locked = true; + if (p4 != 0xFF) regs[p4].locked = true; +} + +void FPURegCache::SpillLockV(const u8 *v, VectorSize vsz) { + for (int i = 0; i < GetNumVectorElements(vsz); i++) { + vregs[i].locked = true; + } +} + +void FPURegCache::SpillLockV(int vec, VectorSize vsz) { + u8 v[4]; + GetVectorRegs(v, vsz, vec); + SpillLockV(v, vsz); +} + +void FPURegCache::ReleaseSpillLocks() { + for (int i = 0; i < NUM_MIPS_FPRS; i++) + regs[i].locked = false; +} + +void FPURegCache::BindToRegister(int i, bool doLoad, bool makeDirty) { + _assert_msg_(DYNA_REC, !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_(DYNA_REC, 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].away = true; + } 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; + } +} + +void FPURegCache::StoreFromRegister(int i) { + _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm"); + if (regs[i].away) { + X64Reg xr = regs[i].location.GetSimpleReg(); + _assert_msg_(DYNA_REC, xr < NUM_X_FPREGS, "WTF - store - invalid reg"); + xregs[xr].dirty = false; + xregs[xr].mipsReg = -1; + OpArg newLoc = GetDefaultLocation(i); + emit->MOVSS(newLoc, xr); + regs[i].location = newLoc; + regs[i].away = false; + } else { + // _assert_msg_(DYNA_REC,0,"already stored"); + } +} + +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); + } + } + } +} + +OpArg FPURegCache::GetDefaultLocation(int reg) const { + if (reg < 32) { + return M(&mips->f[reg]); + } else { + return M(&mips->v[reg - 32]); + } +} + +int FPURegCache::SanityCheck() const { + for (int i = 0; i < NUM_MIPS_FPRS; i++) { + if (regs[i].away) { + if (regs[i].location.IsSimpleReg()) { + Gen::X64Reg simple = regs[i].location.GetSimpleReg(); + if (xregs[simple].mipsReg != i) + return 2; + } + else if (regs[i].location.IsImm()) + return 3; + } + } + return 0; +} + +const int *FPURegCache::GetAllocationOrder(int &count) { + static const int allocationOrder[] = { +#ifdef _M_X64 + XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5 +#elif _M_IX86 + XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, +#endif + }; + count = sizeof(allocationOrder) / sizeof(int); + return allocationOrder; +} + +X64Reg FPURegCache::GetFreeXReg() { + 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_(DYNA_REC, 0, "Regcache ran out of regs"); + return (X64Reg) -1; +} + +void FPURegCache::FlushR(X64Reg reg) { + if (reg >= NUM_X_FPREGS) + PanicAlert("Flushing non existent reg"); + if (xregs[reg].mipsReg != -1) { + StoreFromRegister(xregs[reg].mipsReg); + } +} \ No newline at end of file diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h new file mode 100644 index 0000000000..f4c2fff3ed --- /dev/null +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -0,0 +1,107 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Common/x64Emitter.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" +#include "Core/MIPS/MIPSVFPUUtils.h" + +using namespace Gen; + + +// GPRs are numbered 0 to 31 +// VFPU regs are numbered 32 to 160. + +#define NUM_MIPS_FPRS (32 + 128) + +#ifdef _M_X64 +#define NUM_X_FPREGS 16 +#elif _M_IX86 +#define NUM_X_FPREGS 8 +#endif + +struct X64CachedFPReg { + int mipsReg; + bool dirty; +}; + +struct MIPSCachedFPReg { + OpArg location; + bool away; // value not in source register + bool locked; +}; + +// The PSP has 160 FP registers: 32 FPRs + 128 VFPU registers. +// Soon we will support them all. + +class FPURegCache +{ +public: + FPURegCache(); + ~FPURegCache() {} + + void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats); + void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true); + void StoreFromRegister(int preg); + OpArg GetDefaultLocation(int reg) const; + + void SetEmitter(XEmitter *emitter) {emit = emitter;} + + void Flush(); + int SanityCheck() const; + + const OpArg &R(int freg) const {return regs[freg].location;} + const OpArg &V(int vreg) const {return regs[32 + vreg].location;} + + X64Reg RX(int freg) const + { + if (regs[freg].away && regs[freg].location.IsSimpleReg()) + return regs[freg].location.GetSimpleReg(); + PanicAlert("Not so simple - f%i", freg); + return (X64Reg)-1; + } + + X64Reg VX(int vreg) const + { + if (regs[vreg + 32].away && regs[vreg + 32].location.IsSimpleReg()) + return regs[vreg + 32].location.GetSimpleReg(); + PanicAlert("Not so simple - v%i", vreg); + return (X64Reg)-1; + } + + // Register locking. Prevents them from being spilled. + void SpillLock(int p1, int p2=0xff, int p3=0xff, int p4=0xff); + void ReleaseSpillLocks(); + + void SpillLockV(const u8 *v, VectorSize vsz); + void SpillLockV(int vec, VectorSize vsz); + + MIPSState *mips; + +private: + X64Reg GetFreeXReg(); + void FlushR(X64Reg reg); + const int *GetAllocationOrder(int &count); + + MIPSCachedFPReg regs[NUM_MIPS_FPRS]; + X64CachedFPReg xregs[NUM_X_FPREGS]; + MIPSCachedFPReg *vregs; + + XEmitter *emit; +}; diff --git a/Qt/Core.pro b/Qt/Core.pro index dbafc2514b..cf96fac6ea 100755 --- a/Qt/Core.pro +++ b/Qt/Core.pro @@ -18,12 +18,13 @@ arm { ../Core/MIPS/ARM/ArmJit.cpp \ ../Core/MIPS/ARM/ArmJitCache.cpp \ ../Core/MIPS/ARM/ArmRegCache.cpp \ + ../Core/MIPS/ARM/ArmRegCacheFPU.cpp \ ../ext/disarm.cpp - HEADERS += ../Core/MIPS/ARM/ArmAsm.h \ ../Core/MIPS/ARM/ArmJit.h \ ../Core/MIPS/ARM/ArmJitCache.h \ ../Core/MIPS/ARM/ArmRegCache.h + ../Core/MIPS/ARM/ArmRegCacheFPU.h } x86 { SOURCES += ../Core/MIPS/x86/Asm.cpp \ @@ -34,11 +35,13 @@ x86 { ../Core/MIPS/x86/CompVFPU.cpp \ ../Core/MIPS/x86/Jit.cpp \ ../Core/MIPS/x86/JitCache.cpp \ - ../Core/MIPS/x86/RegCache.cpp + ../Core/MIPS/x86/RegCache.cpp \ + ../Core/MIPS/x86/RegCacheFPU.cpp HEADERS += ../Core/MIPS/x86/Asm.h \ ../Core/MIPS/x86/Jit.h \ ../Core/MIPS/x86/JitCache.h \ - ../Core/MIPS/x86/RegCache.h + ../Core/MIPS/x86/RegCache.h \ + ../Core/MIPS/x86/RegCacheFPU.h } SOURCES += ../Core/CPU.cpp \ # Core diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 3e3356e0d8..68366e380c 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -177,6 +177,7 @@ LOCAL_SRC_FILES := \ $(SRC)/Core/MIPS/ARM/ArmAsm.cpp \ $(SRC)/Core/MIPS/ARM/ArmJit.cpp \ $(SRC)/Core/MIPS/ARM/ArmRegCache.cpp \ + $(SRC)/Core/MIPS/ARM/ArmRegCacheFPU.cpp \ $(SRC)/Core/Util/BlockAllocator.cpp \ $(SRC)/Core/Util/ppge_atlas.cpp \ $(SRC)/Core/Util/PPGeDraw.cpp diff --git a/ext/snappy/snappy-stubs-public.h b/ext/snappy/snappy-stubs-public.h index e97fc24682..9b52a5d2d0 100644 --- a/ext/snappy/snappy-stubs-public.h +++ b/ext/snappy/snappy-stubs-public.h @@ -52,9 +52,11 @@ typedef uint64_t uint64; typedef std::string string; +#ifndef DISALLOW_COPY_AND_ASSIGN #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) +#endif } // namespace snappy