Skip to content

[SPU] Optimize CLZ on targets without AVX512 - #18900

Merged
elad335 merged 5 commits into
RPCS3:masterfrom
WalterKruger:asmjit-clz
Jun 16, 2026
Merged

elad335 merged 5 commits into
RPCS3:masterfrom
WalterKruger:asmjit-clz

Conversation

@WalterKruger

@WalterKruger WalterKruger commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Codegen is currently poor on targets without AVX512. LLVM can't take advantage of the rounding mode being towards-zero (and is generally unoptimal), and ASMJIT isn't even vectorized.

This method works by converting the integer into a float and extracting the exponent to calculate ilog2 of the input. The count can then be derived through lzcnt = 31 - ilog2, with the subtraction being saturating so "negative" inputs are zeroed.

Added a SSE4.1 vectorized CLZ method to the SPU ASMJT.
Comment thread rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp
@AniLeo
AniLeo requested a review from Whatcookie June 16, 2026 03:16
Avoids creating a redundant `XmmGet` allocation on targets without SSE4.1, by duplicating the declaration across both target specific blocks.
@elad335

elad335 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Since cvtdq2ps is SSE2, rewrite it for the base path and conditionally adjust the register merge to SSE2 as well.

@WalterKruger

Copy link
Copy Markdown
Contributor Author

Since cvtdq2ps is SSE2, rewrite it for the base path and conditionally adjust the register merge to SSE2 as well.

Do you still want to keep SSE4.1 path? Its not a super big difference between them, it mostly shortens the dependency chain by one bitwise operation and simplifies the constant selection.

@elad335

elad335 commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Register blend happens at the end so it would be supper easy to adjust to SSE2, for psignd make a contional block with old-school merge mask and allocate the XMM you need in it.

Removed the SSE4.1 instruction to make it compatible with the baseline instruction set. Increased dependency chain by one instruction and caused constant generation to be slightly more expensive.
@WalterKruger WalterKruger changed the title [SPU ASMJIT] Add SSE4.1 CLZ method [SPU ASMJIT] Vectorize CLZ without AVX512 Jun 16, 2026
@elad335

elad335 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Btw, can you adjust the LLVM path as well? LLVM is not aware of the rounding mode and won't emit such code on itself. I would understand if it would be too much to ask in this pull request.

@WalterKruger

WalterKruger commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor Author

Btw, can you adjust the LLVM path as well?

Sure, that doesn't seem too difficult. Current codegen is pretty bad without AVX512. There is an open issue for a similar technique llvm/llvm-project#161746 but its worse due to the width extension.

(I think the linked stackoverflow also has a better method to avoid the constant generation)

@WalterKruger
WalterKruger marked this pull request as draft June 16, 2026 05:38
@Megamouse Megamouse added the CPU label Jun 16, 2026
Comment thread rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp Outdated
- Added a LLVM SPU recompiler implementation as LLVM can't take advantage of the rounding mode.
- Further optimized the method by replacing MSB check with saturation subtraction. Negative values are saturated to zero due to the float's sign bit.
@WalterKruger

Copy link
Copy Markdown
Contributor Author

I think I managed to added a SPU LLVM version. I am not very familiar with the LLVM recompiler so me know if I need to change anything.

Additionally, I managed to eliminate the zeroing logic by replacing the regular subtract with a saturation.

@WalterKruger
WalterKruger marked this pull request as ready for review June 16, 2026 07:57
@WalterKruger WalterKruger changed the title [SPU ASMJIT] Vectorize CLZ without AVX512 [SPU] Optimize CLZ on targets without AVX512 Jun 16, 2026
@elad335 elad335 added the Optimization Optimizes existing code label Jun 16, 2026
@elad335
elad335 enabled auto-merge (rebase) June 16, 2026 11:07
@elad335

elad335 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Tested it locally, the implementation works for both backends perfectly!

c->pxor(v1, XmmConst(v128::from32p(31 + exp_bias)));
c->psubusw(v1, vf); // (x==0)? 32 : 31 - (exponent - exp_bias)
c->movdqa(SPU_OFF_128(gpr, op.rt), v1);
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant return but nvm, will clean afterwards. Overall good job here!

@elad335
elad335 merged commit e429f8c into RPCS3:master Jun 16, 2026
10 checks passed
@WalterKruger
WalterKruger deleted the asmjit-clz branch June 21, 2026 02:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CPU Optimization Optimizes existing code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants