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* starta_pc = m_ir->CreateAnd(get_pc(starta), 0x3fffc);
|
||||||
llvm::Value* data_addr = _ptr(m_lsptr, starta_pc);
|
llvm::Value* data_addr = _ptr(m_lsptr, starta_pc);
|
||||||
|
|
||||||
|
#ifndef ARCH_ARM64
|
||||||
llvm::Value* acc0 = nullptr;
|
llvm::Value* acc0 = nullptr;
|
||||||
llvm::Value* acc1 = nullptr;
|
llvm::Value* acc1 = nullptr;
|
||||||
bool toggle = true;
|
bool toggle = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Use a 512bit simple checksum to verify integrity if size is atleast 512b * 3
|
// 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.
|
// This code uses a 512bit vector for all hardware to ensure behavior matches.
|
||||||
// The checksum path is still faster even on narrow hardware.
|
// The checksum path is still faster even on narrow hardware.
|
||||||
if ((end - starta) >= 192 && !g_cfg.core.precise_spu_verification)
|
if ((end - starta) >= 192 && !g_cfg.core.precise_spu_verification)
|
||||||
{
|
{
|
||||||
|
#ifndef ARCH_ARM64
|
||||||
for (u32 j = starta; j < end; j += 64)
|
for (u32 j = starta; j < end; j += 64)
|
||||||
{
|
{
|
||||||
int indices[16];
|
int indices[16];
|
||||||
@ -1928,6 +1931,105 @@ public:
|
|||||||
// Compare result with zero
|
// Compare result with zero
|
||||||
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0));
|
||||||
m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely);
|
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
|
#ifdef ARCH_ARM64
|
||||||
else
|
else
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user