From e625bab7eb8cd1998501d853045f183bfa3c5c17 Mon Sep 17 00:00:00 2001 From: Eladash <18193363+elad335@users.noreply.github.com> Date: Thu, 7 Mar 2024 17:07:46 +0200 Subject: [PATCH] SPU Analyzer: Detect more tail calls by examining called code --- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 42 +++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index f7e84f82f3..c12374f8e8 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -2317,7 +2317,47 @@ std::vector spu_thread::discover_functions(u32 base_addr, std::span= base_addr && next < std::min(base_addr + ::size32(ls), 0x3FFF0); it--, next += 4) + { + const spu_opcode_t test_op{read_from_ptr>(ls, next - base_addr)}; + const auto type = g_spu_itype.decode(test_op.opcode); + + if (type & spu_itype::branch) + { + break; + } + + bool is_func = false; + + if (type == spu_itype::AI && test_op.rt == 1u && test_op.ra == 1u) + { + if (test_op.si10 >= 0) + { + break; + } + + is_func = true; + } + + if (!is_func) + { + continue; + } + + addr = SPU_LS_SIZE + 4; // Terminate the next condition, no further checks needed + + if (std::count(addrs.begin(), addrs.end(), func)) + { + break; + } + + addrs.push_back(func); + break; + } + + // Search for AI R1, +x or OR R3/4, Rx, 0 before the branch // Reasoning: AI R1, +x means stack pointer restoration, branch after that is likely a tail call // R3 and R4 are common function arguments because they are the first two for (u32 back = addr - 4, it = 10; it && back >= base_addr && back < std::min(base_addr + ::size32(ls), 0x3FFF0); it--, back -= 4)