FP 比较像 SSE2 _mm_cmpeq_pd 可以用来比较 64 位整数吗?
Can FP compares like SSE2 _mm_cmpeq_pd be used to compare 64 bit integers?
FP 可以像 SSE2 _mm_cmpeq_pd
/ AVX _mm_cmp_pd
那样比较 64 位整数吗?
这个想法是模拟类似于 _mm_cmpeq_epi8
、_mm_cmpeq_epi16
、_mm_cmpeq_epi32
.
的缺失 _mm_cmpeq_epi64
问题是我不确定比较是按位比较还是专门处理浮点数,比如 NAN 值总是不相等。
AVX 意味着 SSE4.1 pcmpeqq
可用,在这种情况下你应该只使用 _mm_cmpeq_epi64
.
FP比较对待NaN != NaN,而-0.0 == +0.0
,如果MXCSR中设置了DAZ,则将任何小整数视为零。 (因为指数 = 0 意味着它代表非正规,并且非正规零模式将它们视为输入中的零,以避免对任何微体系结构上的任何操作(包括比较)可能的速度惩罚。IIRC,现代微体系结构没有用于比较的次正规输入的惩罚,但仍然用于一些其他操作。在任何情况下,使用 -ffast-math
构建的程序在启动时为主线程设置 FTZ 和 DAZ。)
所以 FP 比较对于整数来说并不是真正有用的,除非你知道 bits [62:52] (inclusive) 的一些但不是全部都会被设置。
使用 pcmpeqd
(_mm_cmpeq_epi32
) 比破解一些 FP 位操作要重要得多。 (虽然 @chtz 在评论中建议你可以用 xorpd
做 42.0 == (42.0 ^ (a^b))
,只要编译器不优化常量并与 0.0 进行比较。这是一个没有 -ffast-math 的 GCC 错误)。
如果您想要至少一个匹配这样的条件,那么您需要确保 64 位元素的两半都匹配,例如 movmskps
结果上的 mask & (mask<<1)
,这可以编译为 lea
/ test
。 (您可以 mask & (mask<<4)
得到 pmovmskb
结果,但这效率稍低,因为 LEA 复制和移位只能移动 0..3。)
当然,“全匹配”不关心元素大小,因此您可以在任何比较结果上使用 _mm_movemask_epi8
,并对照 0xFFFF
.
进行检查
如果您想将它用于与 and/andnot/or 的混合,您可以 pshufd
/ pand
在 64 位元素中交换两半。 (如果您提供的是 pblendvb
或 blendvpd
,那就意味着 SSE4.1 可用,因此您应该使用 pcmpeqq
。)
要模拟的更昂贵的是 SSE4.2 pcmpgtq
,尽管我认为 GCC and/or clang 确实知道如何在自动矢量化时模拟它。
FP 可以像 SSE2 _mm_cmpeq_pd
/ AVX _mm_cmp_pd
那样比较 64 位整数吗?
这个想法是模拟类似于 _mm_cmpeq_epi8
、_mm_cmpeq_epi16
、_mm_cmpeq_epi32
.
_mm_cmpeq_epi64
问题是我不确定比较是按位比较还是专门处理浮点数,比如 NAN 值总是不相等。
AVX 意味着 SSE4.1 pcmpeqq
可用,在这种情况下你应该只使用 _mm_cmpeq_epi64
.
FP比较对待NaN != NaN,而-0.0 == +0.0
,如果MXCSR中设置了DAZ,则将任何小整数视为零。 (因为指数 = 0 意味着它代表非正规,并且非正规零模式将它们视为输入中的零,以避免对任何微体系结构上的任何操作(包括比较)可能的速度惩罚。IIRC,现代微体系结构没有用于比较的次正规输入的惩罚,但仍然用于一些其他操作。在任何情况下,使用 -ffast-math
构建的程序在启动时为主线程设置 FTZ 和 DAZ。)
所以 FP 比较对于整数来说并不是真正有用的,除非你知道 bits [62:52] (inclusive) 的一些但不是全部都会被设置。
使用 pcmpeqd
(_mm_cmpeq_epi32
) 比破解一些 FP 位操作要重要得多。 (虽然 @chtz 在评论中建议你可以用 xorpd
做 42.0 == (42.0 ^ (a^b))
,只要编译器不优化常量并与 0.0 进行比较。这是一个没有 -ffast-math 的 GCC 错误)。
如果您想要至少一个匹配这样的条件,那么您需要确保 64 位元素的两半都匹配,例如 movmskps
结果上的 mask & (mask<<1)
,这可以编译为 lea
/ test
。 (您可以 mask & (mask<<4)
得到 pmovmskb
结果,但这效率稍低,因为 LEA 复制和移位只能移动 0..3。)
当然,“全匹配”不关心元素大小,因此您可以在任何比较结果上使用 _mm_movemask_epi8
,并对照 0xFFFF
.
如果您想将它用于与 and/andnot/or 的混合,您可以 pshufd
/ pand
在 64 位元素中交换两半。 (如果您提供的是 pblendvb
或 blendvpd
,那就意味着 SSE4.1 可用,因此您应该使用 pcmpeqq
。)
要模拟的更昂贵的是 SSE4.2 pcmpgtq
,尽管我认为 GCC and/or clang 确实知道如何在自动矢量化时模拟它。