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

标签 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 不是常数,而是在运行时计算的。

最佳答案

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

我正在考虑为每个寄存器设置类似 pshufb 的东西

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

您将有一个洗牌掩码表,并使用 table[ (i-N) & 7] 洗牌 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

关于c - 从多个寄存器收集特定元素并存储到一个寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26290853/

相关文章:

c - 如何在不创建变量的情况下将项目添加到结构中

c - 这个错误提示什么?

C 从文件中删除一行不起作用

assembly - IA-32 中的段选择器

c++ - 如何在运行时简化代码生成?

assembly - x86 汇编中 cmove 指令的用途?

linux - x86 上的堆栈对齐

c - x86汇编中用于Mandelbrot循环的高效复杂算术

assembly - 在SSE中组合前缀

c - 没有监听时如何在套接字上发送消息?