跳转到内容

x86 汇编/MMX

来自维基教科书,开放的书籍,为开放的世界

MMX 是英特尔于 1996 年推出的补充指令集。大多数新指令都是“单指令,多数据”(SIMD),这意味着单个指令可以并行处理多个数据。

然而,MMX 存在一些问题:指令执行速度略低于常规算术指令,使用 MMX 寄存器时无法使用浮点单元 (FPU),并且 MMX 寄存器使用饱和算术。

饱和算术

[编辑 | 编辑源代码]

在 8 位灰度图像中,255 是纯白色的值,0 是纯黑色的值。在常规寄存器 (AX、BX、CX ...) 中,如果我们将白色加 1,我们得到黑色!这是因为常规寄存器“回绕”到下一个值。MMX 寄存器通过一种称为“饱和算术”的技术来解决这个问题。在饱和算术中,寄存器的值永远不会再次回绕到 0。这意味着在 MMX 世界中,我们有以下等式

255 + 100 = 255
200 + 100 = 255
0 - 100 = 0;
99 - 100 = 0;

对于习惯于寄存器回绕的人来说,这可能在开始时看起来违反直觉,但在某些情况下是有意义的:如果我们试图使白色更亮,它不应该变成黑色。

单指令多数据 (SIMD) 指令

[编辑 | 编辑源代码]

MMX 寄存器宽 64 位,但可以分解如下

2 32 bit values
4 16 bit values
8 8 bit values

MMX 寄存器不能轻松地用于 64 位算术。假设我们在 MMX 寄存器中加载了 4 个字节:10、25、128、255。我们将它们排列如下

MM0: | 10 | 25 | 128 | 255 |

我们执行以下伪代码操作

MM0 + 10

我们会得到以下结果

MM0: | 10+10 | 25+10 | 128+10 | 255+10 | = | 20 | 35 | 138 | 255 |

请记住,我们的算术在最后一个框中“饱和”,因此值不会超过 255。

使用 MMX,我们实质上是在使用常规寄存器执行 1 次加法所需的时间内执行了 4 次加法,使用了少 4 倍的指令。

MMX 寄存器

[编辑 | 编辑源代码]

有 8 个 64 位 MMX 寄存器。为了避免添加新的寄存器,它们被设置为与 FPU 堆栈寄存器重叠。这意味着MMX 指令和 FPU 指令不能同时使用。MMX 寄存器直接寻址,不需要像 FPU 寄存器那样通过入栈和出栈来访问。

MM7 MM6 MM5 MM4 MM3 MM2 MM1 MM0

这些寄存器对应于 FPU 堆栈上相同编号的 FPU 寄存器。

通常,当您在代码中启动包含 MMX 指令的汇编块时,CPU 会自动禁止浮点指令。要重新允许 FPU 操作,您必须使用 emms 结束所有 MMX 代码。

以下是用 GNU AS 和 GCC 编写的程序,它将 8 个字节从一个变量复制到另一个变量,并打印结果。

汇编部分

.globl copy_memory8
.type  copy_memory8, @function
copy_memory8:
    pushl %ebp
    mov  %esp, %ebp
    mov 8(%ebp), %eax
    movq (%eax), %mm0
    mov 12(%ebp), %eax
    movq %mm0, (%eax)
    popl %ebp
    emms
    ret
.size copy_memory8,.-copy_memory8

C 部分

#include <stdio.h>

void copy_memory8(void * a, void * b);

int main () {
	long long b = 0x0fffffff00000000;
	long long c = 0x00000000ffffffff;
	printf("%lld == %lld\n", b, c);
	copy_memory8(&b, &c);
	printf("%lld == %lld\n", b, c);
	return 0;
}

MMX 指令集

[编辑 | 编辑源代码]

使用几个后缀来指示指令操作的数据大小

  • Byte(8 位)
  • Word(16 位)
  • Double word(32 位)
  • Quad word(64 位)

操作的有符号性也由后缀表示:US 表示无符号,S 表示有符号。

例如,PSUBUSB 减去无符号字节,而 PSUBSD 减去有符号双字。

MMX 定义了超过 40 个新的指令,列在下面。

EMMS、MOVD、MOVQ、PACKSSDW、PACKSSWB、PACKUSWB、PADDB、PADDD、PADDSB、PADDSW、PADDUSB、PADDUSW、PADDW、PAND、PANDN、PCMPEQB、PCMPEQD、PCMPEQW、PCMPGTB、PCMPGTD、PCMPGTW、PMADDWD、PMULHW、PMULLW、POR、PSLLD、PSLLQ、PSLLW、PSRAD、PSRAW、PSRLD、PSRLQ、PSRLW、PSUBB、PSUBD、PSUBSB、PSUBSW、PSUBUSB、PSUBUSW、PSUBW、PUNPCKHBW、PUNPCKHDQ、PUNPCKHWD、PUNPCKLBW、PUNPCKLDQ、PUNPCKLWD、PXOR

华夏公益教科书