我有两个UInt64(即64位四字)整数。
sizeof(UInt64)
)边界对齐(如果有任何用处,我也可以将它们对齐16字节) 如何将它们加载到xmm寄存器中,例如xmm0
:
我发现:
movq xmm0, v[0]
但这只会移动 v[0]
,并将xmm0
中的高64位设置为零:
xmm0
0000000000000000 24FC18D93B2C9D8F
正如W. Chang所指出的那样,字节序化很少,我也可以采用其他方式:
我的难题是如何把它们拿出来,并把它们拿出来。
答案 0 :(得分:4)
对于未对齐的128位负载,请使用:
movups xmm0, [v0]
:为float
或double
数据移动未对齐的单精度浮点数。 ({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
用作负载,它会与movq
或movsd
合并而产生虚假的依赖关系。)
movlps
比movq
小1个字节,但是两者都可以将xmm寄存器的低64位存储到内存中。编译器通常会忽略商店的跨域(vec-int与vec-fp),因此当它们完全等效时,您应该使用并使用SSE1 ...ps
指令。
在所有情况下,FAIFK都不关心float
与double
的CPU,除了实际的加/乘指令外,没有其他处理器关心float
和{{1 }}旁路转发域。 ISA设计使该选项保持打开状态,但实际上,通过使用double
或movups
在movaps
的向量周围进行复制来保存字节永远不会受到任何惩罚。或使用double
代替movlps
。 movlpd
随机播放有时很有用,因为double
就像unpcklpd
(交错64位元素),而punpcklqdq
就像unpcklps
(交错32位元素)。