From 0ea0c21fedd5da7d6772aca16f2cf6382996c530 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 27 Jun 2016 19:34:08 +0300 Subject: [PATCH] LLVM: Indirect call map --- Utilities/VirtualMemory.cpp | 10 ++--- Utilities/VirtualMemory.h | 14 +++---- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 2 + rpcs3/Emu/Cell/PPUThread.cpp | 58 ++++++++------------------- rpcs3/Emu/Cell/PPUTranslator.cpp | 18 +++++++-- rpcs3/Emu/Cell/PPUTranslator.h | 3 ++ 6 files changed, 49 insertions(+), 56 deletions(-) diff --git a/Utilities/VirtualMemory.cpp b/Utilities/VirtualMemory.cpp index a7e85ff4ff..f3fb78af3f 100644 --- a/Utilities/VirtualMemory.cpp +++ b/Utilities/VirtualMemory.cpp @@ -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 } } diff --git a/Utilities/VirtualMemory.h b/Utilities/VirtualMemory.h index ecce48db2e..c63d75f659 100644 --- a/Utilities/VirtualMemory.h +++ b/Utilities/VirtualMemory.h @@ -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); -} \ No newline at end of file + void free_reserved_memory(void* pointer, std::size_t size); +} diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 962218925c..5331465f4b 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -13,6 +13,7 @@ logs::channel cellGcmSys("cellGcmSys", logs::level::notice); extern s32 cellGcmCallback(vm::ptr 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 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(gcm_info.context_addr) = current_context; context->set(gcm_info.context_addr); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index e72f2cbce5..38b437fb95 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -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 g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder" const ppu_decoder s_ppu_interpreter_precise; const ppu_decoder s_ppu_interpreter_fast; -struct ppu_addr_hash +const auto s_ppu_compiled = static_cast(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 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::vectorget(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); } } diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 054418cae4..7b25879f9e 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -82,6 +82,9 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64 thread_struct.insert(thread_struct.end(), 32, GetType()); // 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(), {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* } m_ir->SetInsertPoint(_default); - Call(GetType(), "__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(), "__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) { diff --git a/rpcs3/Emu/Cell/PPUTranslator.h b/rpcs3/Emu/Cell/PPUTranslator.h index e56ca7a31c..354c745b4f 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.h +++ b/rpcs3/Emu/Cell/PPUTranslator.h @@ -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;