从多个寄存器中收集特定元素并存储到一个寄存器

时间:2014-10-10 02:07:31

标签: c x86 sse intrinsics avx

假设我有8个SSE寄存器,枚举为r0,r1,r2,...,r7,每个寄存器包含8个16位整数。我想创建一个新的寄存器,它包含8个寄存器中每个寄存器的第i个元素,从r0开始,到r7。换句话说,我想获得一个包含以下内容的注册表:

r0[i],r1[i],r2[i],r3[i],r4[i],r5[i],r6[i],r7[i]

如何使用SSE(或AVX)完成?

谢谢!

请注意,索引i不是常数,而是在运行时计算的。

1 个答案:

答案 0 :(得分:1)

这似乎是一个有趣的挑战。如果您需要在算法中执行此操作,那么现在应该考虑如何组织事情,以便必须 这就像Paul R在评论中建议的那样,而不是像整个8x8转置那样的东西。

我想为每个寄存器设置pshufb之类的东西,设置

xmmN[N] = old_xmmN[i]; // with other elements zeroed.

您有一张随机播放面具表,并使用table[ (i-N) & 7]进行shufflign xmmN。或者,在零之前/之后重复使用随机屏蔽,您可以使用从table[i]开始的8个连续屏蔽。 (因此,您只需将地址计算到寄存器中一次,并使用增加的位移。

然后POR在树中一起注册。 (实际上,选择第一个POR的操作数并在前两个PSHUFB之后安排它,因此组合可以与改组重叠。)

通过存储到内存然后重新加载,您可以获得更好的吞吐量。 (但可能更糟糕的延迟,因为这将导致存储转发延迟。)

rdi = tmp buffer
switch(i) {
    case 0:
        movd   [rdi],   xmm0
        movd   [rdi+2], xmm1
        ...
        movd   [rdi+14], xmm8  // note: writes all the way to [rdi+17].  use pextrw to avoid that.
        break;
    case 1:
        pextrw [rdi],   xmm0, 1;  // SSE4.1 for memory dest pextrw
        pextrw [rdi+2], xmm1, 1
        ...
        break;
    case 2:
        same, but with imm8 = 2;
        break;
    ...
}
movdqa xmm0, [rdi]   ;// ~10 cycle store-forwarding stall