Merge pull request #4637 from lioncash/jitcache
JitCache: Get rid of reliance on the JIT global variable
This commit is contained in:
commit
440a2f832c
|
@ -167,6 +167,8 @@ set(SRCS ActionReplay.cpp
|
||||||
PowerPC/SignatureDB/DSYSignatureDB.cpp
|
PowerPC/SignatureDB/DSYSignatureDB.cpp
|
||||||
PowerPC/SignatureDB/SignatureDB.cpp
|
PowerPC/SignatureDB/SignatureDB.cpp
|
||||||
PowerPC/JitInterface.cpp
|
PowerPC/JitInterface.cpp
|
||||||
|
PowerPC/CachedInterpreter/CachedInterpreter.cpp
|
||||||
|
PowerPC/CachedInterpreter/InterpreterBlockCache.cpp
|
||||||
PowerPC/Interpreter/Interpreter_Branch.cpp
|
PowerPC/Interpreter/Interpreter_Branch.cpp
|
||||||
PowerPC/Interpreter/Interpreter.cpp
|
PowerPC/Interpreter/Interpreter.cpp
|
||||||
PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
|
PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
|
||||||
|
@ -179,7 +181,6 @@ set(SRCS ActionReplay.cpp
|
||||||
PowerPC/JitCommon/JitAsmCommon.cpp
|
PowerPC/JitCommon/JitAsmCommon.cpp
|
||||||
PowerPC/JitCommon/JitBase.cpp
|
PowerPC/JitCommon/JitBase.cpp
|
||||||
PowerPC/JitCommon/JitCache.cpp
|
PowerPC/JitCommon/JitCache.cpp
|
||||||
PowerPC/CachedInterpreter.cpp
|
|
||||||
PowerPC/JitILCommon/IR.cpp
|
PowerPC/JitILCommon/IR.cpp
|
||||||
PowerPC/JitILCommon/JitILBase_Branch.cpp
|
PowerPC/JitILCommon/JitILBase_Branch.cpp
|
||||||
PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
PowerPC/JitILCommon/JitILBase_LoadStore.cpp
|
||||||
|
|
|
@ -204,6 +204,8 @@
|
||||||
<ClCompile Include="NetPlayClient.cpp" />
|
<ClCompile Include="NetPlayClient.cpp" />
|
||||||
<ClCompile Include="NetPlayServer.cpp" />
|
<ClCompile Include="NetPlayServer.cpp" />
|
||||||
<ClCompile Include="PatchEngine.cpp" />
|
<ClCompile Include="PatchEngine.cpp" />
|
||||||
|
<ClCompile Include="PowerPC\CachedInterpreter\CachedInterpreter.cpp" />
|
||||||
|
<ClCompile Include="PowerPC\CachedInterpreter\InterpreterBlockCache.cpp" />
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp" />
|
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp" />
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter_Branch.cpp" />
|
<ClCompile Include="PowerPC\Interpreter\Interpreter_Branch.cpp" />
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter_FloatingPoint.cpp" />
|
<ClCompile Include="PowerPC\Interpreter\Interpreter_FloatingPoint.cpp" />
|
||||||
|
@ -251,7 +253,6 @@
|
||||||
<ClCompile Include="PowerPC\SignatureDB\CSVSignatureDB.cpp" />
|
<ClCompile Include="PowerPC\SignatureDB\CSVSignatureDB.cpp" />
|
||||||
<ClCompile Include="PowerPC\SignatureDB\DSYSignatureDB.cpp" />
|
<ClCompile Include="PowerPC\SignatureDB\DSYSignatureDB.cpp" />
|
||||||
<ClCompile Include="PowerPC\SignatureDB\SignatureDB.cpp" />
|
<ClCompile Include="PowerPC\SignatureDB\SignatureDB.cpp" />
|
||||||
<ClCompile Include="PowerPC\CachedInterpreter.cpp" />
|
|
||||||
<ClCompile Include="PowerPC\JitInterface.cpp" />
|
<ClCompile Include="PowerPC\JitInterface.cpp" />
|
||||||
<ClCompile Include="PowerPC\MMU.cpp" />
|
<ClCompile Include="PowerPC\MMU.cpp" />
|
||||||
<ClCompile Include="PowerPC\PowerPC.cpp" />
|
<ClCompile Include="PowerPC\PowerPC.cpp" />
|
||||||
|
@ -424,6 +425,8 @@
|
||||||
<ClInclude Include="PatchEngine.h" />
|
<ClInclude Include="PatchEngine.h" />
|
||||||
<ClInclude Include="PowerPC\CPUCoreBase.h" />
|
<ClInclude Include="PowerPC\CPUCoreBase.h" />
|
||||||
<ClInclude Include="PowerPC\Gekko.h" />
|
<ClInclude Include="PowerPC\Gekko.h" />
|
||||||
|
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h" />
|
||||||
|
<ClInclude Include="PowerPC\CachedInterpreter\InterpreterBlockCache.h" />
|
||||||
<ClInclude Include="PowerPC\Interpreter\Interpreter.h" />
|
<ClInclude Include="PowerPC\Interpreter\Interpreter.h" />
|
||||||
<ClInclude Include="PowerPC\Interpreter\Interpreter_FPUtils.h" />
|
<ClInclude Include="PowerPC\Interpreter\Interpreter_FPUtils.h" />
|
||||||
<ClInclude Include="PowerPC\Interpreter\Interpreter_Tables.h" />
|
<ClInclude Include="PowerPC\Interpreter\Interpreter_Tables.h" />
|
||||||
|
@ -451,7 +454,6 @@
|
||||||
<ClInclude Include="PowerPC\SignatureDB\CSVSignatureDB.h" />
|
<ClInclude Include="PowerPC\SignatureDB\CSVSignatureDB.h" />
|
||||||
<ClInclude Include="PowerPC\SignatureDB\DSYSignatureDB.h" />
|
<ClInclude Include="PowerPC\SignatureDB\DSYSignatureDB.h" />
|
||||||
<ClInclude Include="PowerPC\SignatureDB\SignatureDB.h" />
|
<ClInclude Include="PowerPC\SignatureDB\SignatureDB.h" />
|
||||||
<ClInclude Include="PowerPC\CachedInterpreter.h" />
|
|
||||||
<ClInclude Include="PowerPC\JitInterface.h" />
|
<ClInclude Include="PowerPC\JitInterface.h" />
|
||||||
<ClInclude Include="PowerPC\PowerPC.h" />
|
<ClInclude Include="PowerPC\PowerPC.h" />
|
||||||
<ClInclude Include="PowerPC\PPCAnalyst.h" />
|
<ClInclude Include="PowerPC\PPCAnalyst.h" />
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
<Filter Include="PowerPC">
|
<Filter Include="PowerPC">
|
||||||
<UniqueIdentifier>{ebd24590-dfdc-433e-a411-21723e4b7cb5}</UniqueIdentifier>
|
<UniqueIdentifier>{ebd24590-dfdc-433e-a411-21723e4b7cb5}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="PowerPC\Cached Interpreter">
|
||||||
|
<UniqueIdentifier>{d6410c05-51f9-422a-83d5-f0723e34b607}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="PowerPC\Interpreter">
|
<Filter Include="PowerPC\Interpreter">
|
||||||
<UniqueIdentifier>{523f8d77-4aa6-4762-8f27-96f02b5070b4}</UniqueIdentifier>
|
<UniqueIdentifier>{523f8d77-4aa6-4762-8f27-96f02b5070b4}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -273,6 +276,12 @@
|
||||||
<ClCompile Include="HLE\HLE_OS.cpp">
|
<ClCompile Include="HLE\HLE_OS.cpp">
|
||||||
<Filter>HLE</Filter>
|
<Filter>HLE</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="PowerPC\CachedInterpreter\CachedInterpreter.cpp">
|
||||||
|
<Filter>PowerPC\Cached Interpreter</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="PowerPC\CachedInterpreter\InterpreterBlockCache.cpp">
|
||||||
|
<Filter>PowerPC\Cached Interpreter</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp">
|
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp">
|
||||||
<Filter>PowerPC\Interpreter</Filter>
|
<Filter>PowerPC\Interpreter</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -624,9 +633,6 @@
|
||||||
<ClCompile Include="HW\Wiimote.cpp">
|
<ClCompile Include="HW\Wiimote.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="PowerPC\CachedInterpreter.cpp">
|
|
||||||
<Filter>PowerPC</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="PowerPC\JitInterface.cpp">
|
<ClCompile Include="PowerPC\JitInterface.cpp">
|
||||||
<Filter>PowerPC</Filter>
|
<Filter>PowerPC</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -869,6 +875,12 @@
|
||||||
<ClInclude Include="HLE\HLE_OS.h">
|
<ClInclude Include="HLE\HLE_OS.h">
|
||||||
<Filter>HLE</Filter>
|
<Filter>HLE</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h">
|
||||||
|
<Filter>PowerPC\Cached Interpreter</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="PowerPC\CachedInterpreter\InterpreterBlockCache.h">
|
||||||
|
<Filter>PowerPC\Cached Interpreter</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="PowerPC\Interpreter\Interpreter.h">
|
<ClInclude Include="PowerPC\Interpreter\Interpreter.h">
|
||||||
<Filter>PowerPC\Interpreter</Filter>
|
<Filter>PowerPC\Interpreter</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1229,9 +1241,6 @@
|
||||||
<ClInclude Include="PowerPC\Gekko.h">
|
<ClInclude Include="PowerPC\Gekko.h">
|
||||||
<Filter>PowerPC</Filter>
|
<Filter>PowerPC</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="PowerPC\CachedInterpreter.h">
|
|
||||||
<Filter>PowerPC</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="PowerPC\JitInterface.h">
|
<ClInclude Include="PowerPC\JitInterface.h">
|
||||||
<Filter>PowerPC</Filter>
|
<Filter>PowerPC</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/PowerPC/CachedInterpreter.h"
|
#include "Core/PowerPC/CachedInterpreter/CachedInterpreter.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
@ -20,7 +20,7 @@ void CachedInterpreter::Init()
|
||||||
|
|
||||||
jo.enableBlocklink = false;
|
jo.enableBlocklink = false;
|
||||||
|
|
||||||
JitBaseBlockCache::Init();
|
m_block_cache.Init();
|
||||||
UpdateMemoryOptions();
|
UpdateMemoryOptions();
|
||||||
|
|
||||||
code_block.m_stats = &js.st;
|
code_block.m_stats = &js.st;
|
||||||
|
@ -30,12 +30,12 @@ void CachedInterpreter::Init()
|
||||||
|
|
||||||
void CachedInterpreter::Shutdown()
|
void CachedInterpreter::Shutdown()
|
||||||
{
|
{
|
||||||
JitBaseBlockCache::Shutdown();
|
m_block_cache.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachedInterpreter::ExecuteOneBlock()
|
void CachedInterpreter::ExecuteOneBlock()
|
||||||
{
|
{
|
||||||
const u8* normal_entry = JitBaseBlockCache::Dispatch();
|
const u8* normal_entry = m_block_cache.Dispatch();
|
||||||
const Instruction* code = reinterpret_cast<const Instruction*>(normal_entry);
|
const Instruction* code = reinterpret_cast<const Instruction*>(normal_entry);
|
||||||
|
|
||||||
for (; code->type != Instruction::INSTRUCTION_ABORT; ++code)
|
for (; code->type != Instruction::INSTRUCTION_ABORT; ++code)
|
||||||
|
@ -123,7 +123,7 @@ static bool CheckDSI(u32 data)
|
||||||
|
|
||||||
void CachedInterpreter::Jit(u32 address)
|
void CachedInterpreter::Jit(u32 address)
|
||||||
{
|
{
|
||||||
if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || IsFull() ||
|
if (m_code.size() >= CODE_SIZE / sizeof(Instruction) - 0x1000 || m_block_cache.IsFull() ||
|
||||||
SConfig::GetInstance().bJITNoBlockCache)
|
SConfig::GetInstance().bJITNoBlockCache)
|
||||||
{
|
{
|
||||||
ClearCache();
|
ClearCache();
|
||||||
|
@ -140,8 +140,8 @@ void CachedInterpreter::Jit(u32 address)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int block_num = AllocateBlock(PC);
|
int block_num = m_block_cache.AllocateBlock(PC);
|
||||||
JitBlock* b = GetBlock(block_num);
|
JitBlock* b = m_block_cache.GetBlock(block_num);
|
||||||
|
|
||||||
js.blockStart = PC;
|
js.blockStart = PC;
|
||||||
js.firstFPInstructionFound = false;
|
js.firstFPInstructionFound = false;
|
||||||
|
@ -212,12 +212,12 @@ void CachedInterpreter::Jit(u32 address)
|
||||||
b->codeSize = (u32)(GetCodePtr() - b->checkedEntry);
|
b->codeSize = (u32)(GetCodePtr() - b->checkedEntry);
|
||||||
b->originalSize = code_block.m_num_instructions;
|
b->originalSize = code_block.m_num_instructions;
|
||||||
|
|
||||||
FinalizeBlock(block_num, jo.enableBlocklink, b->checkedEntry);
|
m_block_cache.FinalizeBlock(block_num, jo.enableBlocklink, b->checkedEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachedInterpreter::ClearCache()
|
void CachedInterpreter::ClearCache()
|
||||||
{
|
{
|
||||||
m_code.clear();
|
m_code.clear();
|
||||||
JitBaseBlockCache::Clear();
|
m_block_cache.Clear();
|
||||||
UpdateMemoryOptions();
|
UpdateMemoryOptions();
|
||||||
}
|
}
|
|
@ -7,10 +7,11 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Core/PowerPC/CachedInterpreter/InterpreterBlockCache.h"
|
||||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
#include "Core/PowerPC/PPCAnalyst.h"
|
#include "Core/PowerPC/PPCAnalyst.h"
|
||||||
|
|
||||||
class CachedInterpreter : public JitBase, JitBaseBlockCache
|
class CachedInterpreter : public JitBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CachedInterpreter() : code_buffer(32000) {}
|
CachedInterpreter() : code_buffer(32000) {}
|
||||||
|
@ -26,9 +27,8 @@ public:
|
||||||
|
|
||||||
void Jit(u32 address) override;
|
void Jit(u32 address) override;
|
||||||
|
|
||||||
JitBaseBlockCache* GetBlockCache() override { return this; }
|
JitBaseBlockCache* GetBlockCache() override { return &m_block_cache; }
|
||||||
const char* GetName() override { return "Cached Interpreter"; }
|
const char* GetName() override { return "Cached Interpreter"; }
|
||||||
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override {}
|
|
||||||
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }
|
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }
|
||||||
private:
|
private:
|
||||||
struct Instruction
|
struct Instruction
|
||||||
|
@ -59,6 +59,7 @@ private:
|
||||||
const u8* GetCodePtr() { return (u8*)(m_code.data() + m_code.size()); }
|
const u8* GetCodePtr() { return (u8*)(m_code.data() + m_code.size()); }
|
||||||
void ExecuteOneBlock();
|
void ExecuteOneBlock();
|
||||||
|
|
||||||
|
BlockCache m_block_cache{*this};
|
||||||
std::vector<Instruction> m_code;
|
std::vector<Instruction> m_code;
|
||||||
PPCAnalyst::CodeBuffer code_buffer;
|
PPCAnalyst::CodeBuffer code_buffer;
|
||||||
};
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Core/PowerPC/CachedInterpreter/InterpreterBlockCache.h"
|
||||||
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
|
|
||||||
|
BlockCache::BlockCache(JitBase& jit) : JitBaseBlockCache{jit}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||||
|
|
||||||
|
class JitBase;
|
||||||
|
|
||||||
|
class BlockCache final : public JitBaseBlockCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit BlockCache(JitBase& jit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
||||||
|
};
|
|
@ -8,10 +8,14 @@
|
||||||
#include "Common/x64Emitter.h"
|
#include "Common/x64Emitter.h"
|
||||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
|
|
||||||
|
JitBlockCache::JitBlockCache(JitBase& jit) : JitBaseBlockCache{jit}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void JitBlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
void JitBlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
||||||
{
|
{
|
||||||
u8* location = source.exitPtrs;
|
u8* location = source.exitPtrs;
|
||||||
const u8* address = dest ? dest->checkedEntry : g_jit->GetAsmRoutines()->dispatcher;
|
const u8* address = dest ? dest->checkedEntry : m_jit.GetAsmRoutines()->dispatcher;
|
||||||
Gen::XEmitter emit(location);
|
Gen::XEmitter emit(location);
|
||||||
if (*location == 0xE8)
|
if (*location == 0xE8)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,8 +6,13 @@
|
||||||
|
|
||||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||||
|
|
||||||
|
class JitBase;
|
||||||
|
|
||||||
class JitBlockCache : public JitBaseBlockCache
|
class JitBlockCache : public JitBaseBlockCache
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
explicit JitBlockCache(JitBase& jit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
||||||
void WriteDestroyBlock(const JitBlock& block) override;
|
void WriteDestroyBlock(const JitBlock& block) override;
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Jitx86Base : public JitBase, public QuantizedMemoryRoutines
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
bool BackPatch(u32 emAddress, SContext* ctx);
|
bool BackPatch(u32 emAddress, SContext* ctx);
|
||||||
JitBlockCache blocks;
|
JitBlockCache blocks{*this};
|
||||||
TrampolineCache trampolines;
|
TrampolineCache trampolines;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -178,7 +178,7 @@ private:
|
||||||
Arm64GPRCache gpr;
|
Arm64GPRCache gpr;
|
||||||
Arm64FPRCache fpr;
|
Arm64FPRCache fpr;
|
||||||
|
|
||||||
JitArm64BlockCache blocks;
|
JitArm64BlockCache blocks{*this};
|
||||||
|
|
||||||
PPCAnalyst::CodeBuffer code_buffer;
|
PPCAnalyst::CodeBuffer code_buffer;
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,13 @@
|
||||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/PowerPC/JitArm64/JitArm64Cache.h"
|
#include "Core/PowerPC/JitArm64/JitArm64Cache.h"
|
||||||
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
|
|
||||||
|
JitArm64BlockCache::JitArm64BlockCache(JitBase& jit) : JitBaseBlockCache{jit}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest)
|
||||||
{
|
{
|
||||||
u8* location = source.exitPtrs;
|
u8* location = source.exitPtrs;
|
||||||
|
@ -28,7 +33,7 @@ void JitArm64BlockCache::WriteLinkBlock(const JitBlock::LinkData& source, const
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
emit.MOVI2R(DISPATCHER_PC, source.exitAddress);
|
||||||
emit.B(g_jit->GetAsmRoutines()->dispatcher);
|
emit.B(m_jit.GetAsmRoutines()->dispatcher);
|
||||||
}
|
}
|
||||||
emit.FlushIcache();
|
emit.FlushIcache();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,15 @@
|
||||||
|
|
||||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||||
|
|
||||||
|
class JitBase;
|
||||||
|
|
||||||
typedef void (*CompiledCode)();
|
typedef void (*CompiledCode)();
|
||||||
|
|
||||||
class JitArm64BlockCache : public JitBaseBlockCache
|
class JitArm64BlockCache : public JitBaseBlockCache
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
explicit JitArm64BlockCache(JitBase& jit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) override;
|
||||||
void WriteDestroyBlock(const JitBlock& block) override;
|
void WriteDestroyBlock(const JitBlock& block) override;
|
||||||
|
|
|
@ -35,11 +35,12 @@ static void ClearCacheThreadSafe(u64 userdata, s64 cyclesdata)
|
||||||
JitInterface::ClearCache();
|
JitInterface::ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JitBaseBlockCache::IsFull() const
|
JitBaseBlockCache::JitBaseBlockCache(JitBase& jit) : m_jit{jit}
|
||||||
{
|
{
|
||||||
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitBaseBlockCache::~JitBaseBlockCache() = default;
|
||||||
|
|
||||||
void JitBaseBlockCache::Init()
|
void JitBaseBlockCache::Init()
|
||||||
{
|
{
|
||||||
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
|
s_clear_jit_cache_thread_safe = CoreTiming::RegisterEvent("clearJitCache", ClearCacheThreadSafe);
|
||||||
|
@ -66,8 +67,8 @@ void JitBaseBlockCache::Clear()
|
||||||
else
|
else
|
||||||
Core::DisplayMessage("Clearing code cache.", 3000);
|
Core::DisplayMessage("Clearing code cache.", 3000);
|
||||||
#endif
|
#endif
|
||||||
g_jit->js.fifoWriteAddresses.clear();
|
m_jit.js.fifoWriteAddresses.clear();
|
||||||
g_jit->js.pairedQuantizeAddresses.clear();
|
m_jit.js.pairedQuantizeAddresses.clear();
|
||||||
for (int i = 1; i < num_blocks; i++)
|
for (int i = 1; i < num_blocks; i++)
|
||||||
{
|
{
|
||||||
DestroyBlock(i, false);
|
DestroyBlock(i, false);
|
||||||
|
@ -82,15 +83,20 @@ void JitBaseBlockCache::Clear()
|
||||||
blocks[0].invalid = true;
|
blocks[0].invalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitBaseBlockCache::Reset()
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
|
void JitBaseBlockCache::SchedulateClearCacheThreadSafe()
|
||||||
{
|
{
|
||||||
CoreTiming::ScheduleEvent(0, s_clear_jit_cache_thread_safe, 0, CoreTiming::FromThread::NON_CPU);
|
CoreTiming::ScheduleEvent(0, s_clear_jit_cache_thread_safe, 0, CoreTiming::FromThread::NON_CPU);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitBaseBlockCache::Reset()
|
bool JitBaseBlockCache::IsFull() const
|
||||||
{
|
{
|
||||||
Shutdown();
|
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
|
||||||
Init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JitBlock* JitBaseBlockCache::GetBlock(int no)
|
JitBlock* JitBaseBlockCache::GetBlock(int no)
|
||||||
|
@ -98,11 +104,21 @@ JitBlock* JitBaseBlockCache::GetBlock(int no)
|
||||||
return &blocks[no];
|
return &blocks[no];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitBlock* JitBaseBlockCache::GetBlocks()
|
||||||
|
{
|
||||||
|
return blocks.data();
|
||||||
|
}
|
||||||
|
|
||||||
int JitBaseBlockCache::GetNumBlocks() const
|
int JitBaseBlockCache::GetNumBlocks() const
|
||||||
{
|
{
|
||||||
return num_blocks;
|
return num_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int* JitBaseBlockCache::GetICache()
|
||||||
|
{
|
||||||
|
return iCache.data();
|
||||||
|
}
|
||||||
|
|
||||||
int JitBaseBlockCache::AllocateBlock(u32 em_address)
|
int JitBaseBlockCache::AllocateBlock(u32 em_address)
|
||||||
{
|
{
|
||||||
JitBlock& b = blocks[num_blocks];
|
JitBlock& b = blocks[num_blocks];
|
||||||
|
@ -180,20 +196,6 @@ int JitBaseBlockCache::GetBlockNumberFromStartAddress(u32 addr, u32 msr)
|
||||||
return block_num;
|
return block_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr)
|
|
||||||
{
|
|
||||||
int block_num = GetBlockNumberFromStartAddress(addr, msr);
|
|
||||||
if (block_num < 0)
|
|
||||||
{
|
|
||||||
Jit(addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FastLookupEntryForAddress(addr) = block_num;
|
|
||||||
LinkBlock(block_num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const u8* JitBaseBlockCache::Dispatch()
|
const u8* JitBaseBlockCache::Dispatch()
|
||||||
{
|
{
|
||||||
int block_num = FastLookupEntryForAddress(PC);
|
int block_num = FastLookupEntryForAddress(PC);
|
||||||
|
@ -208,6 +210,59 @@ const u8* JitBaseBlockCache::Dispatch()
|
||||||
return blocks[block_num].normalEntry;
|
return blocks[block_num].normalEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced)
|
||||||
|
{
|
||||||
|
auto translated = PowerPC::JitCache_TranslateAddress(address);
|
||||||
|
if (!translated.valid)
|
||||||
|
return;
|
||||||
|
u32 pAddr = translated.address;
|
||||||
|
|
||||||
|
// Optimize the common case of length == 32 which is used by Interpreter::dcb*
|
||||||
|
bool destroy_block = true;
|
||||||
|
if (length == 32)
|
||||||
|
{
|
||||||
|
if (!valid_block.Test(pAddr / 32))
|
||||||
|
destroy_block = false;
|
||||||
|
else
|
||||||
|
valid_block.Clear(pAddr / 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy JIT blocks
|
||||||
|
// !! this works correctly under assumption that any two overlapping blocks end at the same
|
||||||
|
// address
|
||||||
|
if (destroy_block)
|
||||||
|
{
|
||||||
|
auto it = block_map.lower_bound(std::make_pair(pAddr, 0));
|
||||||
|
while (it != block_map.end() && it->first.second < pAddr + length)
|
||||||
|
{
|
||||||
|
DestroyBlock(it->second, true);
|
||||||
|
it = block_map.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the code was actually modified, we need to clear the relevant entries from the
|
||||||
|
// FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't
|
||||||
|
// be (this can clobber flags, and thus break any optimization that relies on flags
|
||||||
|
// being in the right place between instructions).
|
||||||
|
if (!forced)
|
||||||
|
{
|
||||||
|
for (u32 i = address; i < address + length; i += 4)
|
||||||
|
{
|
||||||
|
m_jit.js.fifoWriteAddresses.erase(i);
|
||||||
|
m_jit.js.pairedQuantizeAddresses.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32* JitBaseBlockCache::GetBlockBitSet() const
|
||||||
|
{
|
||||||
|
return valid_block.m_valid_block.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JitBaseBlockCache::WriteDestroyBlock(const JitBlock& block)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Block linker
|
// Block linker
|
||||||
// Make sure to have as many blocks as possible compiled before calling this
|
// Make sure to have as many blocks as possible compiled before calling this
|
||||||
// It's O(N), so it's fast :)
|
// It's O(N), so it's fast :)
|
||||||
|
@ -309,46 +364,21 @@ void JitBaseBlockCache::DestroyBlock(int block_num, bool invalidate)
|
||||||
WriteDestroyBlock(b);
|
WriteDestroyBlock(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitBaseBlockCache::InvalidateICache(u32 address, const u32 length, bool forced)
|
void JitBaseBlockCache::MoveBlockIntoFastCache(u32 addr, u32 msr)
|
||||||
{
|
{
|
||||||
auto translated = PowerPC::JitCache_TranslateAddress(address);
|
int block_num = GetBlockNumberFromStartAddress(addr, msr);
|
||||||
if (!translated.valid)
|
if (block_num < 0)
|
||||||
return;
|
|
||||||
u32 pAddr = translated.address;
|
|
||||||
|
|
||||||
// Optimize the common case of length == 32 which is used by Interpreter::dcb*
|
|
||||||
bool destroy_block = true;
|
|
||||||
if (length == 32)
|
|
||||||
{
|
{
|
||||||
if (!valid_block.Test(pAddr / 32))
|
Jit(addr);
|
||||||
destroy_block = false;
|
}
|
||||||
else
|
else
|
||||||
valid_block.Clear(pAddr / 32);
|
{
|
||||||
|
FastLookupEntryForAddress(addr) = block_num;
|
||||||
|
LinkBlock(block_num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroy JIT blocks
|
int& JitBaseBlockCache::FastLookupEntryForAddress(u32 address)
|
||||||
// !! this works correctly under assumption that any two overlapping blocks end at the same
|
|
||||||
// address
|
|
||||||
if (destroy_block)
|
|
||||||
{
|
{
|
||||||
auto it = block_map.lower_bound(std::make_pair(pAddr, 0));
|
return iCache[(address >> 2) & iCache_Mask];
|
||||||
while (it != block_map.end() && it->first.second < pAddr + length)
|
|
||||||
{
|
|
||||||
DestroyBlock(it->second, true);
|
|
||||||
it = block_map.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the code was actually modified, we need to clear the relevant entries from the
|
|
||||||
// FIFO write address cache, so we don't end up with FIFO checks in places they shouldn't
|
|
||||||
// be (this can clobber flags, and thus break any optimization that relies on flags
|
|
||||||
// being in the right place between instructions).
|
|
||||||
if (!forced)
|
|
||||||
{
|
|
||||||
for (u32 i = address; i < address + length; i += 4)
|
|
||||||
{
|
|
||||||
g_jit->js.fifoWriteAddresses.erase(i);
|
|
||||||
g_jit->js.pairedQuantizeAddresses.erase(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
class JitBase;
|
||||||
|
|
||||||
// A JitBlock is block of compiled code which corresponds to the PowerPC
|
// A JitBlock is block of compiled code which corresponds to the PowerPC
|
||||||
// code at a given address.
|
// code at a given address.
|
||||||
//
|
//
|
||||||
|
@ -112,11 +114,61 @@ public:
|
||||||
static constexpr u32 iCache_Num_Elements = 0x10000;
|
static constexpr u32 iCache_Num_Elements = 0x10000;
|
||||||
static constexpr u32 iCache_Mask = iCache_Num_Elements - 1;
|
static constexpr u32 iCache_Mask = iCache_Num_Elements - 1;
|
||||||
|
|
||||||
|
explicit JitBaseBlockCache(JitBase& jit);
|
||||||
|
virtual ~JitBaseBlockCache();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
void Clear();
|
||||||
|
void Reset();
|
||||||
|
void SchedulateClearCacheThreadSafe();
|
||||||
|
|
||||||
|
bool IsFull() const;
|
||||||
|
|
||||||
|
// Code Cache
|
||||||
|
JitBlock* GetBlock(int block_num);
|
||||||
|
JitBlock* GetBlocks();
|
||||||
|
int GetNumBlocks() const;
|
||||||
|
int* GetICache();
|
||||||
|
|
||||||
|
int AllocateBlock(u32 em_address);
|
||||||
|
void FinalizeBlock(int block_num, bool block_link, const u8* code_ptr);
|
||||||
|
|
||||||
|
// Look for the block in the slow but accurate way.
|
||||||
|
// This function shall be used if FastLookupEntryForAddress() failed.
|
||||||
|
int GetBlockNumberFromStartAddress(u32 em_address, u32 msr);
|
||||||
|
|
||||||
|
// Get the normal entry for the block associated with the current program
|
||||||
|
// counter. This will JIT code if necessary. (This is the reference
|
||||||
|
// implementation; high-performance JITs will want to use a custom
|
||||||
|
// assembly version.)
|
||||||
|
const u8* Dispatch();
|
||||||
|
|
||||||
|
void InvalidateICache(u32 address, const u32 length, bool forced);
|
||||||
|
|
||||||
|
u32* GetBlockBitSet() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
JitBase& m_jit;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0;
|
||||||
|
virtual void WriteDestroyBlock(const JitBlock& block);
|
||||||
|
|
||||||
|
void LinkBlockExits(int i);
|
||||||
|
void LinkBlock(int i);
|
||||||
|
void UnlinkBlock(int i);
|
||||||
|
void DestroyBlock(int block_num, bool invalidate);
|
||||||
|
|
||||||
|
void MoveBlockIntoFastCache(u32 em_address, u32 msr);
|
||||||
|
|
||||||
|
// Fast but risky block lookup based on iCache.
|
||||||
|
int& FastLookupEntryForAddress(u32 address);
|
||||||
|
|
||||||
// We store the metadata of all blocks in a linear way within this array.
|
// We store the metadata of all blocks in a linear way within this array.
|
||||||
// Note: blocks[0] must not be used as it is referenced as invalid block in iCache.
|
// Note: blocks[0] must not be used as it is referenced as invalid block in iCache.
|
||||||
std::array<JitBlock, MAX_NUM_BLOCKS> blocks; // number -> JitBlock
|
std::array<JitBlock, MAX_NUM_BLOCKS> blocks; // number -> JitBlock
|
||||||
int num_blocks;
|
int num_blocks = 1;
|
||||||
|
|
||||||
// links_to hold all exit points of all valid blocks in a reverse way.
|
// links_to hold all exit points of all valid blocks in a reverse way.
|
||||||
// It is used to query all blocks which links to an address.
|
// It is used to query all blocks which links to an address.
|
||||||
|
@ -138,51 +190,4 @@ private:
|
||||||
// This array is indexed with the masked PC and likely holds the correct block id.
|
// This array is indexed with the masked PC and likely holds the correct block id.
|
||||||
// This is used as a fast cache of start_block_map used in the assembly dispatcher.
|
// This is used as a fast cache of start_block_map used in the assembly dispatcher.
|
||||||
std::array<int, iCache_Num_Elements> iCache; // start_addr & mask -> number
|
std::array<int, iCache_Num_Elements> iCache; // start_addr & mask -> number
|
||||||
|
|
||||||
void LinkBlockExits(int i);
|
|
||||||
void LinkBlock(int i);
|
|
||||||
void UnlinkBlock(int i);
|
|
||||||
|
|
||||||
void DestroyBlock(int block_num, bool invalidate);
|
|
||||||
|
|
||||||
void MoveBlockIntoFastCache(u32 em_address, u32 msr);
|
|
||||||
|
|
||||||
// Fast but risky block lookup based on iCache.
|
|
||||||
int& FastLookupEntryForAddress(u32 address) { return iCache[(address >> 2) & iCache_Mask]; }
|
|
||||||
// Virtual for overloaded
|
|
||||||
virtual void WriteLinkBlock(const JitBlock::LinkData& source, const JitBlock* dest) = 0;
|
|
||||||
virtual void WriteDestroyBlock(const JitBlock& block) {}
|
|
||||||
public:
|
|
||||||
JitBaseBlockCache() : num_blocks(1) {}
|
|
||||||
virtual ~JitBaseBlockCache() {}
|
|
||||||
int AllocateBlock(u32 em_address);
|
|
||||||
void FinalizeBlock(int block_num, bool block_link, const u8* code_ptr);
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
void SchedulateClearCacheThreadSafe();
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
bool IsFull() const;
|
|
||||||
|
|
||||||
// Code Cache
|
|
||||||
JitBlock* GetBlock(int block_num);
|
|
||||||
JitBlock* GetBlocks() { return blocks.data(); }
|
|
||||||
int* GetICache() { return iCache.data(); }
|
|
||||||
int GetNumBlocks() const;
|
|
||||||
|
|
||||||
// Look for the block in the slow but accurate way.
|
|
||||||
// This function shall be used if FastLookupEntryForAddress() failed.
|
|
||||||
int GetBlockNumberFromStartAddress(u32 em_address, u32 msr);
|
|
||||||
|
|
||||||
// Get the normal entry for the block associated with the current program
|
|
||||||
// counter. This will JIT code if necessary. (This is the reference
|
|
||||||
// implementation; high-performance JITs will want to use a custom
|
|
||||||
// assembly version.)
|
|
||||||
const u8* Dispatch();
|
|
||||||
|
|
||||||
void InvalidateICache(u32 address, const u32 length, bool forced);
|
|
||||||
|
|
||||||
u32* GetBlockBitSet() const { return valid_block.m_valid_block.get(); }
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/PowerPC/CachedInterpreter.h"
|
#include "Core/PowerPC/CachedInterpreter/CachedInterpreter.h"
|
||||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||||
|
|
Loading…
Reference in New Issue