diff options
| author | skidau <skidau@gmail.com> | 2014-10-07 13:26:23 +1100 |
|---|---|---|
| committer | skidau <skidau@gmail.com> | 2014-10-07 13:26:23 +1100 |
| commit | b3b34d16e6591cfe3aa879b2d4643c1415424a3b (patch) | |
| tree | 6db8662f202359d6061179976bf65a53dba46694 /Source | |
| parent | 8fdf43109f69cdf0a8219b1232ad3043987beb00 (diff) | |
| parent | c7208318fb9f9fd535f0f78c7c2956d874ef5b98 (diff) | |
Merge pull request #1218 from hthh/trampolinecaching
JIT: reuse trampolines when possible
Diffstat (limited to 'Source')
| -rw-r--r-- | Source/Core/Common/x64Analyzer.cpp | 16 | ||||
| -rw-r--r-- | Source/Core/Common/x64Analyzer.h | 2 | ||||
| -rw-r--r-- | Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp | 68 | ||||
| -rw-r--r-- | Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h | 25 |
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; }; |
