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;
對於習慣於暫存器迴繞的人來說,這可能在開始時看起來違反直覺,但在某些情況下是有意義的:如果我們試圖使白色更亮,它不應該變成黑色。
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 倍的指令。
有 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;
}
使用幾個字尾來指示指令操作的資料大小
- 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