如何将两个打包的 64 位四字加载到 128 位 xmm 寄存器中

How to load two packed 64-bit quadwords into a 128-bit xmm register

我有两个 UInt64(即 64 位四字)整数。

如何将它们加载到 xmm 寄存器中,例如xmm0:


我发现:

movq xmm0, v[0]

但这只会移动 v[0],并将 xmm0 中的高 64 位设置为零:

xmm0 0000000000000000 24FC18D93B2C9D8F

奖金问题

编辑

正如 W. Chang 指出的那样,字节顺序化很少,我同意它是相反的:

我的难题是如何让他们进来,又让他们出去。

对于未对齐的 128 位加载,使用:

  • movups xmm0, [v0]floatdouble数据移动未对齐的单精度浮点数。 (movupd 长 1 个字节,但不会造成性能差异。)
  • movdqu xmm0, [v0]: 移动未对齐的双四字

即使两个四字跨高速缓存行边界拆分,这通常也是吞吐量的最佳选择。 (在 AMD CPU 上,当负载不适合缓存行的对齐 32 字节块时,可能会受到惩罚,而不仅仅是 64 字节缓存行边界。但在 Intel 上,64 字节内存中的任何未对齐缓存行是免费的。)

如果您的负载正在提供整数 SIMD 指令,您可能需要 movdqu,即使 movups 在机器代码中短了 1 个字节。一些 CPU 可能关心不同类型负载的“域交叉”。对于存储并不重要,许多编译器总是使用 movups 甚至整数数据。


另请参阅 以了解有关未对齐负载成本的更多信息。 (SIMD 和其他)。

如果不是连续的,你最好的选择是

  • movq xmm0, [v0]: 移动四字
  • movhps xmm0, [v1]移动高压缩单精度浮点数。 (没有整数等价物,无论如何都要使用它。永远不要使用 movhpd,它不再有任何好处,因为没有 CPU 关心双精度与浮点数随机播放。)

或者在旧的 x86 上,比如 Core2 和其他旧的 CPU,即使 16 个字节都来自同一个缓存行,movups 仍然很慢,你可以使用

  • movq xmm0, [v0]: 移动四字
  • movhps xmm0, [v0+8]: 移动高压缩单精度浮点数

movhpsSSE4.1 pinsrq xmm0, [v1], 1 稍有效率(2 微指令,不能在 Intel Sandybridge 系列上进行微熔断:1 微指令用于负载端口,1 微指令用于端口 5)。 movhps 是 1 个微融合 uop,但仍需要相同的后端端口:load + shuffle。

参见 Agner Fog 的 x86 优化指南;他有一个关于 SIMD 的章节,其中很大一部分是关于数据移动的。 https://agner.org/optimize/ And see other links in https://whosebug.com/tags/x86/info.


要取回数据,movups 可以用作存储,movlps/movhps 也可以将 qword 分散成两半。 (但不要使用 movlps 作为负载 - 它合并创建一个错误的依赖关系与 movqmovsd。)

movlpsmovq少了1个字节,但都可以将一个xmm寄存器的低64位存入内存。编译器通常会忽略商店的域交叉(vec-int 与 vec-fp),因此您也应该:通常使用 SSE1 ...ps 指令,当它们与商店完全相同时。 (不适用于 reg-reg 移动;Nehalem 可以在 movaps 整数 SIMD 之间放慢速度,如 paddd,反之亦然。)

在所有情况下 AFAIK,除了实际的加/乘指令之外,没有 CPU 关心 floatdouble,没有 CPU 具有单独的 floatdouble绕过转发域。 ISA 设计保留了该选项,但在实践中,通过使用 movupsmovaps 复制 double 向量来节省字节永远不会受到惩罚。或者使用 movlps 而不是 movlpddouble 混洗有时很有用,因为 unpcklpd 类似于 punpcklqdq(交错 64 位元素)而 unpcklps 类似于 punpckldq(交错 32 位元素) ).