【问题标题】:Is there a Intel SIMD comparison function that returns 0 or 1 instead of 0 or 0xFFFFFFFF?是否有返回 0 或 1 而不是 0 或 0xFFFFFFFF 的英特尔 SIMD 比较函数?
【发布时间】:2020-10-29 00:59:48
【问题描述】:

我目前正在使用英特尔 SIMD 功能:_mm_cmplt_ps( V1, V2 )。 该函数返回一个包含每个组件测试结果的向量。根据 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;

但是有这样的函数返回 1 或 0 吗?一个使用 SIMD 且没有变通办法的函数,因为它应该被优化 + 矢量化。

【问题讨论】:

  • 不,如果您需要,您可以使用_mm_set1_epi32(1) 的向量andps 来清除高位。或从0 中减去整数。但如果你想有条件地增加计数器,使用psubd 来做counter -= cmp_result 因为x -= -1x += 1,而不是先否定或屏蔽。
  • 你打算用 1 或 0 做什么,而你不能用 -1 或 0 做什么?
  • 或者您的意思是返回1.0f 的位模式?通常您实际上并不需要它,请参阅SSE Comparison Intrinsics - How to get 1 or 0 from a comparison?
  • 另一种方法是使用 _mm_srli_epi32 将结果右移 31 位,这样就无需使用寄存器来保存它们。
  • 请尝试在问题中解释您的实际问题,而不是您尝试解决其中的一部分(IMO,您有一个xy-problem)-看起来更像您需要一个混合(但是你最后的评论有点含糊)

标签: intel sse simd intrinsics


【解决方案1】:

您可以自己编写该函数。只有两条指令:

// 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 ) );
}

这是更通用的版本,它返回 2 个值中的任何一个。它需要 SSE 4.1,现在几乎可以使用 97.94% of users

// 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 );
}

【讨论】:

  • 请注意,blendv 是 SSE4.1,但是是的,如果您无法优化实际生成 float 1.0 或 uint32 1,这就是您要做的事情
【解决方案2】:

_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。

【讨论】:

    猜你喜欢
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 2019-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    相关资源
    最近更新 更多