5 ms·
This sort of use of turning conditionals into bitmasks and then shuffling masked values around was fairly common back in the day when writing code for SSE intri
by a_e_k 2y ago
This sort of use of turning conditionals into bitmasks and then shuffling masked values around was fairly common back in the day when writing code for SSE intrinsics.
You wouldn't want to have to check each lane individually since that would spoil the point of using SSE. So you'd write masking ops like this and keep things parallel, tThen judiciously use any() and all() type intrinsics to check whether the lanes could agree to skip certain blocks conditionally.
(This was before ISPC and before autovectorization to handle it for you.)
- djmips 2y agoDoes ISPC + auto vectorization truly remove the need to attend to these details in the most optimized code?
- a_e_k 2y agoThey can, yes. For example, here's a simple Compiler Explorer link with a simple loop conditionally copying from one of two values: https://godbolt.org/z/TbeK99sx1 https://godbolt.org/z/TbeK99sx1. If you look at the assembly code produced, you'll see in lines 9-11, it's doing a similar thing as the swap_if() function: ANDing one value with the mask, ANDing the other with the negation of the mask, and then ORing them together. And it produced that automatically from the ternary in the loop. They can also do things like automatically generate epilogues with a serial loop to handle the leftover items if the loop count isn't an even multiple of the SIMD width. That's something else that I remember writing by hand before autovectorizers. That said, coaxing an autovectorizer to actually vectorize a loop can be an art in itself. They're notoriously finicky. My favorite used to be the one in the old ("classic") ICC compiler where you use compiler flags to get a nice optimization report which would explain exactly why it chose what it did for each loop. You could also set #pragma's which would noisily warn or error out if the associated loop failed to vectorize for some reason. (And of course, a lot of this stuff you might just use GPU compute for now.)
- mgaunard 2y agonormally there is an instruction for this called blend (since SSE4.1). There shouldn't be a need to do any bitwise magic.
- jcla1 2y agoYou can get gcc to generate the blend instruction in the example given - you just have to 'force' it to use SIMD more aggressively by, for example, using -march=native.
- mgaunard 2y agoThat's not forcing anything, if you're not getting blend you're just targeting an old ISA without that instruction. It's up to you to choose your target adequately based on your deployment requirements.