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
This commit is contained in:
Whatcookie 2026-05-28 08:19:33 -04:00 committed by Ani
parent 4a92d96cf4
commit 2f2ac69d60

View File

@ -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<u32[4]>(1, 2, 4, 8);
const auto bits = vsplat<u32[4]>(zext<u32>(trunc<i4>(v)));
set_vr(op.rt, sext<s32[4]>((bits & masks) == masks));
#else
const auto m = bitcast<bool[4]>(trunc<i4>(v));
set_vr(op.rt, sext<s32[4]>(m));
#endif
}
void FSMH(spu_opcode_t op)
{
const auto v = extract(get_vr(op.ra), 3);
#ifdef ARCH_ARM64
const auto masks = build<u16[8]>(1, 2, 4, 8, 16, 32, 64, 128);
const auto bits = vsplat<u16[8]>(zext<u16>(trunc<u8>(v)));
set_vr(op.rt, sext<s16[8]>((bits & masks) == masks));
#else
const auto m = bitcast<bool[8]>(trunc<u8>(v));
set_vr(op.rt, sext<s16[8]>(m));
#endif
}
void FSMB(spu_opcode_t op)
{
const auto v = extract(get_vr(op.ra), 3);
#ifdef ARCH_ARM64
const auto masks = build<u8[16]>(1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128);
const auto bytes = bitcast<u8[16]>(vsplat<u16[8]>(trunc<u16>(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<s8[16]>((bits & masks) == masks));
#else
const auto m = bitcast<bool[16]>(trunc<u16>(v));
set_vr(op.rt, sext<s8[16]>(m));
#endif
}
template <typename TA>
@ -6333,8 +6355,15 @@ public:
void FSMBI(spu_opcode_t op)
{
#ifdef ARCH_ARM64
const auto masks = build<u8[16]>(1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128);
const auto bytes = bitcast<u8[16]>(vsplat<u16[8]>(get_imm<u16>(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<s8[16]>((bits & masks) == masks));
#else
const auto m = bitcast<bool[16]>(get_imm<u16>(op.i16));
set_vr(op.rt, sext<s8[16]>(m));
#endif
}
void IL(spu_opcode_t op)