diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 148b483ef9..64ca42ea50 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -101,10 +101,13 @@ namespace ppu_recompiler_llvm { class Compiler; } +class ppu_llvm_test_class; + class PPUInterpreter : public PPUOpcodes { #ifdef PPU_LLVM_RECOMPILER friend class ppu_recompiler_llvm::Compiler; + friend class ppu_llvm_test_class; #endif private: PPUThread& CPU; diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 10bfd2570b..de12adc8f2 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -45,25 +45,62 @@ using namespace ppu_recompiler_llvm; u64 Compiler::s_rotate_mask[64][64]; bool Compiler::s_rotate_mask_inited = false; -Compiler::Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function, - const Executable execute_unknown_block, bool(*poll_status_function)(PPUThread * ppu_state)) - : m_recompilation_engine(recompilation_engine) - , m_poll_status_function(poll_status_function) { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetDisassembler(); +std::unique_ptr Compiler::create_module(LLVMContext &llvm_context) +{ + const std::vector arg_types = { Type::getInt8PtrTy(llvm_context), Type::getInt64Ty(llvm_context) }; + FunctionType *compiled_function_type = FunctionType::get(Type::getInt32Ty(llvm_context), arg_types, false); - m_llvm_context = new LLVMContext(); - m_ir_builder = new IRBuilder<>(*m_llvm_context); + std::unique_ptr result(new llvm::Module("Module", llvm_context)); + Function *execute_unknown_function = (Function *)result->getOrInsertFunction("execute_unknown_function", compiled_function_type); + execute_unknown_function->setCallingConv(CallingConv::X86_64_Win64); + + Function *execute_unknown_block = (Function *)result->getOrInsertFunction("execute_unknown_block", compiled_function_type); + execute_unknown_block->setCallingConv(CallingConv::X86_64_Win64); + + std::string targetTriple = "x86_64-pc-windows-elf"; + result->setTargetTriple(targetTriple); + + return result; +} + +void Compiler::optimise_module(llvm::Module *module) +{ + llvm::FunctionPassManager fpm(module); + fpm.add(createNoAAPass()); + fpm.add(createBasicAliasAnalysisPass()); + fpm.add(createNoTargetTransformInfoPass()); + fpm.add(createEarlyCSEPass()); + fpm.add(createTailCallEliminationPass()); + fpm.add(createReassociatePass()); + fpm.add(createInstructionCombiningPass()); + fpm.add(new DominatorTreeWrapperPass()); + fpm.add(new MemoryDependenceAnalysis()); + fpm.add(createGVNPass()); + fpm.add(createInstructionCombiningPass()); + fpm.add(new MemoryDependenceAnalysis()); + fpm.add(createDeadStoreEliminationPass()); + fpm.add(new LoopInfo()); + fpm.add(new ScalarEvolution()); + fpm.add(createSLPVectorizerPass()); + fpm.add(createInstructionCombiningPass()); + fpm.add(createCFGSimplificationPass()); + fpm.doInitialization(); + + for (auto I = module->begin(), E = module->end(); I != E; ++I) + fpm.run(*I); +} + + +Compiler::Compiler(LLVMContext *context, llvm::IRBuilder<> *builder, std::unordered_map &function_ptrs) + : m_llvm_context(context), + m_ir_builder(builder), + m_executable_map(function_ptrs) { std::vector arg_types; arg_types.push_back(m_ir_builder->getInt8PtrTy()); arg_types.push_back(m_ir_builder->getInt64Ty()); m_compiled_function_type = FunctionType::get(m_ir_builder->getInt32Ty(), arg_types, false); - m_executableMap["execute_unknown_function"] = execute_unknown_function; - m_executableMap["execute_unknown_block"] = execute_unknown_block; - if (!s_rotate_mask_inited) { InitRotateMask(); s_rotate_mask_inited = true; @@ -71,54 +108,10 @@ Compiler::Compiler(RecompilationEngine & recompilation_engine, const Executable } Compiler::~Compiler() { - delete m_ir_builder; - delete m_llvm_context; } -std::pair Compiler::Compile(const std::string & name, u32 start_address, u32 instruction_count) { - auto compilation_start = std::chrono::high_resolution_clock::now(); - - m_module = new llvm::Module("Module", *m_llvm_context); - m_execute_unknown_function = (Function *)m_module->getOrInsertFunction("execute_unknown_function", m_compiled_function_type); - m_execute_unknown_function->setCallingConv(CallingConv::X86_64_Win64); - - m_execute_unknown_block = (Function *)m_module->getOrInsertFunction("execute_unknown_block", m_compiled_function_type); - m_execute_unknown_block->setCallingConv(CallingConv::X86_64_Win64); - - std::string targetTriple = "x86_64-pc-windows-elf"; - m_module->setTargetTriple(targetTriple); - - llvm::ExecutionEngine *execution_engine = - EngineBuilder(std::unique_ptr(m_module)) - .setEngineKind(EngineKind::JIT) - .setMCJITMemoryManager(std::unique_ptr(new CustomSectionMemoryManager(m_executableMap))) - .setOptLevel(llvm::CodeGenOpt::Aggressive) - .setMCPU("nehalem") - .create(); - m_module->setDataLayout(execution_engine->getDataLayout()); - - llvm::FunctionPassManager *fpm = new llvm::FunctionPassManager(m_module); - fpm->add(createNoAAPass()); - fpm->add(createBasicAliasAnalysisPass()); - fpm->add(createNoTargetTransformInfoPass()); - fpm->add(createEarlyCSEPass()); - fpm->add(createTailCallEliminationPass()); - fpm->add(createReassociatePass()); - fpm->add(createInstructionCombiningPass()); - fpm->add(new DominatorTreeWrapperPass()); - fpm->add(new MemoryDependenceAnalysis()); - fpm->add(createGVNPass()); - fpm->add(createInstructionCombiningPass()); - fpm->add(new MemoryDependenceAnalysis()); - fpm->add(createDeadStoreEliminationPass()); - fpm->add(new LoopInfo()); - fpm->add(new ScalarEvolution()); - fpm->add(createSLPVectorizerPass()); - fpm->add(createInstructionCombiningPass()); - fpm->add(createCFGSimplificationPass()); - fpm->doInitialization(); - - // Create the function +void Compiler::initiate_function(const std::string &name) +{ m_state.function = (Function *)m_module->getOrInsertFunction(name, m_compiled_function_type); m_state.function->setCallingConv(CallingConv::X86_64_Win64); auto arg_i = m_state.function->arg_begin(); @@ -126,6 +119,16 @@ std::pair Compiler::Compile(const std::stri m_state.args[CompileTaskState::Args::State] = arg_i; (++arg_i)->setName("context"); m_state.args[CompileTaskState::Args::Context] = arg_i; +} + +void ppu_recompiler_llvm::Compiler::translate_to_llvm_ir(llvm::Module *module, const std::string & name, u32 start_address, u32 instruction_count) +{ + m_module = module; + + m_execute_unknown_function = module->getFunction("execute_unknown_function"); + m_execute_unknown_block = module->getFunction("execute_unknown_block"); + + initiate_function(name); // Create the entry block and add code to branch to the first instruction m_ir_builder->SetInsertPoint(GetBasicBlockFromAddress(0)); @@ -135,7 +138,7 @@ std::pair Compiler::Compile(const std::stri PPUDisAsm dis_asm(CPUDisAsm_DumpMode); dis_asm.offset = vm::ps3::_ptr(start_address); - m_recompilation_engine.Log() << "Recompiling block :\n\n"; +// m_recompilation_engine.Log() << "Recompiling block :\n\n"; // Convert each instruction in the CFG to LLVM IR std::vector exit_instr_list; @@ -150,7 +153,7 @@ std::pair Compiler::Compile(const std::stri // Dump PPU opcode dis_asm.dump_pc = instructionAddress; (*PPU_instr::main_list)(&dis_asm, instr); - m_recompilation_engine.Log() << dis_asm.last_opcode; +// m_recompilation_engine.Log() << dis_asm.last_opcode; Decode(instr); if (!m_state.hit_branch_instruction) @@ -194,51 +197,17 @@ std::pair Compiler::Compile(const std::stri } } - m_recompilation_engine.Log() << "LLVM bytecode:\n"; - m_recompilation_engine.Log() << *m_module; +// m_recompilation_engine.Log() << "LLVM bytecode:\n"; +// m_recompilation_engine.Log() << *m_module; std::string verify; raw_string_ostream verify_ostream(verify); if (verifyFunction(*m_state.function, &verify_ostream)) { - m_recompilation_engine.Log() << "Verification failed: " << verify_ostream.str() << "\n"; +// m_recompilation_engine.Log() << "Verification failed: " << verify_ostream.str() << "\n"; } - auto ir_build_end = std::chrono::high_resolution_clock::now(); - m_stats.ir_build_time += std::chrono::duration_cast(ir_build_end - compilation_start); - - // Optimize this function - fpm->run(*m_state.function); - auto optimize_end = std::chrono::high_resolution_clock::now(); - m_stats.optimization_time += std::chrono::duration_cast(optimize_end - ir_build_end); - - // Translate to machine code - execution_engine->finalizeObject(); - void *function = execution_engine->getPointerToFunction(m_state.function); - auto translate_end = std::chrono::high_resolution_clock::now(); - m_stats.translation_time += std::chrono::duration_cast(translate_end - optimize_end); - - /* m_recompilation_engine.Log() << "\nDisassembly:\n"; - auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr); - for (size_t pc = 0; pc < mci.size();) { - char str[1024]; - - auto size = LLVMDisasmInstruction(disassembler, ((u8 *)mci.address()) + pc, mci.size() - pc, (uint64_t)(((u8 *)mci.address()) + pc), str, sizeof(str)); - m_recompilation_engine.Log() << fmt::format("0x%08X: ", (u64)(((u8 *)mci.address()) + pc)) << str << '\n'; - pc += size; - } - - LLVMDisasmDispose(disassembler);*/ - - auto compilation_end = std::chrono::high_resolution_clock::now(); - m_stats.total_time += std::chrono::duration_cast(compilation_end - compilation_start); - delete fpm; - - assert(function != nullptr); - return std::make_pair((Executable)function, execution_engine); -} - -Compiler::Stats Compiler::GetStats() { - return m_stats; + m_module = nullptr; + m_state.function = nullptr; } void Compiler::Decode(const u32 code) { @@ -252,7 +221,12 @@ RecompilationEngine::RecompilationEngine() : m_log(nullptr) , m_currentId(0) , m_last_cache_clear_time(std::chrono::high_resolution_clock::now()) - , m_compiler(*this, CPUHybridDecoderRecompiler::ExecuteFunction, CPUHybridDecoderRecompiler::ExecuteTillReturn, CPUHybridDecoderRecompiler::PollStatus) { + , m_llvm_context(getGlobalContext()) + , m_ir_builder(getGlobalContext()) { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetDisassembler(); + FunctionCache = (ExecutableStorageType *)memory_helper::reserve_memory(VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType)); // Each char can store 8 page status FunctionCachePagesCommited = (char *)malloc(VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE)); @@ -350,20 +324,6 @@ void RecompilationEngine::on_task() { } } - std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); - auto total_time = std::chrono::duration_cast(end - start); - auto compiler_stats = m_compiler.GetStats(); - - Log() << "Total time = " << total_time.count() / 1000000 << "ms\n"; - Log() << " Time spent compiling = " << compiler_stats.total_time.count() / 1000000 << "ms\n"; - Log() << " Time spent building IR = " << compiler_stats.ir_build_time.count() / 1000000 << "ms\n"; - Log() << " Time spent optimizing = " << compiler_stats.optimization_time.count() / 1000000 << "ms\n"; - Log() << " Time spent translating = " << compiler_stats.translation_time.count() / 1000000 << "ms\n"; - Log() << " Time spent recompiling = " << recompiling_time.count() / 1000000 << "ms\n"; - Log() << " Time spent idling = " << idling_time.count() / 1000000 << "ms\n"; - Log() << " Time spent doing misc tasks = " << (total_time.count() - idling_time.count() - compiler_stats.total_time.count()) / 1000000 << "ms\n"; - - LOG_NOTICE(PPU, "PPU LLVM Recompilation thread exiting."); s_the_instance = nullptr; // Can cause deadlock if this is the last instance. Need to fix this. } @@ -382,6 +342,92 @@ bool RecompilationEngine::IncreaseHitCounterAndBuild(u32 address) { return false; } +extern void execute_ppu_func_by_index(PPUThread& ppu, u32 id); +extern void execute_syscall_by_index(PPUThread& ppu, u64 code); + +static u32 +wrappedExecutePPUFuncByIndex(PPUThread &CPU, u32 index) noexcept { + try + { + execute_ppu_func_by_index(CPU, index); + return ExecutionStatus::ExecutionStatusBlockEnded; + } + catch (...) + { + CPU.pending_exception = std::current_exception(); + return ExecutionStatus::ExecutionStatusPropagateException; + } +} + +static u32 wrappedDoSyscall(PPUThread &CPU, u64 code) noexcept { + try + { + execute_syscall_by_index(CPU, code); + return ExecutionStatus::ExecutionStatusBlockEnded; + } + catch (...) + { + CPU.pending_exception = std::current_exception(); + return ExecutionStatus::ExecutionStatusPropagateException; + } +} + +static void wrapped_fast_stop(PPUThread &CPU) +{ + CPU.fast_stop(); +} + +std::pair RecompilationEngine::compile(const std::string & name, u32 start_address, u32 instruction_count) { + std::unique_ptr module = Compiler::create_module(m_llvm_context); + + std::unordered_map function_ptrs; + function_ptrs["execute_unknown_function"] = reinterpret_cast(CPUHybridDecoderRecompiler::ExecuteFunction); + function_ptrs["execute_unknown_block"] = reinterpret_cast(CPUHybridDecoderRecompiler::ExecuteTillReturn); + function_ptrs["PollStatus"] = reinterpret_cast(CPUHybridDecoderRecompiler::PollStatus); + function_ptrs["PPUThread.fast_stop"] = reinterpret_cast(wrapped_fast_stop); + function_ptrs["vm.reservation_acquire"] = reinterpret_cast(vm::reservation_acquire); + function_ptrs["vm.reservation_update"] = reinterpret_cast(vm::reservation_update); + function_ptrs["get_timebased_time"] = reinterpret_cast(get_timebased_time); + function_ptrs["wrappedExecutePPUFuncByIndex"] = reinterpret_cast(wrappedExecutePPUFuncByIndex); + function_ptrs["wrappedDoSyscall"] = reinterpret_cast(wrappedDoSyscall); + + Compiler(&m_llvm_context, &m_ir_builder, function_ptrs) + .translate_to_llvm_ir(module.get(), name, start_address, instruction_count); + Compiler::optimise_module(module.get()); + llvm::Module *module_ptr = module.get(); + + + llvm::ExecutionEngine *execution_engine = + EngineBuilder(std::move(module)) + .setEngineKind(EngineKind::JIT) + .setMCJITMemoryManager(std::unique_ptr(new CustomSectionMemoryManager(function_ptrs))) + .setOptLevel(llvm::CodeGenOpt::Aggressive) + .setMCPU("nehalem") + .create(); + module_ptr->setDataLayout(execution_engine->getDataLayout()); + + // Translate to machine code + execution_engine->finalizeObject(); + + Function *llvm_function = module_ptr->getFunction(name); + void *function = execution_engine->getPointerToFunction(llvm_function); + + /* m_recompilation_engine.Log() << "\nDisassembly:\n"; + auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr); + for (size_t pc = 0; pc < mci.size();) { + char str[1024]; + + auto size = LLVMDisasmInstruction(disassembler, ((u8 *)mci.address()) + pc, mci.size() - pc, (uint64_t)(((u8 *)mci.address()) + pc), str, sizeof(str)); + m_recompilation_engine.Log() << fmt::format("0x%08X: ", (u64)(((u8 *)mci.address()) + pc)) << str << '\n'; + pc += size; + } + + LLVMDisasmDispose(disassembler);*/ + + assert(function != nullptr); + return std::make_pair((Executable)function, execution_engine); +} + /** * This code is inspired from Dolphin PPC Analyst */ @@ -464,7 +510,7 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { std::unique_lock lock(local_mutex); const std::pair &compileResult = - m_compiler.Compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount); + compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount); if (!isAddressCommited(block_entry.address / 4)) commitAddress(block_entry.address / 4); diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index 18a2afea88..1b882f68d5 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -46,38 +46,22 @@ namespace ppu_recompiler_llvm { /// Pointer to an executable typedef u32(*Executable)(PPUThread * ppu_state, u64 context); - /// PPU compiler that uses LLVM for code generation and optimization + /// Parses PPU opcodes and translate them into llvm ir. class Compiler : protected PPUOpcodes, protected PPCDecoder { public: - struct Stats { - /// Time spent building the LLVM IR - std::chrono::nanoseconds ir_build_time; - - /// Time spent optimizing - std::chrono::nanoseconds optimization_time; - - /// Time spent translating LLVM IR to machine code - std::chrono::nanoseconds translation_time; - - /// Total time - std::chrono::nanoseconds total_time; - }; - - Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function, - const Executable execute_unknown_block, bool(*poll_status_function)(PPUThread * ppu_state)); + Compiler(llvm::LLVMContext *context, llvm::IRBuilder<> *builder, std::unordered_map &function_ptrs); Compiler(const Compiler&) = delete; // Delete copy/move constructors and copy/move operators virtual ~Compiler(); - /** - * Compile a code fragment described by a cfg and return an executable and the ExecutionEngine storing it - * Pointer to function can be retrieved with getPointerToFunction - */ - std::pair Compile(const std::string & name, u32 start_address, u32 instruction_count); + /// Create a module setting target triples and some callbacks + static std::unique_ptr create_module(llvm::LLVMContext &llvm_context); - /// Retrieve compiler stats - Stats GetStats(); + /// Create a function called name in module and populates it by translating block at start_address with instruction_count length. + void translate_to_llvm_ir(llvm::Module *module, const std::string & name, u32 start_address, u32 instruction_count); + + static void optimise_module(llvm::Module *module); protected: void Decode(const u32 code) override; @@ -484,7 +468,10 @@ namespace ppu_recompiler_llvm { void UNK(const u32 code, const u32 opcode, const u32 gcode) override; - private: + /// Utility function creating a function called name with Executable signature + void initiate_function(const std::string &name); + + protected: /// State of a compilation task struct CompileTaskState { enum Args { @@ -508,12 +495,6 @@ namespace ppu_recompiler_llvm { bool hit_branch_instruction; }; - /// Recompilation engine - RecompilationEngine & m_recompilation_engine; - - /// The function that should be called to check the status of the thread - bool(*m_poll_status_function)(PPUThread * ppu_state); - /// The function that will be called to execute unknown functions llvm::Function * m_execute_unknown_function; @@ -521,7 +502,7 @@ namespace ppu_recompiler_llvm { llvm::Function * m_execute_unknown_block; /// Maps function name to executable memory pointer - std::unordered_map m_executableMap; + std::unordered_map &m_executable_map; /// LLVM context llvm::LLVMContext * m_llvm_context; @@ -538,9 +519,6 @@ namespace ppu_recompiler_llvm { /// State of the current compilation task CompileTaskState m_state; - /// Compiler stats - Stats m_stats; - /// Get the name of the basic block for the specified address std::string GetBasicBlockNameFromAddress(u32 address, const std::string & suffix = "") const; @@ -726,29 +704,22 @@ namespace ppu_recompiler_llvm { } /// Call a function - template - llvm::Value * Call(const char * name, Func function, Args... args) { + template + llvm::Value * Call(const char * name, Args... args) { auto fn = m_module->getFunction(name); if (!fn) { std::vector fn_args_type = { args->getType()... }; auto fn_type = llvm::FunctionType::get(CppToLlvmType(), fn_args_type, false); fn = llvm::cast(m_module->getOrInsertFunction(name, fn_type)); fn->setCallingConv(llvm::CallingConv::X86_64_Win64); - // Note: not threadsafe - m_executableMap[name] = (Executable)(void *&)function; + // Create an entry in m_executable_map that will be populated outside of compiler + (void)m_executable_map[name]; } std::vector fn_args = { args... }; return m_ir_builder->CreateCall(fn, fn_args); } - /// Test an instruction against the interpreter - template - void VerifyInstructionAgainstInterpreter(const char * name, void (Compiler::*recomp_fn)(Args...), void (PPUInterpreter::*interp_fn)(Args...), PPUState & input_state, Args... args); - - /// Excute a test - void RunTest(const char * name, std::function test_case, std::function input, std::function check_result); - /// Handle compilation errors void CompilationError(const std::string & error); @@ -870,12 +841,22 @@ namespace ppu_recompiler_llvm { /// vector storing all exec engine std::vector > m_executable_storage; + + /// LLVM context + llvm::LLVMContext &m_llvm_context; + + /// LLVM IR builder + llvm::IRBuilder<> m_ir_builder; + + /** + * Compile a code fragment described by a cfg and return an executable and the ExecutionEngine storing it + * Pointer to function can be retrieved with getPointerToFunction + */ + std::pair compile(const std::string & name, u32 start_address, u32 instruction_count); + /// The time at which the m_address_to_ordinal cache was last cleared std::chrono::high_resolution_clock::time_point m_last_cache_clear_time; - /// PPU Compiler - Compiler m_compiler; - RecompilationEngine(); RecompilationEngine(const RecompilationEngine&) = delete; // Delete copy/move constructors and copy/move operators @@ -944,16 +925,16 @@ namespace ppu_recompiler_llvm { class CustomSectionMemoryManager : public llvm::SectionMemoryManager { private: - std::unordered_map &executableMap; + std::unordered_map &executableMap; public: - CustomSectionMemoryManager(std::unordered_map &map) : + CustomSectionMemoryManager(std::unordered_map &map) : executableMap(map) {} ~CustomSectionMemoryManager() override {} virtual uint64_t getSymbolAddress(const std::string &Name) override { - std::unordered_map::const_iterator It = executableMap.find(Name); + std::unordered_map::const_iterator It = executableMap.find(Name); if (It != executableMap.end()) return (uint64_t)It->second; return getSymbolAddressInProcess(Name); diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp index 8074eb652f..319ce948c3 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp @@ -29,9 +29,6 @@ #pragma warning(pop) #endif -extern void execute_ppu_func_by_index(PPUThread& ppu, u32 id); -extern void execute_syscall_by_index(PPUThread& ppu, u64 code); - using namespace llvm; using namespace ppu_recompiler_llvm; @@ -1755,24 +1752,8 @@ void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false); } - - -static u32 -wrappedExecutePPUFuncByIndex(PPUThread &CPU, u32 index) noexcept { - try - { - execute_ppu_func_by_index(CPU, index); - return ExecutionStatus::ExecutionStatusBlockEnded; - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } -} - void Compiler::HACK(u32 index) { - llvm::Value *status = Call("wrappedExecutePPUFuncByIndex", &wrappedExecutePPUFuncByIndex, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt32(index & EIF_USE_BRANCH ? index : index & ~EIF_PERFORM_BLR)); + llvm::Value *status = Call("wrappedExecutePPUFuncByIndex", m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt32(index & EIF_USE_BRANCH ? index : index & ~EIF_PERFORM_BLR)); llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(status, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); @@ -1787,24 +1768,11 @@ void Compiler::HACK(u32 index) { } } -static u32 wrappedDoSyscall(PPUThread &CPU, u64 code) noexcept { - try - { - execute_syscall_by_index(CPU, code); - return ExecutionStatus::ExecutionStatusBlockEnded; - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } -} - void Compiler::SC(u32 lev) { switch (lev) { case 0: { - llvm::Value *status = Call("wrappedDoSyscall", &wrappedDoSyscall, m_state.args[CompileTaskState::Args::State], GetGpr(11)); + llvm::Value *status = Call("wrappedDoSyscall", m_state.args[CompileTaskState::Args::State], GetGpr(11)); llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(status, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); @@ -1815,14 +1783,14 @@ void Compiler::SC(u32 lev) { } break; case 3: - Call("PPUThread.fast_stop", &PPUThread::fast_stop, m_state.args[CompileTaskState::Args::State]); + Call("PPUThread.fast_stop", m_state.args[CompileTaskState::Args::State]); break; default: CompilationError(fmt::format("SC %u", lev)); break; } - auto ret_i1 = Call("PollStatus", m_poll_status_function, m_state.args[CompileTaskState::Args::State]); + auto ret_i1 = Call("PollStatus", m_state.args[CompileTaskState::Args::State]); auto cmp_i1 = m_ir_builder->CreateICmpEQ(ret_i1, m_ir_builder->getInt1(true)); auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_true"); auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_true"); @@ -2293,7 +2261,7 @@ void Compiler::LWARX(u32 rd, u32 ra, u32 rb) { auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); auto val_i32_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt32Ty()); val_i32_ptr->setAlignment(4); - Call("vm.reservation_acquire", vm::reservation_acquire, m_ir_builder->CreateBitCast(val_i32_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(4)); + Call("vm.reservation_acquire", m_ir_builder->CreateBitCast(val_i32_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(4)); auto val_i32 = (Value *)m_ir_builder->CreateLoad(val_i32_ptr); val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), val_i32); auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); @@ -2565,7 +2533,7 @@ void Compiler::LDARX(u32 rd, u32 ra, u32 rb) { auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); auto val_i64_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt64Ty()); val_i64_ptr->setAlignment(8); - Call("vm.reservation_acquire", vm::reservation_acquire, m_ir_builder->CreateBitCast(val_i64_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(8)); + Call("vm.reservation_acquire", m_ir_builder->CreateBitCast(val_i64_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(8)); auto val_i64 = (Value *)m_ir_builder->CreateLoad(val_i64_ptr); val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), val_i64); SetGpr(rd, val_i64); @@ -2744,7 +2712,7 @@ void Compiler::STWCX_(u32 rs, u32 ra, u32 rb) { auto rs_i32_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt32Ty()); rs_i32_ptr->setAlignment(4); m_ir_builder->CreateStore(rs_i32, rs_i32_ptr); - auto success_i1 = Call("vm.reservation_update", vm::reservation_update, addr_i32, m_ir_builder->CreateBitCast(rs_i32_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(4)); + auto success_i1 = Call("vm.reservation_update", addr_i32, m_ir_builder->CreateBitCast(rs_i32_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(4)); auto cr_i32 = GetCr(); cr_i32 = SetBit(cr_i32, 2, success_i1); @@ -2863,7 +2831,7 @@ void Compiler::STDCX_(u32 rs, u32 ra, u32 rb) { auto rs_i64_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt64Ty()); rs_i64_ptr->setAlignment(8); m_ir_builder->CreateStore(rs_i64, rs_i64_ptr); - auto success_i1 = Call("vm.reservation_update", vm::reservation_update, addr_i32, m_ir_builder->CreateBitCast(rs_i64_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(8)); + auto success_i1 = Call("vm.reservation_update", addr_i32, m_ir_builder->CreateBitCast(rs_i64_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(8)); auto cr_i32 = GetCr(); cr_i32 = SetBit(cr_i32, 2, success_i1); @@ -3084,10 +3052,10 @@ void Compiler::MFSPR(u32 rd, u32 spr) { rd_i64 = GetVrsave(); break; case 0x10C: - rd_i64 = Call("get_timebased_time", get_timebased_time); + rd_i64 = Call("get_timebased_time"); break; case 0x10D: - rd_i64 = Call("get_timebased_time", get_timebased_time); + rd_i64 = Call("get_timebased_time"); rd_i64 = m_ir_builder->CreateLShr(rd_i64, 32); break; default: @@ -3132,7 +3100,7 @@ void Compiler::LVXL(u32 vd, u32 ra, u32 rb) { } void Compiler::MFTB(u32 rd, u32 spr) { - auto tb_i64 = Call("get_timebased_time", get_timebased_time); + auto tb_i64 = Call("get_timebased_time"); u32 n = (spr >> 5) | ((spr & 0x1f) << 5); if (n == 0x10D) { @@ -5244,7 +5212,7 @@ void Compiler::CreateBranch(llvm::Value * cmp_i1, llvm::Value * target_i32, bool // if (fn) // execStatus = m_ir_builder->CreateCall2(fn, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); // else - execStatus = Call("execute_unknown_function", nullptr, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); + execStatus = Call("execute_unknown_function", m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(execStatus, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException));