I want to implement SIMD minmag and maxmag functions. As far as I understand these functions are
minmag(a,b) = |a|<|b| ? a : b
maxmag(a,b) = |a|>|b| ?
Here's an alternate implementation which uses fewer instructions:
static inline void maxminmag_test(__m128d & a, __m128d & b) {
__m128d cmp = _mm_add_pd(a, b); // test for mean(a, b) >= 0
__m128d amin = _mm_min_pd(a, b);
__m128d amax = _mm_max_pd(a, b);
__m128d minmag = _mm_blendv_pd(amin, amax, cmp);
__m128d maxmag = _mm_blendv_pd(amax, amin, cmp);
a = maxmag, b = minmag;
}
It uses a somewhat subtle algorithm (see below), combined with the fact that we can use the sign bit as a selection mask.
It also uses @EOF's suggestion of using only one mask and switching the operand order, which saves an instruction.
I've tested it with a small number of cases and it seems to match your original implementation.
Algorithm:
if (mean(a, b) >= 0) // this can just be reduced to (a + b) >= 0
{
minmag = min(a, b);
maxmag = max(a, b);
}
else
{
minmag = max(a, b);
maxmag = min(a, b);
}