5

当我查看最新处理器的图表和概述时[1],我从未看到提到 MMX 寄存器 MM0 - MM7。但从规格来看,它们似乎仍然存在。是否可以依赖它们出现在所有支持 SSE 的处理器中?它们是否与更旧的 FPU 堆栈以外的任何东西发生冲突?它们是否与一般 64 位的物理寄存器相同?

虽然 XMM 和 YMM 对于向量来说要好得多,但我偶尔想使用 MMX 寄存器来存储值,否则这些值会溢出到堆栈中。Speedwise 这看起来好一点,而且有时我想避免额外的存储和加载。

[1] http://www.realworldtech.com/haswell-cpu/

4

3 回答 3

7

SSE1 意味着 MMX,所以支持 x86-64 可以保证 MMX(因为 SSE2 是 x86-64 的基线)。

它们是 80 位 x87 regs 的别名,而不是通用整数寄存器!长模式不会改变 MMX 的工作方式。

所有现代 CPU 都支持 64 位,因此在所有模式下都可以使用 MMX。即使只有 32 位嵌入式AMD Geode CPU也有 MMX(但没有 SSE)。


当您拥有 16x XMM regs + 16x 64-bit GP regs 时,MMX 很少值得使用。 存储/重新加载并不可怕,特别是如果重新加载可以使用内存源操作数。

与存储/重新加载相比,将数据移入/移出 MMX regs 的额外 ALU 微指令通常不值得。重载通常可以作为内存源操作数进行微融合,ALU 执行端口压力很容易成为问题。

如果您在禁用缓存的情况下做一些特殊的事情,那么可以肯定,但是如果您可以将其保持在关键路径之外,通常存储转发会使存储/重新加载变得高效。(它确实有约 5 个周期的延迟)。

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

事实上,在 Skylake 上,一个movq2dq成本为 2 微秒。 对于movdq2q. (movq不过,到/从 GP regs 仍然只有 1 uop,与 XMM 和 GP regs 之间的传输具有相同的端口 0 或端口 5 限制)。


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


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

例如,在具有 mov-elimination for 的 Intel/AMD CPU 上movaps xmm,xmm,MMX 寄存器复制movq xmm1, xmm0仍然需要一个 ALU uop,并且仍然有 1 个延迟周期。(两者的前端仍然需要 uop;mov 消除仅消除了延迟和后端成本,而不是 ROB 条目。)

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

因此,与 x87 FPU 一样,遗留代码仍然支持它,但支持它的执行单元较少。这还不算太糟糕,所以像 x264 和 FFmpeg 这样的软件仍然有大量的 MMX 代码,用于在 64 位块中自然工作的东西并不会受到太大影响。

在许多情况下,128 位 AVX 版本的整数指令可能是避免寄存器复制mov指令的最佳选择。

于 2019-07-11T23:29:40.880 回答
1

要查看的最佳“图表和概述”始终是手册,在这种情况下,您会从英特尔手册的第 5.4 节开始,即第 pg.4 页,找到有关 MMX 技术和正在进行的 SSE(流式 SIMD 扩展)的大量信息。122 在 4 卷集的 pdf 中。要更深入地使用 MMX 进行编程,您需要从第 9.2 节(第 228 页)开始。就我个人而言,我非常喜欢英特尔的“C++ Compiler for Linux* Intrinsics Reference”,以了解您可能需要了解的有关 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 状态更改如下:

• x87 FPU 状态字的 TOS(栈顶)值设置为 0。

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

• 当 MMX 指令写入 MMX 寄存器时,它会将 1 (11B) 写入相应浮点寄存器(位 64 到 79)的指数部分。

- 第 9.6.2 节,第 235 页英特尔手册。

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

于 2019-07-11T13:51:38.667 回答
0

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

于 2013-11-30T21:25:02.120 回答