使用AVX内在函数对__mm512中的8位整数求和

问题描述 投票:0回答:1

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的奖励积分。

c x86 simd intrinsics avx
1个回答
4
投票

首先,_mm512_reduce_add_epi64不对应单个AVX512指令,但它会生成一系列混洗和添加。

要将64个epu8值减少到8个epi64值,通常使用vpsadbw指令(SAD =绝对差值之和)对零矢量,然后可以进一步减少:

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)一起使用,GCC和Clang似乎都无法优化掉该功能。

对于epi8而不是epu8,您需要先为每个元素添加128(或者使用0x80进行xor),然后使用vpsadbw减少它,最后减去64*128(或每个中间64位结果的8*128)。 [请注意,在此答案的先前版本中这是错误的]

对于epi16,我建议看一下_mm512_reduce_add_epi32_mm512_reduce_add_epi64生成的指令,并从那里做什么。


总的来说,正如@Mysticial建议的那样,取决于你的背景,减少的最佳方法是什么。例如,如果你有一个非常大的int64数组并想要一个总和作为int64,你应该只是在数据包中将它们加在一起,并且只在最后将一个数据包减少到一个int64

© www.soinside.com 2019 - 2024. All rights reserved.