Implement SPU recompiler cache

Shared between ASMJIT/LLVM recompilers, compiled at startup
This commit is contained in:
Nekotekina 2018-05-05 00:01:27 +03:00
parent f5ee6fb113
commit fe4c3c4d84
7 changed files with 282 additions and 59 deletions

View file

@ -52,25 +52,27 @@ spu_recompiler::spu_recompiler()
}
}
spu_function_t spu_recompiler::get(u32 lsa)
void spu_recompiler::init()
{
// Initialize if necessary
if (!m_spurt)
{
m_cache = fxm::get<spu_cache>();
m_spurt = fxm::get_always<spu_runtime>();
}
}
spu_function_t spu_recompiler::get(u32 lsa)
{
init();
// Simple atomic read
return m_spurt->m_dispatcher[lsa / 4];
}
spu_function_t spu_recompiler::compile(const std::vector<u32>& func)
spu_function_t spu_recompiler::compile(std::vector<u32>&& func_rv)
{
// Initialize if necessary
if (!m_spurt)
{
m_spurt = fxm::get_always<spu_runtime>();
}
init();
// Don't lock without shared runtime
std::unique_lock<shared_mutex> lock(m_spurt->m_mutex, std::defer_lock);
@ -80,16 +82,18 @@ spu_function_t spu_recompiler::compile(const std::vector<u32>& func)
lock.lock();
}
// Try to find existing function
{
const auto found = m_spurt->m_map.find(func);
// Try to find existing function, register new one if necessary
const auto fn_info = m_spurt->m_map.emplace(std::move(func_rv), nullptr);
if (found != m_spurt->m_map.end() && found->second)
{
return found->second;
}
auto& fn_location = fn_info.first->second;
if (fn_location)
{
return fn_location;
}
auto& func = fn_info.first->first;
using namespace asmjit;
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
@ -811,7 +815,7 @@ spu_function_t spu_recompiler::compile(const std::vector<u32>& func)
}
// Register function
m_spurt->m_map[func] = fn;
fn_location = fn;
// Generate a dispatcher (übertrampoline)
std::vector<u32> addrv{func[0]};
@ -1043,6 +1047,11 @@ spu_function_t spu_recompiler::compile(const std::vector<u32>& func)
fs::file(Emu.GetCachePath() + "SPUJIT.log", fs::write + fs::append).write(log);
}
if (m_cache)
{
m_cache->add(func);
}
return fn;
}