From fdbb0b0e2f46ef6fae143c88eaed5b2e47ca5330 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 4 Sep 2023 20:00:05 +0300 Subject: [PATCH] PPU LLVM: Optimize branch list --- rpcs3/Emu/Cell/PPUTranslator.cpp | 47 ++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 382352fd82ae..c0a55da26de5 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -13,6 +13,7 @@ #include "util/v128.hpp" #include "util/simd.hpp" #include +#include #include using namespace llvm; @@ -371,8 +372,50 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect) if (_target >= caddr && _target <= cend) { - callee = m_module->getOrInsertFunction(fmt::format("__0x%x", target), type); - cast(callee.getCallee())->setCallingConv(CallingConv::GHC); + std::unordered_set passed_targets{_target}; + + u32 target_last = _target; + + // Try to follow unconditional branches as long as there is no infinite loop + while (target_last != _target) + { + const ppu_opcode_t op{*ensure(m_info.get_ptr(target_last))}; + const ppu_itype::type itype = g_ppu_itype.decode(op.opcode); + + if (((itype == ppu_itype::BC && (op.bo & 0x14) == 0x14) || itype == ppu_itype::B) && !op.lk) + { + const u32 new_target = (op.aa ? 0 : target_last) + (itype == ppu_itype::B ? +op.bt24 : +op.bt14); + + if (target_last >= caddr && target_last <= cend) + { + if (passed_targets.emplace(new_target).second) + { + // Ok + target_last = new_target; + continue; + } + + // Infinite loop detected + target_last = _target; + } + + // Odd destination + } + else if (itype == ppu_itype::BCLR && (op.bo & 0x14) == 0x14 && !op.lk) + { + // Special case: empty function + // In this case the branch can be treated as BCLR because previous CIA does not matter + indirect = RegLoad(m_lr); + } + + break; + } + + if (!indirect) + { + callee = m_module->getOrInsertFunction(fmt::format("__0x%x", target_last - base), type); + cast(callee.getCallee())->setCallingConv(CallingConv::GHC); + } } else {