aboutsummaryrefslogtreecommitdiff
path: root/src/ARMJIT_RegisterCache.h
diff options
context:
space:
mode:
authorRSDuck <rsduck@users.noreply.github.com>2019-07-10 00:57:59 +0200
committerRSDuck <rsduck@users.noreply.github.com>2020-06-16 11:53:08 +0200
commit27cbc821b139b74142630c57f7da11478a052282 (patch)
tree1045f8803931de9487ce2d39c417dfa1dd692568 /src/ARMJIT_RegisterCache.h
parent10e386fe50af1a11ada54a380f6802025fca8efd (diff)
jit: thumb block transfer working
also pc and sp relative loads and some refactoring
Diffstat (limited to 'src/ARMJIT_RegisterCache.h')
-rw-r--r--src/ARMJIT_RegisterCache.h136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/ARMJIT_RegisterCache.h b/src/ARMJIT_RegisterCache.h
new file mode 100644
index 0000000..04c1eda
--- /dev/null
+++ b/src/ARMJIT_RegisterCache.h
@@ -0,0 +1,136 @@
+#ifndef ARMJIT_REGCACHE_H
+#define ARMJIT_REGCACHE_H
+
+#include "ARMJIT.h"
+
+// TODO: replace this in the future
+#include "dolphin/BitSet.h"
+
+#include <assert.h>
+
+namespace ARMJIT
+{
+
+template <typename T, typename Reg>
+class RegisterCache
+{
+public:
+ RegisterCache()
+ {}
+
+ RegisterCache(T* compiler, FetchedInstr instrs[], int instrsCount)
+ : Compiler(compiler), Instrs(instrs), InstrsCount(instrsCount)
+ {
+ for (int i = 0; i < 16; i++)
+ Mapping[i] = (Reg)-1;
+ }
+
+ void UnloadRegister(int reg)
+ {
+ assert(Mapping[reg] != -1);
+
+ if (DirtyRegs & (1 << reg))
+ Compiler->SaveReg(reg, Mapping[reg]);
+
+ DirtyRegs &= ~(1 << reg);
+ LoadedRegs &= ~(1 << reg);
+ NativeRegsUsed &= ~(1 << (int)Mapping[reg]);
+ Mapping[reg] = (Reg)-1;
+ }
+
+ void LoadRegister(int reg)
+ {
+ assert(Mapping[reg] == -1);
+ for (int i = 0; i < NativeRegsAvailable; i++)
+ {
+ Reg nativeReg = NativeRegAllocOrder[i];
+ if (!(NativeRegsUsed & (1 << nativeReg)))
+ {
+ Mapping[reg] = nativeReg;
+ NativeRegsUsed |= 1 << (int)nativeReg;
+ LoadedRegs |= 1 << reg;
+
+ Compiler->LoadReg(reg, nativeReg);
+
+ return;
+ }
+ }
+
+ assert("Welp!");
+ }
+
+ void Flush()
+ {
+ BitSet16 loadedSet(LoadedRegs);
+ for (int reg : loadedSet)
+ UnloadRegister(reg);
+ }
+
+ void Prepare(int i)
+ {
+ u16 futureNeeded = 0;
+ int ranking[16];
+ for (int j = 0; j < 16; j++)
+ ranking[j] = 0;
+ for (int j = i; j < InstrsCount; j++)
+ {
+ BitSet16 regsNeeded((Instrs[j].Info.SrcRegs & ~(1 << 15)) | Instrs[j].Info.DstRegs);
+ futureNeeded |= regsNeeded.m_val;
+ for (int reg : regsNeeded)
+ ranking[reg]++;
+ }
+
+ // we'll unload all registers which are never used again
+ BitSet16 neverNeededAgain(LoadedRegs & ~futureNeeded);
+ for (int reg : neverNeededAgain)
+ UnloadRegister(reg);
+
+ FetchedInstr Instr = Instrs[i];
+ u16 necessaryRegs = (Instr.Info.SrcRegs & ~(1 << 15)) | Instr.Info.DstRegs;
+ BitSet16 needToBeLoaded(necessaryRegs & ~LoadedRegs);
+ if (needToBeLoaded != BitSet16(0))
+ {
+ int neededCount = needToBeLoaded.Count();
+ BitSet16 loadedSet(LoadedRegs);
+ while (loadedSet.Count() + neededCount > NativeRegsAvailable)
+ {
+ int leastReg = -1;
+ int rank = 1000;
+ for (int reg : loadedSet)
+ {
+ if (!((1 << reg) & necessaryRegs) && ranking[reg] < rank)
+ {
+ leastReg = reg;
+ rank = ranking[reg];
+ }
+ }
+
+ assert(leastReg != -1);
+ UnloadRegister(leastReg);
+
+ loadedSet.m_val = LoadedRegs;
+ }
+
+ for (int reg : needToBeLoaded)
+ LoadRegister(reg);
+ }
+ DirtyRegs |= Instr.Info.DstRegs & ~(1 << 15);
+ }
+
+ static const Reg NativeRegAllocOrder[];
+ static const int NativeRegsAvailable;
+
+ Reg Mapping[16];
+ u32 NativeRegsUsed = 0;
+ u16 LoadedRegs = 0;
+ u16 DirtyRegs = 0;
+
+ T* Compiler;
+
+ FetchedInstr* Instrs;
+ int InstrsCount;
+};
+
+}
+
+#endif \ No newline at end of file