From 577a6e24597ab56c7a364bcc1742d8816ca8f164 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Mon, 29 Jun 2026 17:42:30 +0300 Subject: [PATCH] SPU Precompilation: Add support for unaligned segments --- rpcs3/Emu/Cell/SPUCommonRecompiler.cpp | 35 ++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index e8f2a31fa8..dbb7e048f8 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -646,18 +646,32 @@ spu_cache::~spu_cache() extern void utilize_spu_data_segment(u32 vaddr, const void* ls_data_vaddr, u32 size) { - if (vaddr % 4) + if (u32 rem = vaddr % 4) { - return; + // The remainder that it needs to be aligned up to the next DWORD + rem = 4 - rem; + + if (size < rem) + { + return; + } + + vaddr += rem; + ls_data_vaddr = reinterpret_cast(ls_data_vaddr) + rem; + size -= rem; } size &= -4; - if (!size || vaddr + size > SPU_LS_SIZE) + if (!size || vaddr >= SPU_LS_SIZE) { return; } + // Let SPU block search mistakes pass through + // SPU code mining is too important + size = std::min(SPU_LS_SIZE - vaddr, size); + if (!g_cfg.core.llvm_precompilation) { return; @@ -2364,11 +2378,22 @@ std::vector spu_thread::discover_functions(u32 base_addr, std::span(base_addr, 0x10); i < std::min(base_addr + ::size32(ls), 0x3FFF0); i += 0x10) + for (u32 i = base_addr, end_ls = std::min(base_addr + ::size32(ls), SPU_LS_SIZE); i < end_ls; i = utils::align(i + 1, 0x10)) { // Search for BRSL LR and BRASL LR or BR // TODO: BISL - const v128 inst = read_from_ptr>(ls, i - base_addr); + be_t inst_be{}; + + if (end_ls - i < 16) + { + std::memcpy(&inst_be, ls.data() + (i - base_addr), end_ls - i); + } + else + { + inst_be = read_from_ptr>(ls, i - base_addr); + } + + const v128 inst = inst_be; const v128 cleared_i16 = gv_and32(inst, v128::from32p(std::rotl(~0xffff, 7))); const v128 eq_brsl = gv_eq32(cleared_i16, v128::from32p(0x66u << 23)); const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask);