如何检查 AVX 内在的 inf __m256
How to check inf for AVX intrinsic __m256
检查 AVX 内在 __m256
(8 float
的向量)是否包含任何 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;
}
如果您想要无穷大值的矢量掩码:
#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;
}
我有一个想法,但它最终只有在你想测试所有元素是否为无限时才有帮助。哎呀
使用 AVX2,您可以使用 PTEST
测试所有元素是否为无穷大。我从 EOF 对 this question 的评论中得到了使用 xor 比较相等性的想法,我将其用于我的回答。我以为我将能够制作一个较短版本的 test-for-any-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
}
对于 AVX512,有一个 __mmask8 _mm512_fpclass_pd_mask (__m512d a, int imm8)
。 (vfpclasspd
)。 (参见 Intel's guide)。它的输出是一个掩码寄存器,我还没有研究 testing/branching 那里的值。但是您可以测试 any/all of +/- zero, +/- inf, Q/S NaN, Denormal, Negative.
我认为更好的解决方案是使用 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);
}
内在的_mm256_castps_si256
只是为了让编译器开心"This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency."
vptest
优于 vmovmskps
因为它设置了零标志而 vmovmskps
没有。使用 vmovmskps
编译器必须生成 test
来设置零标志。
检查 AVX 内在 __m256
(8 float
的向量)是否包含任何 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;
}
如果您想要无穷大值的矢量掩码:
#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;
}
我有一个想法,但它最终只有在你想测试所有元素是否为无限时才有帮助。哎呀
使用 AVX2,您可以使用 PTEST
测试所有元素是否为无穷大。我从 EOF 对 this question 的评论中得到了使用 xor 比较相等性的想法,我将其用于我的回答。我以为我将能够制作一个较短版本的 test-for-any-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
}
对于 AVX512,有一个 __mmask8 _mm512_fpclass_pd_mask (__m512d a, int imm8)
。 (vfpclasspd
)。 (参见 Intel's guide)。它的输出是一个掩码寄存器,我还没有研究 testing/branching 那里的值。但是您可以测试 any/all of +/- zero, +/- inf, Q/S NaN, Denormal, Negative.
我认为更好的解决方案是使用 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);
}
内在的_mm256_castps_si256
只是为了让编译器开心"This intrinsic is only used for compilation and does not generate any instructions, thus it has zero latency."
vptest
优于 vmovmskps
因为它设置了零标志而 vmovmskps
没有。使用 vmovmskps
编译器必须生成 test
来设置零标志。