MMX寄存器是否总是存在于现代处理器中?



当我查看最近的处理器的图表和概述[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 cpu也有MMX(但没有SSE)。


当你有16个XMM regs + 16个64位GP regs时,MMX是非常罕见的值得使用的。Store/reload并不可怕,特别是当重新加载可以使用内存源操作数时。

与store/reload相比,将数据从MMX regs移动到/从MMX regs移动的额外ALU通常是不值得的。重载通常可以微融合为内存源操作数,而ALU执行端口压力很容易成为问题。

如果你正在做一些特殊的禁用缓存的事情,那么当然,但通常情况下,如果你能让它远离关键路径,存储转发会使存储/重载变得高效。(它确实有~5个周期的延迟)。

如果您确实希望在XMM和GP regs之间移动数据,那么通常movd/movqpinsrd/pextrd是一个不错的选择,而不是存储/重新加载。我是说,在外部循环中溢出/重新加载GP或XMM reg通常比2x movq或movq2dq xmm0, mm0要好。

事实上,在Skylake上,一个movq2dq需要2个up。movdq2q相同。(movq到/从GP regs传输仍然只有1个上限,尽管在XMM和GP regs之间传输具有相同的端口0或端口5限制)。


另外,在函数中使用MMX需要在它的末尾(或者在任何函数调用之前,如果您想要符合ABI的话)使用emms指令。MMX regs在正常的调用约定中都是被调用的(实际上FPU必须处于x87状态而不是MMX状态)。


在现代cpu上,MMX的效率肯定不如XMM。实际上,用于存储之外的任何东西通常比SSE2更糟糕(如果您想在64位块中工作,则使用movq加载/存储并忽略XMM regs的高字节)。

例如,在movaps xmm,xmm的移动消除的Intel/AMD cpu上,movq xmm1, xmm0的MMX寄存器复制仍然需要一个ALU up,并且仍然有1个周期的延迟。(这两款产品的前端成本仍然很高;move -elimination只删除延迟和后端开销,而不删除ROB条目。

同时,Skylake对于某些指令的XMM版本比MMX版本有更好的吞吐量。例如,paddb/w/d/q mm,mm运行在p05上,但paddb/w/d/q xmm,xmm运行在p015上。许多其他操作,如pavg*pmadd*和shift,对于XMM regs可以在p01上运行,但是对于MMX regs只能在端口0上运行。(https://agner.org/optimize/)

所以像x87 FPU一样,它仍然支持遗留代码,但是支持它的执行单元更少。这还不是很糟糕,所以像x264和FFmpeg这样的软件仍然有大量的MMX代码,这些代码在64位块中自然工作,但不会受到太大的影响。

在许多情况下,

128位AVX版本的整数指令可能是避免寄存器复制mov指令的最佳选择。

最好的"图表和概述"总是手册,在这种情况下,您将从英特尔手册的第5.4节开始找到大量关于MMX技术和SSE(流SIMD扩展)的信息,这是4卷集pdf中的122页。要深入了解使用MMX编程,您需要从第9.2节开始。就我个人而言,我真的很喜欢英特尔的"Linux c++编译器*内在参考",它可以让你了解更多关于MMX的知识。这里有一个副本:https://www.cs.fsu.edu/~engelen/courses/HPC-adv/intref_cls.pdf

可以依赖于它们存在于所有支持SSE的处理器中吗?

是的。SSE表示MMX存在。正如在评论中所提到的,您将需要使用CPUID的内在特性来检查:

CPUID.01H:EDX.MMX[bit 23] = 1

或者只要记住MMX技术是在1997年出现的,我看到这个问题是2013年发布的,编辑于2014年,所以…

它们是否与更旧的FPU堆栈冲突?

没有,但这很奇怪,不是吗?MMX状态与x87 FPU状态关联。这样做的原因是为了避免与现有操作系统中的上下文切换机制的兼容性问题。它们对FPU寄存器来说是唯一的,因为它们是直接可寻址的,所以也许这就是你被它们吸引的原因。另外,它们被设计用于打包数据类型!然而,这种映射使得在同一个应用程序中处理浮点数和SIMD数据变得困难。

它们与一般64位的物理寄存器相同吗?

这个问题有点令人困惑。你说的通用64位是指x64计算机中的16个通用寄存器,对吧?或者像堆栈一样操作的8个80位FPU数据寄存器?无论哪种方式,MMX寄存器都不与x87 FPU数据寄存器堆栈分开。英特尔手册似乎接受了这些MMX寄存器的误导性,它说:

尽管在IA-32体系结构中,MMX寄存器被定义为单独的寄存器,但它们与寄存器存在别名在FPU数据寄存器栈(R0到R7)
-Section 9.2.2, p.229

有8个MMX寄存器(64位)。但是正如你所看到的,有很多寄存器供你使用!令人困惑的是,保存和恢复x87状态的指令也处理MMX状态。

当MMX指令(而不是EMMS指令)被执行时,处理器会改变x87 FPU的状态如下:

•x87 FPU状态字TOS (top of stack)值设置为0。

•整个x87 FPU标签字设置为有效状态(所有标签字段为00B)。

•当MMX指令写入MMX寄存器时,它将1 (11B)写入相应的指数部分浮点寄存器(64位到79位)。 -第9.6.2节,p.235英特尔手册。

也许值得注意的是,当任何东西加载到这些x87数据寄存器中时,它们会自动转换为双扩展精度浮点格式(第194页)英特尔手动)。只要知道当转换到MMX模式时,所有未使用的fpu位都被设置为无效值,因此可能导致浮点指令行为奇怪。

通常不编写MMX支持-我会检查SSE支持,因为如果有SSE支持,则自动意味着支持MMX。

最新更新