From ca22cd6b995413fadd99c4613f7756e7f7cf088e Mon Sep 17 00:00:00 2001 From: Walter Date: Thu, 18 Jun 2026 12:31:08 +1000 Subject: [PATCH] [SPU ASMJIT] SSE2 Vectorized `ROTH` Add vectorized 16-bit left rotate using power of two multiply. SSE2 compatible. Also added AVX512-ICL rotate via funnel shift. --- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 42 +++++++++++++++++++------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 89694affd4..f485da3290 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1863,10 +1863,18 @@ void spu_recompiler::SHL(spu_opcode_t op) void spu_recompiler::ROTH(spu_opcode_t op) //nf { + const XmmLink& va = XmmGet(op.ra, XmmType::Int); + const XmmLink& vb = XmmGet(op.rb, XmmType::Int); + + if (utils::has_avx512_icl()) + { + c->vpshldvw(va, va, vb); + c->vmovdqa(SPU_OFF_128(gpr, op.rt), va); + return; + } + if (utils::has_avx512()) { - const XmmLink& va = XmmGet(op.ra, XmmType::Int); - const XmmLink& vb = XmmGet(op.rb, XmmType::Int); const XmmLink& vt = XmmAlloc(); const XmmLink& v4 = XmmAlloc(); c->vmovdqa(v4, XmmConst(v128::from32r(0x0d0c0d0c, 0x09080908, 0x05040504, 0x01000100))); @@ -1883,21 +1891,33 @@ void spu_recompiler::ROTH(spu_opcode_t op) //nf if (utils::has_xop()) { - const XmmLink& va = XmmGet(op.ra, XmmType::Int); - const XmmLink& vb = XmmGet(op.rb, XmmType::Int); const XmmLink& vt = XmmAlloc(); c->vprotw(vt, va, vb); c->movdqa(SPU_OFF_128(gpr, op.rt), vt); return; } - for (u32 i = 0; i < 8; i++) // unrolled loop - { - c->movzx(qw0->r32(), SPU_OFF_16(gpr, op.ra, &v128::_u16, i)); - c->movzx(asmjit::x86::ecx, SPU_OFF_16(gpr, op.rb, &v128::_u16, i)); - c->rol(qw0->r16(), asmjit::x86::cl); - c->mov(SPU_OFF_16(gpr, op.rt, &v128::_u16, i), qw0->r16()); - } + // Turn shift amount into power of 2 using a float's exponent + // Calculating a negative power makes truncation cheaper + const XmmLink& v1 = XmmAlloc(); + const XmmLink& v2 = XmmAlloc(); + c->psllw(vb, 12); + c->psrlw(vb, 5); + c->paddw(vb, XmmConst(v128::from16p(std::bit_cast(-1.0f) >> 16))); + c->pxor(v1, v1); + c->pxor(v2, v2); + c->punpcklwd(v1, vb); // "shifts" the amount into the exponent + c->punpckhwd(v2, vb); + c->cvttps2dq(v1, v1); + c->cvttps2dq(v2, v2); + c->packssdw(v1, v2); // positive power (1<<15) would have saturated + c->pxor(vb, vb); + c->psubw(vb, v1); + c->movdqa(v2, va); + c->pmullw(v2, vb); + c->pmulhuw(va, vb); + c->por(va, v2); + c->vmovdqa(SPU_OFF_128(gpr, op.rt), va); } void spu_recompiler::ROTHM(spu_opcode_t op)