_mm_movemask_ps() 最快的逆运算是什么?
What is the fastest inverse of _mm_movemask_ps()?
在 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
整数到浮点数的转换。
在整数域中计算掩码效率更高,并且
转换(不转换)结果之后浮动。
Peter Cordes 的回答:is there an inverse instruction to the movemask
英特尔 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
在 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
整数到浮点数的转换。
在整数域中计算掩码效率更高,并且
转换(不转换)结果之后浮动。
Peter Cordes 的回答:is there an inverse instruction to the movemask
英特尔 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