SPU Precompilation: Add support for unaligned segments

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

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) 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; size &= -4;
if (!size || vaddr + size > SPU_LS_SIZE) if (!size || vaddr >= SPU_LS_SIZE)
{ {
return; 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) if (!g_cfg.core.llvm_precompilation)
{ {
return; 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 // TODO: Does not detect jumptables or fixed-addr indirect calls
const v128 brasl_mask = is_known_addr ? v128::from32p(0x62u << 23) : v128::from32p(umax); 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 // Search for BRSL LR and BRASL LR or BR
// TODO: BISL // 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 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_brsl = gv_eq32(cleared_i16, v128::from32p(0x66u << 23));
const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask); const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask);