问题描述
这是一个函数,它接受一个 64 位整数数组并计算每个位置有多少 1 位。使用 AVX2,应该可以同时对 16 位执行此操作,但是每个计数器最多只能达到 65536。以下代码将计算 65500 个值的每个块,但我错过了一个关键操作:我找不到方法将每个数字单独移动不同的计数。我错过了什么吗?代码中的注释显示了该位置。理想情况下,每个数字都从内存中加载,并分成 4 个 16 位块。每个块都可以在一个 256 位寄存器上处理。为了计数超过 64k,计数将存储在内存中并添加到更宽的寄存器中。
void countHistBits4(const uint64_t p[],uint32_t n,uint32_t hist[64]) {
uint16_t shifts[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint16_t maskss[16] = {1,1};
__m256i shift = _mm256_load_si256((__m256*)shifts);
__m256i mask1 = _mm256_load_si256((__m256*)masks);
for (uint32_t j = 0; j < n; j += 65500) {
__m256i count1 = _mm256_setzero_si256();
__m256i count2 = _mm256_setzero_si256();
__m256i count3 = _mm256_setzero_si256();
__m256i count4 = _mm256_setzero_si256();
for (uint32_t i = 0; i < 65500; i++) {
__m256i v1 = _mm256_set1_epi16(p[i] & 0xFFFF);
__m256i v2 = _mm256_set1_epi16((p[i] >> 16) & 0xFFFF);
__m256i v3 = _mm256_set1_epi16((p[i] >> 32) & 0xFFFF);
__m256i v4 = _mm256_set1_epi16((p[i] >> 48) & 0xFFFF);
// for each bit,right shift to the 1 position,and with 1
// and add to the count
// this isn't right. How to shift each 16 bit value by different const?
// if that isn't possible,what is the approach?
v1 = _mm256_srl_epi16(v1,shift);
v2 = _mm256_srl_epi16(v2,shift);
v3 = _mm256_srl_epi16(v3,shift);
v4 = _mm256_srl_epi16(v4,shift);
v1 = _mm256_and_si256(v1,mask1);
count1 = _mm256_adds_epi16 (count1,v1);
v2 = _mm256_and_si256(v2,mask1);
count2 = _mm256_adds_epi16 (count2,v2);
v3 = _mm256_and_si256(v3,mask1);
count3 = _mm256_adds_epi16 (count3,v3);
v4 = _mm256_and_si256(v4,mask1);
count4 = _mm256_adds_epi16 (count4,v4);
}
// store and add into larger counters...
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)