From 2f2ac69d605a3b19aa00636cdcd39b3fbf278850 Mon Sep 17 00:00:00 2001 From: Whatcookie Date: Thu, 28 May 2026 08:19:33 -0400 Subject: [PATCH] SPU LLVM: Idiomatic FSM implementation - Compiles down to just 2 instructions on Neon, instead of falling back to scalar instructions - Remove this workaround when LLVM fixes this issue upstream: https://github.com/llvm/llvm-project/issues/200325 --- rpcs3/Emu/Cell/SPULLVMRecompiler.cpp | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 10be1f28f2..b7093a01bf 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -5657,22 +5657,44 @@ public: } const auto v = extract(get_vr(op.ra), 3); +#ifdef ARCH_ARM64 +// Workaround for bad codegen via LLVM +// More idiomatic version that compiles to 2 neon instructions +// Remove me when addressed by upstream llvm: https://github.com/llvm/llvm-project/issues/200325 - Whatcookie + const auto masks = build(1, 2, 4, 8); + const auto bits = vsplat(zext(trunc(v))); + set_vr(op.rt, sext((bits & masks) == masks)); +#else const auto m = bitcast(trunc(v)); set_vr(op.rt, sext(m)); +#endif } void FSMH(spu_opcode_t op) { const auto v = extract(get_vr(op.ra), 3); +#ifdef ARCH_ARM64 + const auto masks = build(1, 2, 4, 8, 16, 32, 64, 128); + const auto bits = vsplat(zext(trunc(v))); + set_vr(op.rt, sext((bits & masks) == masks)); +#else const auto m = bitcast(trunc(v)); set_vr(op.rt, sext(m)); +#endif } void FSMB(spu_opcode_t op) { const auto v = extract(get_vr(op.ra), 3); +#ifdef ARCH_ARM64 + const auto masks = build(1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128); + const auto bytes = bitcast(vsplat(trunc(v))); + const auto bits = zshuffle(bytes, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + set_vr(op.rt, sext((bits & masks) == masks)); +#else const auto m = bitcast(trunc(v)); set_vr(op.rt, sext(m)); +#endif } template @@ -6333,8 +6355,15 @@ public: void FSMBI(spu_opcode_t op) { +#ifdef ARCH_ARM64 + const auto masks = build(1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128); + const auto bytes = bitcast(vsplat(get_imm(op.i16))); + const auto bits = zshuffle(bytes, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1); + set_vr(op.rt, sext((bits & masks) == masks)); +#else const auto m = bitcast(get_imm(op.i16)); set_vr(op.rt, sext(m)); +#endif } void IL(spu_opcode_t op)