The simd if else is not a ternary operator with short-circuiting, is the short version.
inline float_4 ifelse(float_4 mask, float_4 a, float_4 b) {
return (a & mask) | andnot(mask, b);
}
so both a and b get evaluated at all simd points and then the unused values get masked off
This is basically how vector-conditionals work. This is made more confusing by immediately above having
inline float ifelse(bool cond, float a, float b) {
return cond ? a : b;
}
which is by no means the same statement
For instance the float if else will work fine in a form float *x = nullptr; ifelse(true, 0.,f, *x)
whereas the simd equivalent will crash.
The basic reason for this is the SSE instruction set (which rack::simd is making it so you don’t have to see, for better in many cases, but perhaps not in this one) implements if essentially as masks. You get functions like _mm_cmpgt(a,b)
which does a parallel comparison of a and b element wise in 3 of 4 instructions and returns a mask which you then and or or on for the result, so you can have different truthiness across your vector. But as a result you don’t get short-circuiting since that’s not consistent with a single vector pipeline.
My guess is your .process method updates an internal state so the short circuited version implements one-or-the-other state but the non-short circuited version updates both (since its not short circuited) hence the difference you see.
Hope that helps!