如何将两个打包的64位Quadwords加载到128位Xmm寄存器中

时间:2018-11-26 23:01:25

标签: assembly x86 language-agnostic sse2

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

  • 它们与8字节(sizeof(UInt64))边界对齐(如果有任何用处,我也可以将它们对齐16字节)
  • 它们包装在一起,因此它们在内存中并排

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

enter image description here


我发现:

movq xmm0, v[0]

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

  

xmm0 0000000000000000 24FC18D93B2C9D8F

奖金问题

  • 如何退回他们?
  • 如果它们不在内存中并排怎么办?
  • 如果它们对齐4字节怎么办?

编辑

正如W. Chang所指出的那样,字节序化很少,我也可以采用其他方式:

enter image description here

我的难题是如何把它们拿出来,并把它们拿出来。

1 个答案:

答案 0 :(得分:4)

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

  • movups xmm0, [v0]floatdouble数据移动未对齐的单精度浮点数。 ({movupd长1个字节,但从不影响性能。)
  • movdqu xmm0, [v0]移动未对齐的双四边形

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

如果您的负载正在馈送整数SIMD指令,则即使movdqu在机器代码中短了1个字节,您也可能想要movups。一些CPU可能会关心不同类型的负载的“域交叉”。对于存储无关紧要,即使对于整数数据,许多编译器也始终使用movups


有关未对齐负载的成本的更多信息,另请参见How can I accurately benchmark unaligned access speed on x86_64。 (SIMD等)。

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

  • movq xmm0, [v0]移动四字词
  • movhps xmm0, [v1]移动高压缩单精度浮点数。 (没有等价的整数,无论​​如何都要使用。永远不要使用movhpd,因为没有CPU会关心double和float洗牌,所以它不再有用。)

或者在较旧的x86上(例如Core2和其他较旧的CPU上,movups仍然很慢,即使16个字节全部来自同一缓存行),您也可以使用

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

movhps的效率比SSE4.1 pinsrq xmm0, [v1], 1略高(2 uop,不能在Intel Sandybridge系列上进行微熔丝:1 uop装载端口,1 uop装载端口5)。 movhps是1个微融合的uop,但仍需要相同的后端端口:load + shuffle。

请参阅Agner Fog的x86优化指南;他有一章关于SIMD,其中有很大一部分涉及数据移动。 https://agner.org/optimize/ ,并查看https://stackoverflow.com/tags/x86/info中的其他链接。


要获取数据,movups可以用作存储,movlps / movhps可以将qword的一半散开。 (但不要将movlps用作负载,它会与movqmovsd合并而产生虚假的依赖关系。)

movlpsmovq小1个字节,但是两者都可以将xmm寄存器的低64位存储到内存中。编译器通常会忽略商店的跨域(vec-int与vec-fp),因此当它们完全等效时,您应该使用并使用SSE1 ...ps指令。

在所有情况下,FAIFK都不关心floatdouble的CPU,除了实际的加/乘指令外,没有其他处理器关心float和{{1 }}旁路转发域。 ISA设计使该选项保持打开状态,但实际上,通过使用doublemovupsmovaps的向量周围进行复制来保存字节永远不会受到任何惩罚。或使用double代替movlpsmovlpd随机播放有时很有用,因为double就像unpcklpd(交错64位元素),而punpcklqdq就像unpcklps(交错32位元素)。