SPU LLVM: Discourage memory mirrors use on LQD/STQD

This commit is contained in:
Elad 2026-06-30 09:25:47 +03:00
parent bb5dc93bec
commit 09a39fac5d

View File

@ -9288,6 +9288,11 @@ public:
return byteswap(data);
}
static constexpr u64 make_negative_LS_offset(u32 original)
{
return original | ~u64{SPU_LS_SIZE - 1};
}
void STQX(spu_opcode_t op)
{
const auto a = get_vr(op.ra);
@ -9297,17 +9302,20 @@ public:
{
if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok)
{
data._u32[3] %= SPU_LS_SIZE;
// "sign extend" offset addend
// Discourage the use of multiple addresses to refer to the same block of memory (due to memory mirrors use)
// Which may confuse LLVM's optimization
const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? make_negative_LS_offset(data._u32[3]) : data._u32[3];
if (const u32 remainder = data._u32[3] % 0x10; remainder == 0)
{
value_t<u64> addr = eval(splat<u64>(data._u32[3]) + zext<u64>(extract(pair.second, 3) & 0x3fff0));
value_t<u64> addr = eval(splat<u64>(addend) + zext<u64>(extract(pair.second, 3) & 0x3fff0));
make_store_ls(addr, get_vr<u8[16]>(op.rt));
return;
}
else
{
value_t<u64> addr = eval(splat<u64>(data._u32[3] - remainder) + zext<u64>((extract(pair.second, 3) + remainder) & 0x3fff0));
value_t<u64> addr = eval(splat<u64>(addend - remainder) + zext<u64>((extract(pair.second, 3) + remainder) & 0x3fff0));
make_store_ls(addr, get_vr<u8[16]>(op.rt));
return;
}
@ -9327,17 +9335,20 @@ public:
{
if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok)
{
data._u32[3] %= SPU_LS_SIZE;
// "sign extend" offset addend
// Discourage the use of multiple addresses to refer to the same block of memory
// Which may confuse LLVM's optimization
const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? make_negative_LS_offset(data._u32[3]) : data._u32[3];
if (const u32 remainder = data._u32[3] % 0x10; remainder == 0)
{
value_t<u64> addr = eval(splat<u64>(data._u32[3]) + zext<u64>(extract(pair.second, 3) & 0x3fff0));
value_t<u64> addr = eval(splat<u64>(addend) + zext<u64>(extract(pair.second, 3) & 0x3fff0));
set_vr(op.rt, make_load_ls(addr));
return;
}
else
{
value_t<u64> addr = eval(splat<u64>(data._u32[3] - remainder) + zext<u64>((extract(pair.second, 3) + remainder) & 0x3fff0));
value_t<u64> addr = eval(splat<u64>(addend - remainder) + zext<u64>((extract(pair.second, 3) + remainder) & 0x3fff0));
set_vr(op.rt, make_load_ls(addr));
return;
}
@ -9398,18 +9409,22 @@ public:
if (auto [ok, x, y] = match_expr(a, match<u32[4]>() + match<u32[4]>()); ok)
{
if (auto [ok1, data] = get_const_vector(x.value, m_pos + 1); ok1 && data._u32[3] % 16 == 0)
for (auto pair : std::initializer_list<std::pair<llvm_match_t<u32[4]>, llvm_match_t<u32[4]>>>{{x, y}, {y, x}})
{
value_t<u64> addr = eval(zext<u64>(extract(y, 3) & 0x3fff0) + ((get_imm<u64>(op.si10) << 4) + splat<u64>(data._u32[3] & 0x3fff0)));
make_store_ls(addr, get_vr<u8[16]>(op.rt));
return;
}
if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok)
{
// "sign extend" offset addend
// Discourage the use of multiple addresses to refer to the same block of memory
// Which may confuse LLVM's optimization
const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? make_negative_LS_offset(data._u32[3]) : data._u32[3];
if (auto [ok2, data] = get_const_vector(y.value, m_pos + 2); ok2 && data._u32[3] % 16 == 0)
{
value_t<u64> addr = eval(zext<u64>(extract(x, 3) & 0x3fff0) + ((get_imm<u64>(op.si10) << 4) + splat<u64>(data._u32[3] & 0x3fff0)));
make_store_ls(addr, get_vr<u8[16]>(op.rt));
return;
if (const u32 remainder = data._u32[3] % 0x10; remainder == 0)
{
value_t<u64> addr = eval(zext<u64>(extract(pair.second, 3) & 0x3fff0) + ((get_imm<u64>(op.si10) << 4) + splat<u64>(addend)));
make_store_ls(addr, get_vr<u8[16]>(op.rt));
return;
}
}
}
}
@ -9421,20 +9436,22 @@ public:
{
const auto a = get_vr(op.ra);
if (auto [ok, x1, y1] = match_expr(a, match<u32[4]>() + match<u32[4]>()); ok)
if (auto [ok, x, y] = match_expr(a, match<u32[4]>() + match<u32[4]>()); ok)
{
if (auto [ok1, data] = get_const_vector(x1.value, m_pos + 1); ok1 && data._u32[3] % 16 == 0)
for (auto pair : std::initializer_list<std::pair<llvm_match_t<u32[4]>, llvm_match_t<u32[4]>>>{{x, y}, {y, x}})
{
value_t<u64> addr = eval(zext<u64>(extract(y1, 3) & 0x3fff0) + ((get_imm<u64>(op.si10) << 4) + splat<u64>(data._u32[3] & 0x3fff0)));
set_vr(op.rt, make_load_ls(addr));
return;
}
if (auto [ok, data] = get_const_vector(pair.first.value, m_pos); ok)
{
// "sign extend" offset addend
const u64 addend = (data._u32[3] >= SPU_LS_SIZE) ? data._u32[3] | ~u64{SPU_LS_SIZE - 1} : data._u32[3];
if (auto [ok2, data] = get_const_vector(y1.value, m_pos + 2); ok2 && data._u32[3] % 16 == 0)
{
value_t<u64> addr = eval(zext<u64>(extract(x1, 3) & 0x3fff0) + ((get_imm<u64>(op.si10) << 4) + splat<u64>(data._u32[3] & 0x3fff0)));
set_vr(op.rt, make_load_ls(addr));
return;
if (const u32 remainder = data._u32[3] % 0x10; remainder == 0)
{
value_t<u64> addr = eval(zext<u64>(extract(pair.second, 3) & 0x3fff0) + ((get_imm<u64>(op.si10) << 4) + splat<u64>(addend)));
set_vr(op.rt, make_load_ls(addr));
return;
}
}
}
}