C++ C++;SIMD:在数组中累积uint64_t元素的POPCOUNTs

C++ C++;SIMD:在数组中累积uint64_t元素的POPCOUNTs,c++,sse,simd,C++,Sse,Simd,我正在尝试使用SSE指令为数组中的uint64\u t整数累加POPCOUNTs。 这是我的代码: #include <emmintrin.h> #include <nmmintrin.h> #include <chrono> int main() { uint64_t data[4] = {1,1,1,1}; uint64_t data2[4] = {1,0,1,0}; __m128i* ptr = (__m128i*) data;

我正在尝试使用SSE指令为数组中的
uint64\u t
整数累加
POPCOUNT
s。
这是我的代码:

#include <emmintrin.h>
#include <nmmintrin.h>
#include <chrono>

int main()
{    
  uint64_t data[4] = {1,1,1,1};
  uint64_t data2[4] = {1,0,1,0};
  __m128i* ptr = (__m128i*) data;
  __m128i* ptr2 = (__m128i*) data2;

  int total = 0;
  for (int i = 0; i < 2; ++i, ++ptr, ++ptr2)
    total += popcount(_mm_and_si128(*ptr, *ptr2)); // This doesn't work    
}
#包括
#包括
#包括
int main()
{    
uint64_t数据[4]={1,1,1};
uint64_t data2[4]={1,0,1,0};
__m128i*ptr=(u m128i*)数据;
__m128i*ptr2=(uu m128i*)数据2;
int-total=0;
对于(int i=0;i<2;++i,++ptr,++ptr2)
total+=popcount(_mm_and_si128(*ptr,*ptr2));//这不起作用
}

我需要一个等价的
POPCOUNT
函数,该函数对
\u mm\u和_si128
的输出进行操作,这样我就可以将所有
POPCOUNT
累积到
total
变量中。

POPCOUNT
不适用于SSE寄存器。您需要将
\u mm\u和
的结果保存到内存中,然后在两半上使用
POPCOUNT
\u mm\u popcnt\u u64
),因为
POPCOUNT
指令最多只能使用64位操作数。

关于这个主题,我们有一篇完整的研究论文:。尽管标题如此,它也涵盖了苏格兰和南方能源公司。有关相关的软件库,请参阅。它包括各种各样的快速函数来完成这类工作

简单回答:您可以使用Muła popcount函数,如下所示:

 __m128i popcount(__m128i v) {
    const __m128i lookup = _mm_setr_epi8(
    /* 0 */ 0, /* 1 */ 1, /* 2 */ 1, /* 3 */ 2,
    /* 4 */ 1, /* 5 */ 2, /* 6 */ 2, /* 7 */ 3,
    /* 8 */ 1, /* 9 */ 2, /* a */ 2, /* b */ 3,
    /* c */ 2, /* d */ 3, /* e */ 3, /* f */ 4
);
   __m128i low_mask = _mm_set1_epi8(0x0f);
   __m128i lo  = _mm_and_si128(v, low_mask);
   __m128i hi  = _mm_and_si128(_mm_srli_epi16(v, 4), low_mask);
   __m128i popcnt1 = _mm_shuffle_epi8(lookup, lo);
   __m128i popcnt2 = _mm_shuffle_epi8(lookup, hi);
  return _mm_sad_epu8(_mm_add_epi8(popcnt1, popcnt2), _mm_setzero_si128());
}

popcount
调用的结果是一个128位计数器,由两个64位计数器组成,必须相加。为了节省计算时间,可以在最后对两个64位计数器进行求和。

你会问:-)?@KerrekSB我觉得这两个问题是在各自的具体空间中进行的,我认为把它们放在一起是没有帮助的:)两个可能对你非常有用的链接是和。最近的一篇博文中提到了他们两人。@zx485:不再有SSSE3链接@IsaacPascual:Thx。archive.org上的新链接:谢谢,你知道我应该包含哪些头文件,以便我可以调用
\u mm\u popcnt\u u64
?@Cauchy
#包括“nmmintrin.h”
。完整引用.I在函数“\uuuum128i\umm\uMullo\uEpi32(\uuum128i,\uuum128i):/usr/lib/gcc/x86\u64-redhat-linux/5.3.1/include/smmintrin.h:328:22:错误:”\uuuuuuv4su“未在此范围内声明返回(\uuuuuuuuum128i*(\uv4y)); ^ /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/smmintrin.h:328:29:error:expected')在“uuuuux”返回(uuuum128i)((uuuv4su)uuuuuuux*(uuuuuuuuuv4su)Y)之前
我如何才能访问这两部分?@Cauchy我不知道您的编译错误,因为我的mm头不使用_v4su,但是要访问这两部分,您可以查看
\u_m128i
中的
的定义。它是一个联合体,使用
m128i_i64
可以访问两个64位的半部分。