SPU Precompilation: Add support for unaligned segments

This commit is contained in:
Elad 2026-06-29 17:42:30 +03:00
parent 8eaa3ec9a2
commit 577a6e2459

View File

@ -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<const char*>(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<u32>(SPU_LS_SIZE - vaddr, size);
if (!g_cfg.core.llvm_precompilation)
{
return;
@ -2364,11 +2378,22 @@ std::vector<u32> spu_thread::discover_functions(u32 base_addr, std::span<const u
// TODO: Does not detect jumptables or fixed-addr indirect calls
const v128 brasl_mask = is_known_addr ? v128::from32p(0x62u << 23) : v128::from32p(umax);
for (u32 i = utils::align<u32>(base_addr, 0x10); i < std::min<u32>(base_addr + ::size32(ls), 0x3FFF0); i += 0x10)
for (u32 i = base_addr, end_ls = std::min<u32>(base_addr + ::size32(ls), SPU_LS_SIZE); i < end_ls; i = utils::align<u32>(i + 1, 0x10))
{
// Search for BRSL LR and BRASL LR or BR
// TODO: BISL
const v128 inst = read_from_ptr<be_t<v128>>(ls, i - base_addr);
be_t<v128> 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<be_t<v128>>(ls, i - base_addr);
}
const v128 inst = inst_be;
const v128 cleared_i16 = gv_and32(inst, v128::from32p(std::rotl<u32>(~0xffff, 7)));
const v128 eq_brsl = gv_eq32(cleared_i16, v128::from32p(0x66u << 23));
const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask);