C++ 如何检查AVX内在的inf _uM256

C++ 如何检查AVX内在的inf _uM256,c++,c,sse,intrinsics,avx,C++,C,Sse,Intrinsics,Avx,检查AVX内部\uuuu m256(8的向量浮点)是否包含任何inf的最佳方法是什么?我试过了 __m256 X=_mm256_set1_ps(1.0f/0.0f); _mm256_cmp_ps(X,X,_CMP_EQ_OQ); 但这与true相比。请注意,此方法将找到nan(与false相比)。因此,一种方法是检查X=nan&&0*X==nan: __m256 Y=_mm256_mul_ps(X,_mm256_setzero_ps()); // 0*X=nan if X=inf _mm2

检查AVX内部
\uuuu m256
(8的向量
浮点
)是否包含任何
inf
的最佳方法是什么?我试过了

__m256 X=_mm256_set1_ps(1.0f/0.0f);
_mm256_cmp_ps(X,X,_CMP_EQ_OQ);
但这与
true
相比。请注意,此方法将找到
nan
(与
false
相比)。因此,一种方法是检查
X=nan&&0*X==nan

__m256 Y=_mm256_mul_ps(X,_mm256_setzero_ps());   // 0*X=nan if X=inf
_mm256_andnot_ps(_mm256_cmp_ps(Y,Y,_CMP_EQ_OQ),
                 _mm256_cmp_ps(X,X,_CMP_EQ_OQ));

然而,这似乎有些冗长。有没有更快的方法?

如果要检查向量是否有无穷大:

#include <limits>

bool has_infinity(__m256 x){
    const __m256 SIGN_MASK = _mm256_set1_ps(-0.0);
    const __m256 INF = _mm256_set1_ps(std::numeric_limits<float>::infinity());

    x = _mm256_andnot_ps(SIGN_MASK, x);
    x = _mm256_cmp_ps(x, INF, _CMP_EQ_OQ);
    return _mm256_movemask_ps(x) != 0;
}
#包括
布尔有无穷大(uuum256 x){
常数m256符号掩码=mm256_set1_ps(-0.0);
常量m256 INF=\u mm256\u set1\u ps(std::numeric\u limits::infinity());
x=_mm256_和not_ps(符号掩码,x);
x=_mm256_cmp_ps(x,INF,_cmp_EQ_OQ);
返回_mm256_movemask_ps(x)!=0;
}
如果需要无穷大值的向量掩码:

#include <limits>

__m256 is_infinity(__m256 x){
    const __m256 SIGN_MASK = _mm256_set1_ps(-0.0);
    const __m256 INF = _mm256_set1_ps(std::numeric_limits<float>::infinity());

    x = _mm256_andnot_ps(SIGN_MASK, x);
    x = _mm256_cmp_ps(x, INF, _CMP_EQ_OQ);
    return x;
}
#包括
__m256是无穷大(uum256 x){
常数m256符号掩码=mm256_set1_ps(-0.0);
常量m256 INF=\u mm256\u set1\u ps(std::numeric\u limits::infinity());
x=_mm256_和not_ps(符号掩码,x);
x=_mm256_cmp_ps(x,INF,_cmp_EQ_OQ);
返回x;
}

我有一个想法,但它最终只在您想要测试所有元素是否为无限元素时起作用。哎呀

使用AVX2,您可以使用
PTEST
测试无限大的所有元素。我从EOF的评论中得到了使用xor来比较等式的想法,我在那里用它作为我的答案。我以为我可以为任何inf生成一个较短版本的测试,但当然,
pxor
只能作为所有256b相等的测试

#include <limits>

bool all_infinity(__m256 x){
    const __m256i SIGN_MASK = _mm256_set1_epi32(0x7FFFFFFF);  // -0.0f inverted
    const __m256 INF = _mm256_set1_ps(std::numeric_limits<float>::infinity());

    x = _mm256_xor_si256(x, INF);  // other than sign bit, x will be all-zero only if all the bits match.
    return _mm256_testz_si256(x, SIGN_MASK); // flags are ready to branch on directly
}
#包括
布尔全部无穷大(uuum256 x){
常数m256i符号掩码=\u mm256\u设置1\u epi32(0x7FFFFFFF);//-0.0f反转
常量m256 INF=\u mm256\u set1\u ps(std::numeric\u limits::infinity());
x=_mm256_xor_si256(x,INF);//除符号位外,只有当所有位都匹配时,x才全部为零。
return _mm256_testz_si256(x,SIGN_MASK);//标志已准备好直接进行分支
}

对于AVX512,有一个
\uuuuMMASK8\uMM512\uFPClass\uPD\uMask(\uuuuM512dA,intimm8)
。(
vfpclasspd
)。(见附件)。它的输出是一个掩码寄存器,我还没有研究在那里测试/分支一个值。但是你可以测试+/-zero、+/-inf、Q/S NaN、非规范、负值中的任何一个/全部。

我认为更好的解决方案是使用
vptest
而不是
vmovmskps

bool has_infinity(const __m256 &x) {
    __m256 s   = _mm256_andnot_ps(_mm256_set1_ps(-0.0), x);
    __m256 cmp = _mm256_cmp_ps(s,_mm256_set1_ps(1.0f/0.0f),0);
    __m256i cmpi = _mm256_castps_si256(cmp);
    return !_mm256_testz_si256(cmpi,cmpi);
}
内在的
\u mm256\u castps\u si256
只是为了让编译器满意


vptest
优于
vmovmskps
,因为它设置了零标志,而
vmovmskps
没有。使用
vmovmskps
编译器必须生成
test
以设置零标志。

屏蔽符号位并直接与正无穷大进行比较。这是2条指令。@Mysticial 3:我还必须加载+inf。根据编译器的操作方式,常量可以作为内存访问进行内联。比如:
vandnps-ymm1,ymm0,YMMPTR[MASK];vcmpps ymm1,ymm1,YMMPTR[Infinitity],0如果它在一个循环中,编译器可能会将两个常量都拉入寄存器。@Mystical您介意将注释“升级”为答案吗?您的
has _∞
函数似乎是
ptest
之前的老方法
vmovmskps
也需要
test
,而
vptest
设置
RFLAGS
寄存器,不需要
test
。根据我回答中的Peter评论,似乎
ptest
movmsk
没有什么大的优势。这可能会引起你的兴趣。我在这里做了类似的事情。我想你是否可以自己使用
vptest
生成一个
has _∞
?我不这么认为,因为您所能做的就是测试表示
inf
的位模式是否存在。您需要的是测试所有位是否已设置。我认为,如果您希望在一个元素与您的模式匹配时条件为真,但其他元素可以是任何东西,那么您需要类似于
pcmpeq
cmpps
的东西来将匹配的精确位模式转换为全集或无集。
movmsk
ptest
的对比并不像您想象的那么明显<代码>测试
可以与
jcc
融合,而
测试
为2 UOP。但我认为
ptest
的延迟更低。@PeterCordes,好的观点!我想这就是为什么Paul R发现我使用
ptest
的解决方案只比
movmsk
快一点,而不是快很多。