我有一个汇编程序,该程序在内存中的数据结构上工作,该结构由3个浮点数(3 * 32位)的元组组成。我想知道是否可以使用xmm寄存器优化数据复制。 从内存中读取值不会有太大问题,因为我可以以4 * 32bit的速度加载,但是有什么办法可以将xmm寄存器的仅一部分写回到内存中呢? 我在ISA文档中发现的唯一一件事是,您可以使用写掩码,但没有有关执行此操作的说明。
答案 0 :(得分:2)
只有AVX512具有vmovups [rdi]{k1}, xmm0
之类的一般屏蔽存储。
AVX1具有vmaskmovps
,其工作方式基本相同,但带有矢量控制掩码。 (例如pcmpeqd xmm1,xmm1
/ psrldq xmm1, 4
)。但这要花费几倍。如果目标扩展到另一个页面,它会进行错误抑制,但是如果它实际上会发生错误,则它的效率可能很低。如果16字节的目标不跨越页面边界,甚至不跨越缓存行边界,也很好。 (这可能会导致虚假的高速缓存未命中,或者不得不按高速缓存行拆分重播存储uop,即使只是被遮罩的部分接触了另一个高速缓存行。我忘记了并且最近没有检查过。)
您不希望SSE2 maskmovdqu
;具有NT存储语义,因此写入后将其从缓存中逐出。
如果您不知道源对象在页面末尾的位置,则通常可以在没有屏蔽的加载/存储的情况下安全地加载额外的数据。
您可以存储到目的地的尽头而无需采取任何重要措施的可能性要小得多。 (除非您用一个虚拟元素填充您的结构以允许此操作,否则它将存储在数组中并且无论如何您将要存储下一个元素。)
您可以使用2个存储区来写入12个字节,一个8字节和一个4字节。 (或者,两个重叠的8字节存储区如果更容易洗牌)。
;; SSE2
movups xmm0, [rsi] ; loads 4 bytes past the end of your object
movsd [rdi], xmm0 ; 8 byte store of the low 2 elements
unpckhpd xmm0, xmm0 ; extract the high half
movss [rdi+8], xmm0
如果要连续存储到一个结构数组中,则只需执行一个16字节的存储并将其与下一个16字节的存储重叠。只需注意最后一个元素:剥离最后的迭代即可。
或者通过SSE4.1 unpckhpd / movss可以成为
extractps [rdi+8], xmm0, 2
({extractps
has a r/m32 destination:您不能将其用于将标量浮点数提取到另一个XMM寄存器,但这对于将FP存储到内存很有用。)
如果您的代码曾经复制过副本,则您可能还希望分别进行两次加载,因此存储转发将起作用。
您甚至可以将RAX和EDX等GP整数寄存器用于8 + 4字节的加载/存储。 (在重叠或4k别名的情况下,最好先执行两个加载,然后再执行两个存储,因此CPU不必弄清楚第二个加载不会与第一个存储重叠。)