当我查看最近处理器的图表和概述[1]时,我从未看到MMX寄存器MM0-MM7的提及。但从规格来看,它们似乎仍然存在。可以依赖它们存在于支持SSE的所有处理器中吗?除了更老的FPU堆栈之外,它们是否会发生冲突?它们与一般的64位物理寄存器相同吗?
虽然XMM和YMM对于向量要好得多,但我偶尔也想使用MMX寄存器来存储否则会溢出到堆栈的值。 Speedwise看起来好一点,而且有时我想避免额外的存储和负载。
答案 0 :(得分:3)
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操作通常不值得。重新加载通常可以微融合为存储源操作数,而ALU执行端口压力很容易成为问题。
如果您在禁用高速缓存的情况下进行了特殊的操作,那么可以肯定,但是通常情况下,存储转发可以使存储/重新加载有效,如果您可以使其脱离关键路径。 (它确实有约5个周期的延迟)。
但是,如果您想在XMM和GP regs之间移动数据,通常movd
/ movq
或pinsrd
/ pextrd
是一个不错的选择,而不是存储/重新加载。我是说,外循环中GP或XMM reg的溢出/重装通常比2x movq或movq2dq xmm0, mm0
好。
实际上,在Skylake上,一个movq2dq
的价格为2微克。与movdq2q
相同。 ({/ movq
到GP reg的进出仍然是1 uop,但端口0或端口5的限制与XMM和GP regs之间的传输相同)。
此外,在函数中使用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*
和shift)可以在p01上运行,而对于MMX reg,只能在端口0上运行。 (https://agner.org/optimize/)
与x87 FPU一样,旧代码仍支持它,但是支持它的执行单元较少。它还不算太糟,因此像x264和FFmpeg这样的软件仍然具有大量的MMX代码,这些代码可以自然地在64位块中工作,而不会遭受太大的损失。
在许多情况下,避免寄存器复制mov
指令是128位AVX版本的整数指令的最佳选择。
答案 1 :(得分:1)
最好的“图表和概述”始终是手册,在这种情况下,您会发现许多有关MMX技术的信息以及从英特尔手册5.4节开始的后续SSE(流式SIMD扩展),即pg。 4卷集pdf中的122。为了更深入地使用MMX进行编程,您需要从9.2节(p.228)开始。就我个人而言,我真的很喜欢英特尔的《 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个通用寄存器,对不对?还是八个像堆栈一样工作的80位FPU数据寄存器?无论哪种方式,MMX寄存器都不与x87 FPU数据寄存器堆栈分开。英特尔手册似乎通过说:
来拥抱这些MMX寄存器的误导性。
尽管MMX寄存器在IA-32体系结构中定义为单独的寄存器,但它们是这些寄存器的别名 在FPU数据寄存器堆栈中(R0至R7)-第9.2.2节,第229
有8个MMX寄存器(64位)。但是正如您所知,有很多寄存器供您使用!令人困惑的是,保存和恢复x87状态的指令还处理MMX状态。
当执行MMX指令(不是EMMS指令)时,处理器将更改x87 FPU状态 如下:-第9.6.2节,第235页,英特尔手册。
•x87 FPU状态字的TOS(堆栈顶部)值设置为0。
•整个x87 FPU标记字都设置为有效状态(所有标记字段均为00B)。
•当MMX指令写入MMX寄存器时,它会将1(11B)写入相应的指数部分 浮点寄存器(位64至79)。
也许值得注意的是,当将任何内容加载到这些x87数据寄存器中时,它们会自动转换为双精度扩展浮点格式(第194页英特尔手册)。只是知道当转换为MMX模式时,所有未使用的fpu位都设置为无效值,因此可能导致浮点指令的行为异常。
答案 2 :(得分:0)
通常不会写MMX支持 - 我会检查SSE支持,因为如果支持SSE则自动意味着支持MMX。