假设我有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不是常数,而是在运行时计算的。
答案 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