我有一个简单的问题。具有起始 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/

10-12 23:15