是否有SIMD指令来加速校验和计算

Are there SIMD instructions to speed up checksum calculations?

本文关键字:加速 校验和 计算 指令 SIMD 是否      更新时间:2023-10-16

我将不得不编写一个非常基本的校验和函数,类似于:

char sum(const char * data, const int len)
{
    char sum(0);
    for (const char * end=data+len ; data<end ; ++data)
        sum += *data;
    return sum;
}

这是微不足道的。现在,我该如何优化它呢?首先,我可能应该使用一些std::for_each和lambda或类似的东西:

char sum2(const char * data, const int len)
{
    char sum(0);
    std::for_each(data, data+len, [&sum](char b){sum+=b;});
    return sum;
}

接下来,我可以使用多个线程/内核来总结块,然后添加结果。我不会把它写下来,我担心创建线程(或者从池中获取它们)的成本,然后切割数组,然后调度所有东西,等等,考虑到我主要计算小数组的校验和,大多数是10-100字节,很少高达1000,这将不是很好。

但是我真正想要的是更低层次的东西,一些SIMD的东西,可以在128b寄存器上求和字节,或者在两个寄存器之间独立求和字节,而不携带进位,或者两者兼而有之。

世界上有这样的东西吗?

注意:这实际上是不成熟的优化,但它很有趣,所以什么鬼?

编辑:我仍然需要一种方法来总结SSE寄存器中的所有字节,比

更好的方法
char ptr[16];
_mm_storeu_si128((__m128i*)ptr, sum);
checksum += ptr[0] + ptr[1] + ptr[2]  + ptr[3]  + ptr[4]  + ptr[5]  + ptr[6]  + ptr[7]
          + ptr[8] + ptr[9] + ptr[10] + ptr[11] + ptr[12] + ptr[13] + ptr[14] + ptr[15];

是的,在MMX指令集中有这样的指令,称为"打包ADD":

  • _mm_add_pi8在Visual c++
  • __builtin_ia32_paddb in gcc

在SSE2指令集中:

  • _mm_add_epi8在Visual c++
  • __builtin_ia32_paddb128 in gcc

编辑:一个更快的方法来添加部分和:

__m128i sums;
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 1));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 2));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 4));
sums = _mm_add_epi8(sums, _mm_srli_si128(sums, 8));
checksum += _mm_cvtsi128_si32(sums);

查看_mm_add_ps。同时添加128位连续块。您需要对数组进行零填充或处理最后几个非SIMD样式。