nal*_*zok 0 c x86 simd intrinsics avx
AVX512 为我们提供了对__mm512向量中所有单元格求和的内在函数。然而,他们的一些同行却不见了:还没有_mm512_reduce_add_epi8。
_mm512_reduce_add_ps     //horizontal sum of 16 floats
_mm512_reduce_add_pd     //horizontal sum of 8 doubles
_mm512_reduce_add_epi32  //horizontal sum of 16 32-bit integers
_mm512_reduce_add_epi64  //horizontal sum of 8 64-bit integers
基本上,我需要MAGIC在以下代码段中实现。
__m512i all_ones = _mm512_set1_epi16(1);
short sum_of_ones = MAGIC(all_ones);
/* now sum_of_ones contains 32, the sum of 32 ones. */
最明显的方法是使用_mm512_storeu_epi8数组元素并将其相加,但这会很慢,而且可能会使缓存无效。我想存在一种更快的方法。
实施的奖励积分_mm512_reduce_add_epi16也是如此。
首先,_mm512_reduce_add_epi64不对应一条AVX512指令,而是产生一系列的shuffle和addition。
要将 64 个epu8值减少到 8 个epi64值,通常vpsadbw对零向量使用指令 (SAD=Sum of Absolute Differences),然后可以进一步减少:
long reduce_add_epu8(__m512i a)
{
    return _mm512_reduce_add_epi64(_mm512_sad_epu8(a, _mm512_setzero_si512()));
}
在 Godbolt 上试试:https ://godbolt.org/z/1rMiPH 。不幸的是,如果函数与_mm512_set1_epi16(1).
为epi8代替epu8,你需要首先添加128到每个元件(或与异或0x80),那么它使用减小vpsadbw并在结束减法64*128(或8*128每个中间64位结果)。[请注意,这在此答案的先前版本中是错误的]
因为epi16我建议看看什么指令_mm512_reduce_add_epi32,_mm512_reduce_add_epi64并从中生成和推导出要做什么。
总的来说,正如@Mysticial 所建议的,这取决于您的上下文,减少的最佳方法是什么。例如,如果您有一个非常大的 数组int64并且想要一个总和 as int64,您应该将它们逐包添加在一起,并且只有在最后将一个数据包减少为单个int64.