mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-12-27 06:21:02 +00:00
LLVM: Indirect call map
This commit is contained in:
parent
7a921cbdf9
commit
0ea0c21fed
@ -25,21 +25,21 @@ namespace memory_helper
|
||||
return ret;
|
||||
}
|
||||
|
||||
void commit_page_memory(void* pointer, size_t page_size)
|
||||
void commit_page_memory(void* pointer, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VERIFY(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL);
|
||||
VERIFY(VirtualAlloc(pointer, size, MEM_COMMIT, PAGE_READWRITE) != NULL);
|
||||
#else
|
||||
VERIFY(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1);
|
||||
VERIFY(mprotect((void*)((u64)pointer & -4096), size, PROT_READ | PROT_WRITE) != -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void free_reserved_memory(void* pointer, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VERIFY(VirtualFree(pointer, 0, MEM_RELEASE) != 0);
|
||||
VERIFY(VirtualFree(pointer, 0, MEM_DECOMMIT) != 0);
|
||||
#else
|
||||
VERIFY(munmap(pointer, size) == 0);
|
||||
VERIFY(mprotect(pointer, size, PROT_NONE) != -1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,20 @@
|
||||
namespace memory_helper
|
||||
{
|
||||
/**
|
||||
* Reserve size bytes of virtual memory and returns it.
|
||||
* Reserve `size` bytes of virtual memory and returns it.
|
||||
* The memory should be commited before usage.
|
||||
*/
|
||||
void* reserve_memory(size_t size);
|
||||
void* reserve_memory(std::size_t size);
|
||||
|
||||
/**
|
||||
* Commit page_size bytes of virtual memory starting at pointer.
|
||||
* Commit `size` bytes of virtual memory starting at pointer.
|
||||
* That is, bake reserved memory with physical memory.
|
||||
* pointer should belong to a range of reserved memory.
|
||||
*/
|
||||
void commit_page_memory(void* pointer, size_t page_size);
|
||||
void commit_page_memory(void* pointer, std::size_t size);
|
||||
|
||||
/**
|
||||
* Free memory alloced via reserve_memory.
|
||||
* Decommit all memory committed via commit_page_memory.
|
||||
*/
|
||||
void free_reserved_memory(void* pointer, size_t size);
|
||||
}
|
||||
void free_reserved_memory(void* pointer, std::size_t size);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
logs::channel cellGcmSys("cellGcmSys", logs::level::notice);
|
||||
|
||||
extern s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count);
|
||||
extern void ppu_register_function_at(u32 addr, ppu_function_t ptr);
|
||||
|
||||
const u32 tiled_pitches[] = {
|
||||
0x00000000, 0x00000200, 0x00000300, 0x00000400,
|
||||
@ -384,6 +385,7 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
||||
vm::write32(gcm_info.context_addr + 0x44, 0xabadcafe);
|
||||
vm::write32(gcm_info.context_addr + 0x48, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback)));
|
||||
vm::write32(gcm_info.context_addr + 0x4c, ppu_instructions::BLR());
|
||||
ppu_register_function_at(gcm_info.context_addr + 0x48, BIND_FUNC(cellGcmCallback));
|
||||
|
||||
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
|
||||
context->set(gcm_info.context_addr);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Utilities/VirtualMemory.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
@ -56,17 +57,16 @@ cfg::map_entry<ppu_decoder_type> g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder"
|
||||
const ppu_decoder<ppu_interpreter_precise> s_ppu_interpreter_precise;
|
||||
const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
|
||||
|
||||
struct ppu_addr_hash
|
||||
const auto s_ppu_compiled = static_cast<ppu_function_t*>(memory_helper::reserve_memory(0x200000000));
|
||||
|
||||
extern void ppu_register_function_at(u32 addr, ppu_function_t ptr)
|
||||
{
|
||||
u32 operator()(u32 value) const
|
||||
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
|
||||
{
|
||||
return value / sizeof(32);
|
||||
memory_helper::commit_page_memory(s_ppu_compiled + addr / 4, sizeof(ppu_function_t));
|
||||
s_ppu_compiled[addr / 4] = ptr;
|
||||
}
|
||||
};
|
||||
|
||||
static std::unordered_map<u32, ppu_function_t, ppu_addr_hash> s_ppu_compiled; // TODO
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::string PPUThread::get_name() const
|
||||
{
|
||||
@ -134,12 +134,7 @@ void PPUThread::cpu_task_main()
|
||||
{
|
||||
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
|
||||
{
|
||||
const auto found = s_ppu_compiled.find(pc);
|
||||
|
||||
if (found != s_ppu_compiled.end())
|
||||
{
|
||||
return found->second(*this);
|
||||
}
|
||||
return s_ppu_compiled[pc / 4](*this);
|
||||
}
|
||||
|
||||
g_tls_log_prefix = []
|
||||
@ -397,27 +392,6 @@ static void ppu_trace(u64 addr)
|
||||
LOG_NOTICE(PPU, "Trace: 0x%llx", addr);
|
||||
}
|
||||
|
||||
static void ppu_call(PPUThread& ppu, u32 addr)
|
||||
{
|
||||
const auto found = s_ppu_compiled.find(addr);
|
||||
|
||||
if (found != s_ppu_compiled.end())
|
||||
{
|
||||
return found->second(ppu);
|
||||
}
|
||||
|
||||
const auto op = vm::read32(addr).value();
|
||||
const auto itype = s_ppu_itype.decode(op);
|
||||
|
||||
// Allow HLE callbacks without compiling them
|
||||
if (itype == ppu_itype::HACK && vm::read32(addr + 4) == ppu_instructions::BLR())
|
||||
{
|
||||
return ppu_execute_function(ppu, op & 0x3ffffff);
|
||||
}
|
||||
|
||||
ppu_trap(addr);
|
||||
}
|
||||
|
||||
static __m128 sse_rcp_ps(__m128 A)
|
||||
{
|
||||
return _mm_rcp_ps(A);
|
||||
@ -511,7 +485,7 @@ extern void ppu_initialize(const std::string& name, const std::vector<std::pair<
|
||||
{ "__hlecall", (u64)&ppu_execute_function },
|
||||
{ "__syscall", (u64)&ppu_execute_syscall },
|
||||
{ "__get_tbl", (u64)&get_timebased_time },
|
||||
{ "__call", (u64)&ppu_call },
|
||||
{ "__call", (u64)s_ppu_compiled },
|
||||
{ "__lwarx", (u64)&ppu_lwarx },
|
||||
{ "__ldarx", (u64)&ppu_ldarx },
|
||||
{ "__stwcx", (u64)&ppu_stwcx },
|
||||
@ -676,17 +650,19 @@ extern void ppu_initialize(const std::string& name, const std::vector<std::pair<
|
||||
return;
|
||||
}
|
||||
|
||||
s_ppu_compiled.clear();
|
||||
memory_helper::free_reserved_memory(s_ppu_compiled, 0x200000000); // TODO
|
||||
|
||||
// Get function addresses
|
||||
// Get and install function addresses
|
||||
for (const auto& info : funcs)
|
||||
{
|
||||
const u32 addr = info.first;
|
||||
if (info.second)
|
||||
{
|
||||
const std::uintptr_t link = jit->get(fmt::format("__sub_%x", info.first));
|
||||
s_ppu_compiled.emplace(info.first, (ppu_function_t)link);
|
||||
const std::uintptr_t link = jit->get(fmt::format("__sub_%x", addr));
|
||||
memory_helper::commit_page_memory(s_ppu_compiled + addr / 4, sizeof(ppu_function_t));
|
||||
s_ppu_compiled[addr / 4] = (ppu_function_t)link;
|
||||
|
||||
LOG_NOTICE(PPU, "** Function __sub_%x -> 0x%llx (addr=0x%x, size=0x%x)", info.first, link, info.first, info.second);
|
||||
LOG_NOTICE(PPU, "** Function __sub_%x -> 0x%llx (addr=0x%x, size=0x%x)", addr, link, addr, info.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,9 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<bool>()); // CR[0..31]
|
||||
|
||||
m_thread_type = StructType::create(m_context, thread_struct, "context_t");
|
||||
|
||||
// Callable
|
||||
m_call = new GlobalVariable(*module, ArrayType::get(FunctionType::get(GetType<void>(), {m_thread_type->getPointerTo()}, false)->getPointerTo(), 0x40000000), true, GlobalValue::ExternalLinkage, 0, "__call");
|
||||
}
|
||||
|
||||
PPUTranslator::~PPUTranslator()
|
||||
@ -265,8 +268,7 @@ Function* PPUTranslator::TranslateToIR(u64 start_addr, u64 end_addr, be_t<u32>*
|
||||
}
|
||||
|
||||
m_ir->SetInsertPoint(_default);
|
||||
Call(GetType<void>(), "__call", m_thread, _ctr);
|
||||
m_ir->CreateRetVoid();
|
||||
CallFunction(0, true, _ctr);
|
||||
}
|
||||
|
||||
//for (auto i = inst_begin(*m_function), end = inst_end(*m_function); i != end;)
|
||||
@ -321,7 +323,17 @@ void PPUTranslator::CallFunction(u64 target, bool tail, Value* indirect)
|
||||
|
||||
const auto callee_type = func ? m_func_types[target] : nullptr;
|
||||
|
||||
const auto result = func ? m_ir->CreateCall(func, {m_thread}) : Call(GetType<void>(), "__call", m_thread, indirect ? indirect : m_ir->getInt64(target));
|
||||
if (func)
|
||||
{
|
||||
m_ir->CreateCall(func, {m_thread});
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto addr = indirect ? indirect : (Value*)m_ir->getInt64(target);
|
||||
const auto pos = m_ir->CreateLShr(addr, 2, "", true);
|
||||
const auto ptr = m_ir->CreateGEP(m_call, {m_ir->getInt64(0), pos});
|
||||
m_ir->CreateCall(m_ir->CreateLoad(ptr), {m_thread});
|
||||
}
|
||||
|
||||
if (!tail)
|
||||
{
|
||||
|
@ -157,6 +157,9 @@ class PPUTranslator final //: public CPUTranslator
|
||||
// Thread context
|
||||
llvm::Value* m_thread;
|
||||
|
||||
// Callable functions
|
||||
llvm::Value* m_call;
|
||||
|
||||
// Thread context struct
|
||||
llvm::StructType* m_thread_type;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user