C SIMD-AVX-具有非零值而非最高位的屏蔽
我有AVX(没有AVX2或AVX-512)。我有一个32位值的向量(仅使用4个最低位,其余始终为零): 在内部,由于按位操作,我将向量保留为C SIMD-AVX-具有非零值而非最高位的屏蔽,c,simd,avx,C,Simd,Avx,我有AVX(没有AVX2或AVX-512)。我有一个32位值的向量(仅使用4个最低位,其余始终为零): 在内部,由于按位操作,我将向量保留为\uuuum256,位表示“浮点数”。我需要从向量中导出单个8位数字,其中包含1表示非零位,0表示零位 因此,对于上面的示例,我需要8位数字:10000110 我想到使用\u mm256\u cmp\u ps然后使用\u mm256\u movemask\u ps。然而,对于cmp,我不知道它是否能正常工作,如果数字不完全是浮点数,并且可以是任何“垃圾”。在
\uuuum256
,位表示“浮点数”。我需要从向量中导出单个8位数字,其中包含1表示非零位,0表示零位
因此,对于上面的示例,我需要8位数字:10000110
我想到使用\u mm256\u cmp\u ps
然后使用\u mm256\u movemask\u ps
。然而,对于cmp,我不知道它是否能正常工作,如果数字不完全是浮点数,并且可以是任何“垃圾”。在这种情况下,cmp使用哪个操作数
或者还有其他解决方案吗?从概念上讲,您所做的应该是可行的。高24位为零的浮点为有效浮点。然而,它们是非规范的 虽然它应该有效,但存在两个潜在问题:
替代方法: 因为上面的24位是零,所以可以对它们进行规格化。然后进行浮点比较 (警告:未测试的代码) 这里,
data
是您的输入,其中每个“float”的上24位为零。让我们调用每个8位整数x
或使用2^23
设置浮点的尾数,使其成为值为2^23+x
的标准化浮点
然后将
2^23
与float
进行比较,只有当x
为非零时,才会给出1。备选答案,供将来有AVX2的读者参考。
您可以强制转换到\uuu m256i
并使用SIMD整数比较
这避免了DAZ将这些小整数位模式视为零的任何问题,也避免了非规范(又称次正常)输入的微码辅助
在某些CPU上,在vcmpeqd
和vpmovmskps
之间可能有一个额外的绕过延迟周期,但您仍然领先,因为整数比较的延迟低于FP比较
int nonzero_positions_avx2(__m256 v)
{
__m256i vi = _mm256_castps_si256(v);
vi = _mm256_cmpeq_epi32(vi, _mm256_setzero_si256());
return _mm256_movemask_ps(_mm256_castsi256_ps(vi));
}
值得注意的是,您不需要使用
2^23
。只要表示的底部4位为零,几乎可以使用任何其他标准化浮点值。
int to_mask(__m256 data){
const __m256 MASK = _mm256_set1_ps(8388608.); // 2^23
data = _mm256_or_ps(data, MASK);
data = _mm256_cmp_ps(data, MASK, _CMP_NEQ_UQ);
return _mm256_movemask_ps(data);
}
int nonzero_positions_avx2(__m256 v)
{
__m256i vi = _mm256_castps_si256(v);
vi = _mm256_cmpeq_epi32(vi, _mm256_setzero_si256());
return _mm256_movemask_ps(_mm256_castsi256_ps(vi));
}