90年代MMX:Intel Pentium的SIMD初体验

SIMD in the 90s: Programming Intel's Pentium MMX

90年代MMX:Intel Pentium的SIMD初体验

如果你曾在90年代末编写PC程序,一定记得'Intel Inside Pentium with MMX'的贴纸。MMX不仅是营销热词,更是Intel将SIMD(单指令多数据)指令引入主流桌面CPU的重要尝试。文章回顾了1997年Pentium MMX的诞生,解释了它如何通过复用x87浮点寄存器实现64位整数并行处理,以及它在图像处理、音频混合等场景中的实际应用。虽然SIMD并非Intel首创,但MMX让普通开发者首次接触到这种技术,成为从高性能计算走向桌面软件的关键一步。

MMX并不是SIMD的发明者,但它让SIMD从专业领域走向了普通桌面软件开发。
  1. theandrewbailey

    每个 MMX 寄存器宽 64 位。在内部,MMX 寄存器实际上是 x87 浮点寄存器的别名。

    由于首批 Pentium 3 处理器(Katmai)的构建方式,它们同样将 x87(从而也包括 MMX)寄存器别名化为 XMM SSE 寄存器,但这对程序是隐藏的。直到至少 Coppermine 版本,它们才再次成为独立的寄存器。

  2. gustavopezzi

    我要补充的是,SSE1 和 SSE2 现在是 AMD64 指令集的必要组成部分。所有 64 位 PC 处理器都必须支持这两者。正因如此,现代编译器在构建 64 位二进制文件时会忽略 x87 FPU。取而代之的是,它们将所有 float 和 double 运算分别编译为 SSE1 和 SSE2 指令。

  3. Const-me

    我在 2000 年代对音频和视频编解码器进行了大量的 MMX 和 SSE2 优化。MMX 带来了巨大提升,但也让人头疼。

    MMX 优化几乎必须使用汇编语言。Pentium MMX 是一款顺序执行的双流水线 CPU,虽然编译器支持 MMX 内联函数,但其代码生成质量极差。例如,Visual C++ 6 生成的代码中,三分之二都是寄存器到寄存器的移动操作,数值在每次 ALU 运算之间被不必要地在两个寄存器间来回搬运。SSE/SSE2 内联函数也存在同样的问题。我遇到的最糟糕案例是 _mm_set_epi8() 内联函数,它用于从 16 个输入构建一个 128 位向量。当所有输入都是常量时,它本应生成一条单一的 128 位常量加载指令;然而,Visual Studio 2008 却生成了约 80 条指令,通过字节加载来计算它。微软直到 VS2010 才修复这个问题。

    MMX 指令的延迟结合顺序执行的双流水线架构,也让汇编循环变得混乱。简单操作是单周期的,但乘法有 3 个周期的延迟,存储操作需要数据提前一个周期就绪,计算好的加载/存储地址也需要提前一个周期。仅仅并行运行 2-4 次迭代并不是选项,因为只有 8 个向量寄存器,而且你仍然会在功能单元上遇到瓶颈。因此,要获得峰值性能,通常需要将循环迭代交错执行,并在循环周围编写特殊的入口和出口代码。

    EMMS 的问题被低估了。当 CPU 切换 t […]

同日更多故事

2026-08-16