我有一个简单的问题。具有起始 uint_32 值(例如 125)和要添加的 __m128i 操作数,例如 (+5,+10,-1,-5)。我想尽快得到一个 vector (125 + 5, 125 + 5 + 10, 125 + 5 + 10 - 1, 125 + 5 + 10 - 1 - 5),即从操作数中累积添加值到起始值。到目前为止,我能想到的唯一解决方案是添加 4 个 __m128i 变量。例如,它们将是
/* pseudoSSE code... */
__m128i src = (125,125,125,125)
__m128i operands =(5,10,-1,-5)
/* Here I omit the partitioning of operands into add1,..add4 for brevity */
__m128i add1 = (+05,+05,+05,+05)
__m128i add2 = (+00,+10,+10,+10)
__m128i add3 = (+00,+00,-01,-01)
__m128i add4 = (+00,+00,+00,-05)
__m128i res1 = _mm_add_epu32( add1, add2 )
__m128i res2 = _mm_add_epu32( add3, add4 )
__m128i res3 = _mm_add_epu32( res1, add2 )
__m128i res = _mm_add_epu32( res3, src )
就这样,我得到了我想要的。对于此解决方案,我将需要设置所有 add_ 变量,然后执行 4 次添加。我真正要问的是这是否可以更快地完成。要么通过一些不同的算法,要么使用一些我还不知道的专门的 SSE 函数(比如 _mm_cumulative_sum())。非常感谢。
最佳答案
您可以添加更多并行性并使用 3 个添加而不是 4 个:
const __m128i src = _mm_set1_epi32(125);
const __m128i operands = _mm_set_epi32(5,10,-1,-5);
const __m128i shift1 =
_mm_add_epi32(operands,
_mm_and_si128(_mm_shuffle_epi32(operands, 0xF9),
_mm_set_epi32(0,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF)));
const __m128i shift2 =
_mm_add_epi32(shift1,
_mm_and_si128(_mm_shuffle_epi32(shift1, 0xFE),
_mm_set_epi32(0,0,0xFFFFFFFF,0xFFFFFFFF)));
const __m128i res = _mm_add_epi32(src, shift2);
这里使用了 SSE2 指令集。使用较新的指令集,您可以将 _mm_and_si128/_mm_shuffle_epi32 替换为单个指令,例如 _mm_shuffle_epi8。
累积和是通过 2 次加法计算的,如下所示:
a b c d
+ a b c
------------------
a a+b b+c c+d
+ a a+b
------------------
a a+b a+b+c a+b+c+d
SSE 不太适合这样的任务。它的性能仅适用于“垂直”操作,但它需要大量额外的工作用于“水平”操作,这里需要。
关于c++ - 上证累计求和,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12971139/