From 1b54e8910c6bbd1be27c30651efeecdbf8638491 Mon Sep 17 00:00:00 2001 From: Malcolm Date: Mon, 1 Jun 2026 16:45:22 -0400 Subject: [PATCH] SPU: Add some comments clarifying very obtuse code --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 13 +++++++++++++ rpcs3/Emu/Cell/SPUThread.cpp | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index c459febcdc..c8c3db5c29 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -1847,8 +1847,11 @@ public: if ((end - starta) >= 192 && !g_cfg.core.precise_spu_verification) { #ifdef ARCH_ARM64 + // Loop if there is at least 288 bytes of data to checksum on ARM. + // Each ARM checksum block consumes 6 NEON vectors: 2 direct adds and 2 UABD accumulates. constexpr u32 checksum_block_size = 96; #else + // Loop if there is atleast (16 * stride) bytes of data to checksum to save some instruction cache constexpr u32 checksum_block_size = 64; #endif constexpr u32 checksum_loop_vectors = 16; @@ -2003,6 +2006,13 @@ public: const auto cond = m_ir->CreateICmpNE(elem, m_ir->getInt64(0)); m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely); #else + // Very cursed "checksumming" code + // 96 bytes per ARM checksum step + //vls[0] -> add + //vls[1], vls[2] -> uaba + //vls[3] -> add + //vls[4], vls[5] -> uaba + //This allows us to save on some ALU ops relative to load instructions const auto acc_init = ConstantAggregateZero::get(get_type()); llvm::Value* checksum_parts[4] = {acc_init, acc_init, acc_init, acc_init}; u32 checksum[16] = {0}; @@ -2237,6 +2247,9 @@ public: m_ir->CreateBitCast(expected, get_type())), get_type()); }; + // Multiply accumulate based comparison + // See comment above cmp16_pair_accum_arm64 in SPUThread.cpp + // Dotproduct instructions have slightly higher throughput on many common ARM cores const auto accumulate_pair = [&](llvm::Value* lhs, llvm::Value* rhs) { llvm::Value*& acc = *accs[acc_index]; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 93af9e8b03..dee3f15309 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -245,6 +245,15 @@ static FORCE_INLINE bool cmp_rdata_avx(const __m256i* lhs, const __m256i* rhs) } #endif +// Insane idea to accelerate comparisons on Neon with a fixed length +// Common ARM chips like the a78 and a715 can Perform 3 128b loads/clock +// But only execute 2 128b instructions on the ALU per clock +// To consume data any faster, we need to use ALU instructions that take 3 inputs +// Idea: compare data, filling each lane with either -1 or 0 +// Then multiply each pair of comparisons together, resulting in 1 if both pairs were -1 +// Accummulate those results, and compare the accumulated value to the expected count +// Benchmarks showed this to be faster even on arm machines that aren't capable of more loads than ALU operations +// Tested on Tensor G1, Snapdragon 8 gen 2, and the Snapdragon 8 Elite gen 5 #if defined(ARCH_ARM64) static FORCE_INLINE int16x8_t cmp16_pair_accum_arm64( int16x8_t acc, const v128& lhs0, const v128& rhs0, const v128& lhs1, const v128& rhs1)