summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorskidau <skidau@gmail.com>2014-10-07 13:26:23 +1100
committerskidau <skidau@gmail.com>2014-10-07 13:26:23 +1100
commitb3b34d16e6591cfe3aa879b2d4643c1415424a3b (patch)
tree6db8662f202359d6061179976bf65a53dba46694 /Source
parent8fdf43109f69cdf0a8219b1232ad3043987beb00 (diff)
parentc7208318fb9f9fd535f0f78c7c2956d874ef5b98 (diff)
Merge pull request #1218 from hthh/trampolinecaching
JIT: reuse trampolines when possible
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Common/x64Analyzer.cpp16
-rw-r--r--Source/Core/Common/x64Analyzer.h2
-rw-r--r--Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp68
-rw-r--r--Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h25
4 files changed, 100 insertions, 11 deletions
diff --git a/Source/Core/Common/x64Analyzer.cpp b/Source/Core/Common/x64Analyzer.cpp
index 5be91ea585..7e8b40e6cd 100644
--- a/Source/Core/Common/x64Analyzer.cpp
+++ b/Source/Core/Common/x64Analyzer.cpp
@@ -223,3 +223,19 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
info->instructionSize = (int)(codePtr - startCodePtr);
return true;
}
+
+bool InstructionInfo::operator==(const InstructionInfo &other) const
+{
+ return operandSize == other.operandSize &&
+ instructionSize == other.instructionSize &&
+ regOperandReg == other.regOperandReg &&
+ otherReg == other.otherReg &&
+ scaledReg == other.scaledReg &&
+ zeroExtend == other.zeroExtend &&
+ signExtend == other.signExtend &&
+ hasImmediate == other.hasImmediate &&
+ isMemoryWrite == other.isMemoryWrite &&
+ byteSwap == other.byteSwap &&
+ immediate == other.immediate &&
+ displacement == other.displacement;
+}
diff --git a/Source/Core/Common/x64Analyzer.h b/Source/Core/Common/x64Analyzer.h
index 4858f099da..c87a89a51f 100644
--- a/Source/Core/Common/x64Analyzer.h
+++ b/Source/Core/Common/x64Analyzer.h
@@ -20,6 +20,8 @@ struct InstructionInfo
bool byteSwap;
u64 immediate;
s32 displacement;
+
+ bool operator==(const InstructionInfo &other) const;
};
struct ModRM
diff --git a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp
index ae83eec2d5..7b23ac1427 100644
--- a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp
+++ b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp
@@ -19,25 +19,42 @@
using namespace Gen;
-extern u8 *trampolineCodePtr;
-
void TrampolineCache::Init()
{
- AllocCodeSpace(4 * 1024 * 1024);
+ AllocCodeSpace(8 * 1024 * 1024);
+}
+
+void TrampolineCache::ClearCodeSpace()
+{
+ X64CodeBlock::ClearCodeSpace();
+ cachedTrampolines.clear();
}
void TrampolineCache::Shutdown()
{
FreeCodeSpace();
+ cachedTrampolines.clear();
+}
+
+const u8* TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 registersInUse)
+{
+ TrampolineCacheKey key = { registersInUse, 0, info };
+
+ auto it = cachedTrampolines.find(key);
+ if (it != cachedTrampolines.end())
+ return it->second;
+
+ const u8* trampoline = GenerateReadTrampoline(info, registersInUse);
+ cachedTrampolines[key] = trampoline;
+ return trampoline;
}
-// Extremely simplistic - just generate the requested trampoline. May reuse them in the future.
-const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 registersInUse)
+const u8* TrampolineCache::GenerateReadTrampoline(const InstructionInfo &info, u32 registersInUse)
{
if (GetSpaceLeft() < 1024)
PanicAlert("Trampoline cache full");
- const u8 *trampoline = GetCodePtr();
+ const u8* trampoline = GetCodePtr();
X64Reg addrReg = (X64Reg)info.scaledReg;
X64Reg dataReg = (X64Reg)info.regOperandReg;
@@ -80,13 +97,25 @@ const u8 *TrampolineCache::GetReadTrampoline(const InstructionInfo &info, u32 re
return trampoline;
}
-// Extremely simplistic - just generate the requested trampoline. May reuse them in the future.
-const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc)
+const u8* TrampolineCache::GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc)
+{
+ TrampolineCacheKey key = { registersInUse, pc, info };
+
+ auto it = cachedTrampolines.find(key);
+ if (it != cachedTrampolines.end())
+ return it->second;
+
+ const u8* trampoline = GenerateWriteTrampoline(info, registersInUse, pc);
+ cachedTrampolines[key] = trampoline;
+ return trampoline;
+}
+
+const u8* TrampolineCache::GenerateWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc)
{
if (GetSpaceLeft() < 1024)
PanicAlert("Trampoline cache full");
- const u8 *trampoline = GetCodePtr();
+ const u8* trampoline = GetCodePtr();
X64Reg dataReg = (X64Reg)info.regOperandReg;
X64Reg addrReg = (X64Reg)info.scaledReg;
@@ -153,4 +182,25 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info, u32 r
return trampoline;
}
+size_t TrampolineCacheKeyHasher::operator()(const TrampolineCacheKey& k) const
+{
+ size_t res = std::hash<int>()(k.registersInUse);
+ res ^= std::hash<int>()(k.info.operandSize) >> 1;
+ res ^= std::hash<int>()(k.info.regOperandReg) >> 2;
+ res ^= std::hash<int>()(k.info.scaledReg) >> 3;
+ res ^= std::hash<u64>()(k.info.immediate) >> 4;
+ res ^= std::hash<int>()(k.pc) >> 5;
+ res ^= std::hash<int>()(k.info.displacement) << 1;
+ res ^= std::hash<bool>()(k.info.signExtend) << 2;
+ res ^= std::hash<bool>()(k.info.hasImmediate) << 3;
+ res ^= std::hash<bool>()(k.info.isMemoryWrite) << 4;
+
+ return res;
+}
+bool TrampolineCacheKey::operator==(const TrampolineCacheKey &other) const
+{
+ return pc == other.pc &&
+ registersInUse == other.registersInUse &&
+ info == other.info;
+}
diff --git a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h
index 516a071ac2..bf7109d6d9 100644
--- a/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h
+++ b/Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h
@@ -11,12 +11,33 @@
// We need at least this many bytes for backpatching.
const int BACKPATCH_SIZE = 5;
+struct TrampolineCacheKey
+{
+ u32 registersInUse;
+ u32 pc;
+ InstructionInfo info;
+
+ bool operator==(const TrampolineCacheKey &other) const;
+};
+
+struct TrampolineCacheKeyHasher
+{
+ size_t operator()(const TrampolineCacheKey& k) const;
+};
+
class TrampolineCache : public Gen::X64CodeBlock
{
public:
void Init();
void Shutdown();
- const u8 *GetReadTrampoline(const InstructionInfo &info, u32 registersInUse);
- const u8 *GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc);
+ const u8* GetReadTrampoline(const InstructionInfo &info, u32 registersInUse);
+ const u8* GetWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc);
+ void ClearCodeSpace();
+
+private:
+ const u8* GenerateReadTrampoline(const InstructionInfo &info, u32 registersInUse);
+ const u8* GenerateWriteTrampoline(const InstructionInfo &info, u32 registersInUse, u32 pc);
+
+ std::unordered_map<TrampolineCacheKey, const u8*, TrampolineCacheKeyHasher> cachedTrampolines;
};