MMX指令集
這篇來介紹intel cpu的高級特性,SIMD-單指令多數(shù)據(jù),從名字來看,就是執(zhí)行一條指令可以計算多個數(shù)據(jù)。先從最簡單的mmx指令集來看,在寄存器那篇已經(jīng)提 到,mmx有 mm0-mm7 共8個64位寄存器,但是寄存器并非獨立寄存器,而是復用了上篇說到的fpu數(shù)據(jù)堆棧寄存器,也就是說使用mmx指令集會破壞fpu的計算,如果同時使用 著兩種特性,一定要注意這點,避免出現(xiàn)莫名的錯誤。
首先mmx指令集需要cpu的支持,但不是所有cpu都支持,不然也不會稱之為高級特性 了,所以在使用之前需要檢測,檢測指令為cpuid,獲得cpu的特性,cpuid雖然只有一條指令,但是其隱含的內(nèi)容太多,這里僅僅介紹檢測SIMD指 令集所需要的部分,其他一些信息可參閱Intel 手冊獲得。
當eax為1時,cpuid指令返回cpu簽名信息,放入ecx和edx寄存器中,相應(yīng)位為1表示支持。檢測SIMD指令集的結(jié)果如下:
| EDX | 23 | 支持MMX | 
| EDX | 25 | 支持SSE | 
| EDX | 26 | 支持SSE2 | 
| ECX | 0 | 支持SSE3 | 
具體檢測代碼如下(AT&T 語法):
.section .datammxstring: .asciz "支持mmx指令集\n"ssestring: .asciz "支持sse指令集\n"sse2string: .asciz "支持sse2指令集\n"sse3string: .asciz "支持sse3指令集\n".section .text .globl _main _main:movl $1, %eaxcpuidmmxop:test $0x800000, %edxjz sseoppushl $mmxstringcall _printfsseop:test $0x2000000, %edxjz sse2oppushl $ssestringcall _printfsse2op:test $0x4000000, %edxjz sse3oppushl $sse2stringcall _printfsse3op:test $0x01, %ecxjz endpushl $sse3stringcall _printf end:pushl $0call _exit下面正式開始mmx指令集的介紹,使用mmx需要三個步驟:
- 從整數(shù)值創(chuàng)建打包整數(shù),載入mmx寄存器
- 使用mmx指令集計算
- 從mmx獲得結(jié)果,存入內(nèi)存
第一個和最后一個步驟比較簡單,僅僅是數(shù)據(jù)移動而已,這里提到打包,因為這里要單指令多數(shù)據(jù),所以需要把多數(shù)據(jù)合成一個操作數(shù)進行計算,存入64位的mmx寄存器中,打包的過程就是把 8個字節(jié)/4個字/2個雙字 合成一個64位數(shù)據(jù)。
從加減法說起,對于普通數(shù)據(jù),如果數(shù)據(jù)溢出可以置標記位,但是對于多數(shù)據(jù)的運算,由于同時計算多個加法,就不能單純的設(shè)置標志,對mmx計算有幾種情況:
環(huán)繞運算 截斷其值,丟棄進位 帶符號飽和 最大/最小 帶符號值 無符號飽和 最大/最小 無符號值其中飽和運算的預設(shè)值根據(jù)結(jié)果的位數(shù)決定,有符號8位最大為127,如果超過127,結(jié)果按127計算,其他情況與此類似,這里方便與一些圖形處理,比如色彩黑色為0,為無符號最小值,小于其值也按黑色處理。
好 了,到此可以看一下具體的指令,這里的指令有相同的格式,instruction source, destination;其中source可以是mmx寄存器或者64位內(nèi)存,destination為mmx寄存器。這是AT&T語法,對于 MASM語法源目的操作數(shù)相反。
| paddb | 環(huán)繞打包字節(jié)整數(shù)加法 | 
| paddw | 環(huán)繞打包字整數(shù)加法 | 
| paddd | 環(huán)繞打包雙字整數(shù)加法 | 
| paddsb | 帶符號飽和打包字節(jié)整數(shù)加法 | 
| paddsw | 帶符號飽和打包字整數(shù)加法 | 
| paddusb | 無符號飽和打包字節(jié)整數(shù)加法 | 
| paddusw | 無符號飽和打包字整數(shù)加法 | 
| psubb | 環(huán)繞打包字節(jié)整數(shù)減法 | 
| psubw | 環(huán)繞打包字整數(shù)減法 | 
| psubd | 環(huán)繞打包雙字整數(shù)減法 | 
| psubsb | 帶符號飽和打包字節(jié)整數(shù)減法 | 
| psubsw | 帶符號飽和打包字整數(shù)減法 | 
| psubusb | 無符號飽和打包字節(jié)整數(shù)減法 | 
| psubusw | 無符號飽和打包字整數(shù)減法 | 
下面以AT&T加法為例進行說明,這里以飽和方式計算4個無符號字之和:
# add four word # output : result is 18932, 7631, 65535, 510 .section .datavalue1: .short 12300, 2384, 60000, 456value2: .short 6632, 5247, 40000, 54outstring: .asciz "result is %u, %u, %u, %u\n" .section .text .globl _main _main:movq value1, %mm0movq value2, %mm1paddusw %mm1, %mm0movq %mm0, value1movl $value1, %ebxxorl %eax, %eaxmovw 6(%ebx), %axpushl %eaxmovw 4(%ebx), %axpushl %eaxmovw 2(%ebx), %axpushl %eaxmovw (%ebx), %axpushl %eaxpushl $outstringcall _printfpushl $0call _exitmovq 指令把內(nèi)存中的數(shù)據(jù)傳送至mmx寄存器,如果數(shù)據(jù)之前在內(nèi)存中不是連續(xù)的,則需要集中存放,即進行打包,之后使用paddusw進行加法計算,輸出時 word需轉(zhuǎn)化成dword放入堆棧,可以看到以飽和方式第三個結(jié)果為65535,即16位無符號數(shù)的最大值。從這里例子可以看出,通過一條指令計算了四 個word整數(shù)相加,很大程度上提高了計算的效率,但是同時需要注意,整數(shù)的打包以及傳送過程也需要耗時,如果打包操作很多,結(jié)果不是提高效率而是降低效 率了。
mmx指令集的加法根據(jù)需要有飽和方式和環(huán)繞方式計算,但對于乘法而言,由于結(jié)果的寬度可能是操作數(shù)的兩倍,所以兩種方式看上去都不合適,所以intel提供了兩個指令,一個得到計算結(jié)果的低字節(jié),另一個得到計算結(jié)果的高字節(jié)。
| pmulluw | 對無符號16位整數(shù)相乘取結(jié)果低16位 | 
| pmulhuw | 對無符號16位整數(shù)相乘取結(jié)果高16位 | 
| pmullw | 對有符號16位整數(shù)相乘取結(jié)果低16位 | 
| pmulhw | 對有符號16位整數(shù)相乘取結(jié)果高16位 | 
| pmaddwd | 對4個帶符號整數(shù)相乘,高位兩個結(jié)果相加存入高32位,低位相同 | 
mmx指令集還提供對四字值進行布爾邏輯操作和移位指令:
| pand | 對源和目標操作數(shù)按位與操作 | 
| pandn | 對目標操作數(shù)進行按位邏輯非操作,然后對源和目標操作數(shù)按位與操作 | 
| por | 對源和目標操作數(shù)按位或操作 | 
| pxor | 對源和目標操作數(shù)按位異或操作 | 
| psll | 對目標操作數(shù)執(zhí)行邏輯左移操作,使用0填充空位 | 
| psra | 對目標操作數(shù)執(zhí)行邏輯右移操作,使用0填充空位 | 
其AT&T指令格式如下:
pand source, destination其中source是mmx寄存器或者64位內(nèi)存,destination必須是mmx寄存器。移位指令可以使用字,雙字或者四字操作數(shù),還有移位的位置數(shù)量。MASM格式的源目的操作數(shù)相反。
mmx構(gòu)架提供了用于比較兩個值的指令:
| pcmpeqb | 比較打包字節(jié)整數(shù)值的相等性 | 
| pcmpeqw | 比較打包字整數(shù)值的相等性 | 
| pcmpeqd | 比較打包雙字整數(shù)值的相等性 | 
| pcmpgtb | 判斷打包字節(jié)整數(shù)值是否大于另一個 | 
| pcmpgtw | 判斷打包字整數(shù)值是否大于另一個 | 
| pcmpgtd | 判斷打包雙字整數(shù)值是否大于另一個 | 
因為mmx同時比較多個數(shù)據(jù),所以不能設(shè)置標志,替換的做法是把判斷結(jié)果放到目標打包整數(shù)值中,如果打包整數(shù)值滿足對比提交,就把結(jié)果設(shè)置為全1,否則設(shè)置為全0。
由于mmx指令集并非所有cpu都可以支持,所以對c語言這種編譯通用性的程序而言,是不會貿(mào)然使用mmx指令集的,這也對我們手工匯編優(yōu)化程序提供了很大的空間,但是需要注意打包整數(shù)的效率損耗。
另外,intel除了mmx指令集,另有SIMD指令如sse指令集,將會再下篇詳細說明。
轉(zhuǎn)載:http://fancymore.com/reading/assembler-mmx-instruct.html
轉(zhuǎn)載于:https://www.cnblogs.com/DeeLMind/p/7367775.html
總結(jié)
 
                            
                        - 上一篇: Intel汇编-传送MMX整数
- 下一篇: MMX 指令
