c - 使用 __builtin_popcount 或其他内在函数来处理 _mm256_movemask_pd 比较位图的结果?

标签 c simd intrinsics avx bitmask

我有这段代码,我希望最终实现本文中的位掩码评估算法的修改版本 - Adapting Tree Structures for Processing with SIMD Instructions

#include <stdint.h>
#include <immintrin.h>
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdalign.h>

int main(void)
{
    __m256d avx_creg, res, avx_sreg;
    int bitmask;
    uint64_t key = 503;

    avx_sreg = _mm256_castsi256_pd(_mm256_set1_epi64x(key));
    alignas(32) uint64_t v[4]; 
    _mm256_store_pd((double*)v, avx_sreg);
    printf("v2_u64: %lld %lld %lld %lld\n", v[0], v[1],v[2],v[3]);
    uint64_t b[4]= {500,505,510,515};
    avx_creg = _mm256_castsi256_pd(
                   _mm256_loadu_si256((__m256i const *)&b));
    //
    alignas(32) uint64_t v1[4]; 
    _mm256_store_pd((double*)v1, avx_creg);
    printf("v2_u64: %lld %lld %lld %lld\n", v1[0], v1[1],v1[2],v1[3]);

    res      = _mm256_cmp_pd(avx_sreg, avx_creg, 30);
    bitmask  = _mm256_movemask_pd(res);
    int mmask = __builtin_popcount(bitmask);
    printf("mmask is %d\n",mmask);

    return 0;
}

上面的代码将mmask的值打印为1。所以这里是我完全不清楚的地方。我是否应该将数字“1”解释为数组索引,其中数组元素大于输入键,还是指设置的位数?

例如,如果我将 key 更改为 499,则 mmask 将打印为 0。

最后,如果我将 key 更改为 517,则 mmask 的值为 4。

有人可以澄清一下吗?我还有第二个问题,如果有人建议,我可以将其作为一个单独的问题提出。是否可以从 AVX 内在函数中获取大于给定输入键的所有值?

最佳答案

movemask 通过从 vector 中获取每个元素的高位来生成整数位图。将其打印为十六进制或以 2 为基数以便更好地查看。

如果您只关心 0 与非零计数,只需检查 if(bitmask != 0)

或者if(bitmask == 0x0f)来检查它们是否都为真。 (4 元素 vector 为 4 位)。


使用 popcount 来找出有多少是真实的。 __builtin_popcnt 计算其输入中设置的位数。

使用__builtin_ctz查找比较正确的第一个元素的位置。 (如果 vector 是从内存加载的,则从低内存地址到高内存地址计数)。请注意,__builtin_ctz 仅对非零输入有意义。例如在 memchr 循环中,只有在 _mm256_movemask_epi8(cmp_result) == 0 上突破搜索循环后,您才需要使用 ctz 来确定该 vector 中有一个匹配项。 (epi8 因为我正在谈论字节搜索循环,与您的 Packed-double 比较不同)。

您可能想使用 BMI1 _lzcnt_u32(bitmask)如果您已经需要 AVX2,则在位掩码 = 0 上获得明确定义的结果(32 个前导零)。 (因为我认为所有 AVX2 CPU 都有 BMI1。)


要迭代匹配,您可以使用clear-lowest-set-bit操作,如果仍然有任何位设置,则ctz来找出哪一个。请参阅Clearing the lowest set bit of a number .

如果您在启用 BMI1 的情况下进行编译,例如

x & (x-1) 将有效编译为 BMI1 blsr 指令与-march=haswell

(为了使其正常工作,您肯定需要一个与您的 vector 元素大小相匹配的 movemask ,因此对于 64 位整数,请将您的 vector 转换为 _pd 这样您就可以可以使用_mm256_movemask_pd。)

关于c - 使用 __builtin_popcount 或其他内在函数来处理 _mm256_movemask_pd 比较位图的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52700868/

相关文章:

c - 根据 POSIX 标准,在同一套接字上并行调用 send/recv 是否有效?

c - 分段故障

c++ - Open MP:SIMD循环中的SIMD兼容功能?

c - SIMD 值得吗?有更好的选择吗?

c++ - 如何使用 SSE 将 _m128i 转换为 unsigned int?

c++ - 如何混合 32 位整数?或 : Why is there no _mm256_blendv_epi32?

c++ - "vperm v0,v0,v0,v17"和未使用的 v0 有什么作用?

c - 如何在 C 中处理一个 float 以写入 4 个单独的字节?

c - 尝试打印帕斯卡三角形时,第 13 次迭代打印错误答案

c - Vanilla C 下降替代英特尔内在函数?