mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-07-09 17:25:18 -06:00
SPU LLVM: Add ARM checksum UABA path
This commit is contained in:
parent
ed145540a2
commit
35f65c2244
@ -1835,15 +1835,18 @@ public:
|
||||
llvm::Value* starta_pc = m_ir->CreateAnd(get_pc(starta), 0x3fffc);
|
||||
llvm::Value* data_addr = _ptr(m_lsptr, starta_pc);
|
||||
|
||||
#ifndef ARCH_ARM64
|
||||
llvm::Value* acc0 = nullptr;
|
||||
llvm::Value* acc1 = nullptr;
|
||||
bool toggle = true;
|
||||
#endif
|
||||
|
||||
// Use a 512bit simple checksum to verify integrity if size is atleast 512b * 3
|
||||
// This code uses a 512bit vector for all hardware to ensure behavior matches.
|
||||
// The checksum path is still faster even on narrow hardware.
|
||||
if ((end - starta) >= 192 && !g_cfg.core.precise_spu_verification)
|
||||
{
|
||||
#ifndef ARCH_ARM64
|
||||
for (u32 j = starta; j < end; j += 64)
|
||||
{
|
||||
int indices[16];
|
||||
@ -1928,6 +1931,105 @@ public:
|
||||
// Compare result with zero
|
||||
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
||||
m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely);
|
||||
#else
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
const auto acc_init = ConstantAggregateZero::get(get_type<u32[4]>());
|
||||
llvm::Value* checksum_parts[4] = {acc_init, acc_init, acc_init, acc_init};
|
||||
u32 checksum[16] = {0};
|
||||
|
||||
for (u32 j = starta; j < end; j += 64)
|
||||
{
|
||||
llvm::Value* vls[4] = {};
|
||||
u32 words[16] = {};
|
||||
bool any_data = false;
|
||||
|
||||
for (u32 part = 0; part < 4; part++)
|
||||
{
|
||||
int indices[4];
|
||||
bool holes = false;
|
||||
bool data = false;
|
||||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
const u32 k = j + (part * 4 + i) * 4;
|
||||
|
||||
if (k < start || k >= end || !func.data[(k - start) / 4])
|
||||
{
|
||||
indices[i] = 4;
|
||||
holes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
indices[i] = i;
|
||||
data = true;
|
||||
words[part * 4 + i] = func.data[(k - start) / 4];
|
||||
}
|
||||
}
|
||||
|
||||
if (!data)
|
||||
{
|
||||
vls[part] = acc_init;
|
||||
continue;
|
||||
}
|
||||
|
||||
any_data = true;
|
||||
|
||||
// Load unaligned code block from LS
|
||||
vls[part] = m_ir->CreateAlignedLoad(get_type<u32[4]>(), _ptr(data_addr, j + part * 16 - starta), llvm::MaybeAlign{4});
|
||||
|
||||
// Mask if necessary
|
||||
if (holes)
|
||||
{
|
||||
vls[part] = m_ir->CreateShuffleVector(vls[part], acc_init, llvm::ArrayRef(indices, 4));
|
||||
}
|
||||
}
|
||||
|
||||
if (!any_data)
|
||||
{
|
||||
// Skip full-sized holes
|
||||
continue;
|
||||
}
|
||||
|
||||
// Keep the checksum logically 512-bit wide while using four NEON vectors.
|
||||
// The add/uabd pattern is intended to select UABA for the difference lanes.
|
||||
checksum_parts[0] = m_ir->CreateAdd(checksum_parts[0], vls[0]);
|
||||
checksum_parts[1] = m_ir->CreateAdd(checksum_parts[1], m_ir->CreateCall(get_intrinsic<u32[4]>(llvm::Intrinsic::aarch64_neon_uabd), {vls[0], vls[1]}));
|
||||
checksum_parts[2] = m_ir->CreateAdd(checksum_parts[2], vls[2]);
|
||||
checksum_parts[3] = m_ir->CreateAdd(checksum_parts[3], m_ir->CreateCall(get_intrinsic<u32[4]>(llvm::Intrinsic::aarch64_neon_uabd), {vls[2], vls[3]}));
|
||||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
checksum[i] += words[i];
|
||||
checksum[4 + i] += words[i] > words[4 + i] ? words[i] - words[4 + i] : words[4 + i] - words[i];
|
||||
checksum[8 + i] += words[8 + i];
|
||||
checksum[12 + i] += words[8 + i] > words[12 + i] ? words[8 + i] - words[12 + i] : words[12 + i] - words[8 + i];
|
||||
}
|
||||
|
||||
check_iterations++;
|
||||
}
|
||||
|
||||
llvm::Value* elem = nullptr;
|
||||
|
||||
for (u32 part = 0; part < 4; part++)
|
||||
{
|
||||
auto* const_vector = ConstantDataVector::get(m_context, llvm::ArrayRef(checksum + part * 4, 4));
|
||||
llvm::Value* acc = m_ir->CreateXor(checksum_parts[part], const_vector);
|
||||
acc = m_ir->CreateBitCast(acc, get_type<u64[2]>());
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
const auto lane = m_ir->CreateExtractElement(acc, i);
|
||||
elem = elem ? m_ir->CreateOr(elem, lane) : lane;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare result with zero
|
||||
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
||||
m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely);
|
||||
#endif
|
||||
}
|
||||
#ifdef ARCH_ARM64
|
||||
else
|
||||
|
||||
Loading…
Reference in New Issue
Block a user