sse - _mm_movemask_ps() 的最快逆函数是什么?

标签 sse simd

How to perform the inverse of _mm256_movemask_epi8 (VPMOVMSKB)? ,OP 要求使用 _mm256_movemask_epi8 的逆函数,但是对于 SSE 的 _mm_movemask_ps(),是否有更简单的版本?这是我能想到的最好的结果,还算不错。

__m128 movemask_inverse(int x) {
    __m128 m = _mm_setr_ps(x & 1, x & 2, x & 4, x & 8);
    return _mm_cmpneq_ps(m, _mm_setzero_ps());
}

最佳答案

反向移动掩码的效率在很大程度上取决于编译器。 使用 gcc 大约需要 21 instructions .

但是,使用 clang -std=c99 -O3 -m64 -Wall -march=nehalem 代码矢量化效果很好, 结果实际上还不错:

movemask_inverse_original:              # @movemask_inverse_original
        movd    xmm0, edi
        pshufd  xmm0, xmm0, 0           # xmm0 = xmm0[0,0,0,0]
        pand    xmm0, xmmword ptr [rip + .LCPI0_0]
        cvtdq2ps        xmm1, xmm0
        xorps   xmm0, xmm0
        cmpneqps        xmm0, xmm1
        ret
    

不过,您不需要cvtdq2ps 整数到 float 的转换。 在整数域中计算掩码效率更高,并且 转换(不转换)结果之后 float 。 Peter Cordes 的回答:is there an inverse instruction to the movemask instruction in intel avx2? , 讨论了关于 AVX2 案例的许多想法。 大多数这些想法也可以以某种形式用于 SSE 案例。 LUT 解决方案和 ALU 解决方案适合您的情况。

具有内部函数的 ALU 解决方案:

__m128 movemask_inverse_alternative(int x) {
    __m128i msk8421 = _mm_set_epi32(8, 4, 2, 1);
    __m128i x_bc = _mm_set1_epi32(x);
    __m128i t = _mm_and_si128(x_bc, msk8421);
    return _mm_castsi128_ps(_mm_cmpeq_epi32(msk8421, t));
}

使用 gcc 8.3 生成的程序集:gcc -std=c99 -O3 -m64 -Wall -march=nehalem

movemask_inverse_alternative:
  movd xmm1, edi
  pshufd xmm0, xmm1, 0
  pand xmm0, XMMWORD PTR .LC0[rip]
  pcmpeqd xmm0, XMMWORD PTR .LC1[rip]
  ret

关于sse - _mm_movemask_ps() 的最快逆函数是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56622298/

相关文章:

c++ - 我不明白使用sse的代码在哪里有问题

c - _mm_sad_epu8 比 _mm_sad_pu8 快

Swift SIMD 或 Accelerate Sum UInt32

c++ - 是否有 SIMD 指令来加速校验和计算?

c++ - 使用 SIMD 查找表

clang - 为什么添加 xorps 指令使这个函数使用 cvtsi2ss 并添加 ~5x 快?

c++ - MSVC 2013 : crash at addpd xmm6, xmmword ptr [rax+rbx*8]

simd - 在 Powerpc 上,是否有与英特尔的 movemask 内在函数等效的东西?

x86 - shuffle 和 permute 有什么区别

c++ - 使用 SIMD AVX 计算两个排序数组的对称差异的大小