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

时间:2018-10-08 11:03:00

标签: 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”解释为数组索引,其中数组元素大于输入键,还是引用设置的位数?

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

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

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

1 个答案:

答案 0 :(得分:2)

#import "YourTest.h" #import <Test/Test-Swift.h> #import "Test-Swift.h" // Error in this line @implementation YourTest -(void)testTest { // This is how I want to use the swift class MyTest *test = [MyTest new]; [test addTest]; } @end 通过从向量中获取每个元素的高位来生成整数位图。打印为十六进制或基数为2时效果更好。

如果您只关心0计数与非零计数,只需检查#import <UIKit/UIKit.h> //! Project version number for Test. FOUNDATION_EXPORT double TestVersionNumber; //! Project version string for Test. FOUNDATION_EXPORT const unsigned char TestVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import <Test/PublicHeader.h>

movemask检查它们是否全部正确。 (4元素向量为4位)。


使用popcount找出有多少是真实的。 if(bitmask != 0)计算其输入中的设置位数。

使用if(bitmask == 0x0f)查找比较正确的第一个元素的位置。 (如果向量是从内存加载的,则从低到高的内存地址计数)。请注意,__builtin_popcnt仅对非零输入有意义。例如在__builtin_ctz循环中,只有在打破__builtin_ctz的搜索循环来确定此向量中存在匹配项之后,才使用memchr。 (epi8,因为我说的是字节搜索循环,不像打包的ctz比较)。

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


要遍历比赛,您可以使用清除最低位设置操作,如果仍然设置了任何位,则_mm256_movemask_epi8(cmp_result) == 0找出哪个位。参见_lzcnt_u32(bitmask)

如果在启用了BMI1的情况下进行编译,则

double将有效地编译为BMI1 ctz指令。与x & (x-1)

(要使其正常工作,您肯定希望blsr与向量元素大小匹配,因此对于64位整数,请将向量转换为-march=haswell,以便可以使用{{1} }。