Skip to content

Commit

Permalink
Merge pull request #1218 from hthh/trampolinecaching
Browse files Browse the repository at this point in the history
JIT: reuse trampolines when possible
  • Loading branch information
skidau committed Oct 7, 2014
2 parents 8fdf431 + c720831 commit b3b34d1
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 11 deletions.
16 changes: 16 additions & 0 deletions Source/Core/Common/x64Analyzer.cpp
Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions Source/Core/Common/x64Analyzer.h
Expand Up @@ -20,6 +20,8 @@ struct InstructionInfo
bool byteSwap;
u64 immediate;
s32 displacement;

bool operator==(const InstructionInfo &other) const;
};

struct ModRM
Expand Down
68 changes: 59 additions & 9 deletions Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
25 changes: 23 additions & 2 deletions Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h
Expand Up @@ -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;
};

0 comments on commit b3b34d1

Please sign in to comment.