Repository navigation
[SPU] Optimize CLZ on targets without AVX512 - #18900
Conversation
Added a SSE4.1 vectorized CLZ method to the SPU ASMJT.
Avoids creating a redundant `XmmGet` allocation on targets without SSE4.1, by duplicating the declaration across both target specific blocks.
|
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. |
|
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.
|
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. |
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) |
- 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.
|
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. |
|
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; |
There was a problem hiding this comment.
Redundant return but nvm, will clean afterwards. Overall good job here!
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
ilog2of the input. The count can then be derived throughlzcnt = 31 - ilog2, with the subtraction being saturating so "negative" inputs are zeroed.