【问题标题】:How to store 4 32 bit floats into one 128 bit xmm register?如何将 4 个 32 位浮点数存储到一个 128 位 xmm 寄存器中?
【发布时间】:2019-11-16 04:21:12
【问题描述】:

我想将 4 个 32 位浮点数存储到 xmm0 中,其中每个浮点数都存储在一个 128 位寄存器中。 例如我有 4 个花车: xmm1: 10.2 xmm2: 5.8 xmm3: 9.3 xmm4:12.7(每个只使用 128 位寄存器的 32 位) 并希望它们像这样存储到 xmm0 中: 10.2、5.8、9.3、12.7 以便将它们存储在 xmm0 内的旁边。

然后我还想在对 xmm0 做了一些数学运算后分别提取它们(例如 mulps ..)

我尝试过使用 movlps 和 movhps,但它们只使用内存来加载,而不是使用 128 位寄存器作为源。由于性能原因,我不想使用任何额外的内存。

PSLLDQ 可能会有所帮助,但我的问题是否有更好的解决方案?

【问题讨论】:

  • PSLLD 不会像您认为的那样做。它不会移动双字本身,它会移动每个双字内的位。请改用SHUFPSPSLLDQ
  • I asked GCC and clang to do it。他们将xmm1..4 合并为xmm0。两者都使用 3 条指令,每条指令都应使用端口 5 和 1c lat/tput(但我只浏览了 Agner Fog 的表格并且仅适用于 SklX)。但是如果我没记错的话,gcc one 只使用 SSE 扩展。
  • unpcklpsmovlhps 可以将内存或其他寄存器作为第二个参数。如果您不需要 AVX 指令,只需获取@MargaretBloom 的链接并将-march=cannonlake 替换为-msse(或-msse4.2,或您喜欢的任何指令集):godbolt.org/z/ruhVhl
  • @MargaretBloom:我不知道有什么方法可以用 SSE/AVX2 击败 3 端口 5 微指令。到目前为止,最明显的方法是 2x unpcklps + unpcklpdmovlhps。但是既然你提到了它,如果你可以使用shufps 将你的输入输入到[abxx] [xxcd],或者实际上可能:[axcx] [xbxd](因为 shufps 输出的低 2 个元素来自第一个 source=dst,另一半来自另一个源。)x86-64 GCC 默认使用基线 x86-64,即 SSE1 + SSE2。跨度>
  • @pedzer:查看_mm_set_ps(f3,f2,f1,f0) 的编译器输出。或者查看 Agner Fog 的优化指南:他有一章是关于 SSE/AVX 的,其中有一个方便的按类型列出的数据移动指令表。 agner.org/optimize

标签: assembly x86 x86-64 sse simd


【解决方案1】:

查看 compiler output for _mm_set_ps(f3,f2,f1,f0)_mm_setr_ps(f0,f1,f2,f3) 以及您选择的曲调和 -march 选项。

或者看看Agner Fog's optimization guide:他有一章是关于 SSE/AVX 的,里面有一个方便的按类型列出的数据移动指令表。非常适合了解在高度非正交的 SSE/AVX 扩展中可以使用哪些 shuffle。


正如人们所指出的那样,标准方法是 2x unpcklps 将对合并到 [00ba] [00dc] 的向量中,其中 0 是一个无关值,或者实际上 0.0 如果上层元素你的标量浮点数恰好为零。 (我的符号遵循 Intel 惯例,图中高元素位于 left,因此左移将数据移动到符号的左侧,并且查看具有不同元素宽度的数据不会改变你是怎么写的。)

然后movlhps将一个xmm寄存器的低位qword复制到另一个xmm寄存器的高位qword(合并到现有值中)。

如果这对您来说不是很明显且不为人所知,那么您应该使用带有内在函数的 C 语言编写,并查看优化的编译器输出以了解基本方法。 clang 有一个非常好的 shuffle 优化器,可以找到更好的方法将内在函数的逻辑实现到 asm 中。


可能有更好的方法:

这 3 条指令都是随机播放的,并且在英特尔 Sandybridge 系列 CPU 上,每个时钟的吞吐量限制为 1 条(竞争端口 5)。

如果我们有可用于blendps 的 SSE4.1(带有即时混合控制),我们也许可以将其用作最后一步,而不是随机播放。它可以在任何端口上运行。

我认为我们可以使用shufps 来创建[0c0a][d0b0] 的向量。 shufps 输出的低 2 个元素来自第一个 source=dst 操作数,另一半来自另一个源。

如果您的输入向量实际上是零扩展且绝对没有高垃圾,您可以使用 SSE1 orps 而不是混合来获得 [dcba]

【讨论】:

    猜你喜欢
    • 2011-01-14
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 2017-10-16
    • 2012-06-28
    • 1970-01-01
    • 2019-04-28
    相关资源
    最近更新 更多