当我查看最新处理器的图表和概述[1]时,从未见过提到MMX寄存器MM0-MM7。但是从规范来看,它们似乎仍然存在。可以依靠它们出现在所有支持SSE的处理器中吗?除了甚至更老的FPU堆栈之外,它们是否与其他任何冲突?它们是否与通用64位寄存器相同?
虽然XMM和YMM对于矢量要好得多,但我偶尔还是想使用MMX寄存器来存储可能会溢出到堆栈中的值。从速度上看,这看起来要好一些,而且有时候我想避免额外的存储和装载。
[1] http://www.realworldtech.com/haswell-cpu/
最佳答案
SSE1表示MMX,因此支持x86-64可以保证MMX(因为SSE2是x86-64的基线)。
它们是80位x87寄存器的别名,而不是通用整数寄存器的别名!长模式不会改变MMX的工作方式。
所有现代CPU均具有64位功能,因此在所有模式下均具有MMX。即使只有32位嵌入式AMD Geode CPUs也具有MMX(但没有SSE)。
当您拥有16x XMM regs + 16x 64位GP regs时,MMX值得使用的情况很少。 存储/重载不是很糟糕的,特别是如果重载可以使用内存源操作数。
与存储/重新加载相比,将数据移入/移出MMX reg的额外ALU指令通常不值得。 Reload通常可以作为存储源操作数进行微融合,而ALU执行端口压力很容易成为问题。
如果您在禁用高速缓存的情况下进行了一些特殊的操作,那么可以肯定,但是通常情况下,存储转发可以使存储/重新加载有效,如果您可以使其脱离关键路径。 (它确实有约5个周期的延迟)。
但是,如果您确实想在XMM和GP regs之间移动数据,通常movd
/movq
或pinsrd
/pextrd
是一个不错的选择,而不是存储/重新加载。我说的是,外循环中GP或XMM reg的溢出/重新加载通常比2x movq或movq2dq xmm0, mm0
更好。
实际上,在Skylake上,一个movq2dq
的成本为2 uops。 与movdq2q
相同。 (尽管与XMM和GP regs之间的传输具有相同的端口0或端口5限制,往返GP regs的movq
仍然仅为1 uop)。
另外,在函数中使用MMX会在结尾处(或在任何函数调用之前,如果要符合ABI要求)在emms
指令上花钱。在正常的调用约定中,MMX regs都被调用了(实际上FPU必须处于x87状态而不是MMX状态)。
在现代CPU上,MMX绝对不如XMM高效。实际上,将其用于除存储以外的其他功能通常比SSE2差(如果要使用64位块,则使用movq
加载/存储并忽略XMM reg的高字节)。
例如,在对movaps xmm,xmm
进行了移动消除的Intel/AMD CPU上,带有movq xmm1, xmm0
的MMX寄存器复制仍然需要ALU uop,并且仍具有1个周期的延迟。 (两者仍然为前端付出了小小的努力;移动消除仅消除了ROB条目以外的等待时间和后端成本。)
同样,对于某些指令的XMM版本,Skylake具有比MMX版本更好的吞吐量。例如paddb/w/d/q mm,mm
在p05上运行,但是paddb/w/d/q xmm,xmm
在p015上运行。对于XMM reg,许多其他操作(例如pavg*
,pmadd*
和shifts)都可以在p01上运行,而对于MMX reg,只能在端口0上运行。 (https://agner.org/optimize/)
因此,像x87 FPU一样,它仍支持旧代码,但支持它的执行单元较少。它还不是很糟糕,因此像x264和FFmpeg这样的软件仍然具有大量的MMX代码,这些代码可以自然地在64位块中工作,而不会遭受太大的损失。
在许多情况下,避免寄存器复制mov
指令,最好的选择是128位AVX版本的整数指令。
关于assembly - MMX寄存器是否始终存在于现代处理器中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16981000/