SIMD - AVX - 使用非零值而不是最高位进行掩码

Mar*_*rry 5 c simd avx

我有 AVX(没有 AVX2 或 AVX-512)。我有一个具有 32 位值的向量(仅使用 4 个最低位,其余部分始终为零):

[ 1010, 0000, 0000, 0000, 0000, 1010, 1010, 0000]
Run Code Online (Sandbox Code Playgroud)

在内部,我将向量保留为__m256因为按位运算,并且这些位代表“浮点数”。我需要从向量中导出单个 8 位数字,其中 1 表示非零,0 表示零位。

所以对于上面的例子,我需要8位数字:10000110

我有想法使用_mm256_cmp_ps然后_mm256_movemask_ps。但是,对于 cmp,如果数字不完全是浮点数并且可以是任何“垃圾”,我不知道它是否能正常工作。在这种情况下,cmp 使用哪个操作数?

或者还有其他解决办法吗?

Mys*_*ial 5

从概念上讲,你正在做的事情应该有效。高 24 位为零的浮点数是有效浮点数。然而,它们是非正常的。

虽然它应该可以工作,但有两个潜在的问题:

  1. 如果 FP 模式设置为将非正规数刷新为零,则它们都将被视为零。(因此,打破了这种方法)
  2. 因为这些是非正规的,所以您最终可能会遭受巨大的性能损失,具体取决于硬件是否可以本机处理它们。

替代方法:

由于高 24 位为零,因此您可以对它们进行标准化。然后进行浮点比较。

(警告:未经测试的代码)

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);
}
Run Code Online (Sandbox Code Playgroud)

这里data是您的输入,其中每个“浮点数”的高 24 位为零。我们将这些 8 位整数称为x

2^23设置浮点数的尾数,使其成为值为 的标准化浮点数2^23 + x

2^23然后与as -进行比较,仅当 the非零float时,它才会给出 1 。x

  • 值得注意的是,您不需要使用“2^23”。只要表示形式的底部 4 位为零,您就可以使用几乎任何其他标准化浮点值。 (2认同)