是否有英特尔 SIMD 比较函数 returns 0 或 1 而不是 0 或 0xFFFFFFFF?

Is there a Intel SIMD comparison function that returns 0 or 1 instead of 0 or 0xFFFFFFFF?

我目前正在使用英特尔 SIMD 功能:_mm_cmplt_ps( V1, V2 )。 函数 returns 包含每个组件测试结果的向量。基于是否 V1 组件小于 V2 组件,示例:

XMVECTOR Result;

Result.x = (V1.x < V2.x) ? 0xFFFFFFFF : 0;
Result.y = (V1.y < V2.y) ? 0xFFFFFFFF : 0;
Result.z = (V1.z < V2.z) ? 0xFFFFFFFF : 0;
Result.w = (V1.w < V2.w) ? 0xFFFFFFFF : 0;

return Result;

但是有没有像这样的函数 returns 1 或 0 呢?使用 SIMD 且没有解决方法的函数,因为它应该被优化 + 矢量化。

_mm_cmplt_ps 的 DirectXMath 非内部函数版本实际上是:

    XMVECTORU32 Control = { { {
            (V1.vector4_f32[0] < V2.vector4_f32[0]) ? 0xFFFFFFFF : 0,
            (V1.vector4_f32[1] < V2.vector4_f32[1]) ? 0xFFFFFFFF : 0,
            (V1.vector4_f32[2] < V2.vector4_f32[2]) ? 0xFFFFFFFF : 0,
            (V1.vector4_f32[3] < V2.vector4_f32[3]) ? 0xFFFFFFFF : 0
        } } };
    return Control.v;

XMVECTOR__m128 相同,后者是 4 个浮点数,因此它需要别名以确保它写入整数。

我使用 _mm_movemask_ps 作为 DirectXMath 函数的“控制寄存器”版本。它只收集每个 SIMD 值的最高位。

int result = _mm_movemask_ps(_mm_cmplt_ps( V1, V2 ));

result 的低半字节将包含位模式。每个通过测试的值对应一个 1 位,每个未通过测试的值对应一个 0 位。这可以用来重建 1 对 0。

你可以自己写那个函数。只有 2 条指令:

// 1.0 for lanes where a < b, zero otherwise
inline __m128 compareLessThan_01( __m128 a, __m128 b )
{
    const __m128 cmp = _mm_cmplt_ps( a, b );
    return _mm_and_ps( cmp, _mm_set1_ps( 1.0f ) );
}

这是更通用的版本,returns 两个值中的任何一个。它需要 SSE 4.1,现在几乎可以通过 97.94% of users 普遍使用,如果您必须仅支持 SSE2,请使用 _mm_and_ps、_mm_andnot_ps 和 _mm_or_ps 进行仿真。

// y for lanes where a < b, x otherwise
inline __m128 compareLessThan_xy( __m128 a, __m128 b, float x, float y )
{
    const __m128 cmp = _mm_cmplt_ps( a, b );
    return _mm_blendv_ps( _mm_set1_ps( x ), _mm_set1_ps( y ), cmp );
}