MMX的数据结构 MMX指令集
源地址:http://dev.gameres.com/Program/Other/MMXData.htm
 ? ? ? ?http://www.360doc.com/content/12/1129/18/1317564_251021032.shtml
 MMX的數(shù)據(jù)結(jié)構(gòu)
 ? ? 多媒體軟件具有如下顯著的特點(diǎn):
 1、 小整型數(shù)據(jù)類(lèi)型(圖形數(shù)據(jù)為8位 ,聲頻數(shù)據(jù)為16位)
 2、 對(duì)小整型數(shù)據(jù)的頻繁且重復(fù)的計(jì)算操作(例如被頻繁調(diào)用的核心算法);
 3、 許多操作具有內(nèi)存的并行性(例如對(duì)大量的數(shù)據(jù)進(jìn)行同一個(gè)加,減或乘法運(yùn)算操作);
 ? ? MMX技術(shù)設(shè)計(jì)了一套基本的,通用的緊縮整形指令,共57條。
 所謂“緊縮整形數(shù)據(jù)”是指多個(gè)8/16/32位的整形數(shù)據(jù)組合成為一個(gè)64位的數(shù)據(jù).MMX指令主要就是使用
 這種緊縮整形數(shù)據(jù),它又分成4種整形類(lèi)型:緊縮字節(jié)、緊縮字、緊縮雙字、緊縮4字
 ? ? *緊縮字節(jié)(Packed Byte): 8個(gè)字節(jié)組合成一個(gè)64位的數(shù)據(jù);
 ? ? *緊縮字 (Packed Word): 4個(gè)字組合成一個(gè)64位的數(shù)據(jù);
 ? ? *緊縮雙字(Packed Doubleword): 2個(gè)雙字組合成一個(gè)64位的數(shù)據(jù);
 ? ? *緊縮4字 (Packed Quadword):一個(gè)64位數(shù)據(jù)
 ? ? 這樣一條MMX指令就能夠同時(shí)處理8/4/2個(gè)數(shù)據(jù)單元,這就是所謂的“單指令多數(shù)據(jù)SIMD”結(jié)構(gòu)。這種結(jié)構(gòu)
 是MMX技術(shù)把機(jī)器性能提高的最根本因素。
 ? ? 為了方便使用64位緊縮整形數(shù)據(jù),MMX技術(shù)含有8個(gè)64位的MMX寄存器(MM0-MM7),只有MMX指令可以使用MMX寄存器。值得一提的是,MMX寄存器是隨機(jī)存取的,但實(shí)際上是借用了8個(gè)浮點(diǎn)數(shù)據(jù)寄存器實(shí)現(xiàn)的。浮點(diǎn)處理單元FPU有8個(gè)浮點(diǎn)寄存器FPR,以堆棧方式存取。每個(gè)浮點(diǎn)數(shù)據(jù)寄存器有80位,高16位用于指數(shù)和符號(hào),低64位用于有效數(shù)字。MMX利用其64位有效數(shù)字部分用做隨機(jī)存取的64位的MMX寄存器。也就是說(shuō)MMX寄存器并非獨(dú)立寄存器,而是復(fù)用了fpu數(shù)據(jù)堆棧寄存器,也就是說(shuō)使用mmx指令集會(huì)破壞fpu的計(jì)算,如果同時(shí)使用著兩種特性,一定要注意這點(diǎn),避免出現(xiàn)莫名的錯(cuò)誤。
 
 
 MMX指令集
 1、算術(shù)運(yùn)算:
 PADD[B、W、D] 環(huán)繞加[字節(jié),字,雙字]
 PADDS[B , W] 有符號(hào)飽和加[字節(jié),字]
 PADDUS[B , W] 無(wú)符號(hào)飽和加[字節(jié),字]
 PSUB[B、W、D] 環(huán)繞減[字節(jié),字,雙字]
 PSUBS[B,W] 有符號(hào)飽和減[字節(jié),字]
 PSUBUS[D,W] 無(wú)符號(hào)飽和減[字節(jié),字]
 PMULHW 緊縮字乘后取高位
 PMULLW 緊縮字乘后取低位
 PMADDWD 緊縮字乘,積相加
 2、比較:
 PCMPEQ[B,W,D] 緊縮比較是否相等[字節(jié),字,雙字]
 PCMPGT[B,W,D] 緊縮比較是否大于[字節(jié),字,雙字]
 3、類(lèi)型轉(zhuǎn)換:
 PACKUSWB 按無(wú)符號(hào)飽和壓縮[字成字節(jié)]
 PACKSS[WB,DW] 按有符號(hào)飽和壓縮[字/雙字成/字節(jié)/字]
 PUNPCKH[BW,WD,DQ] 擴(kuò)展高位[字節(jié),字,雙字成字,雙字,4字]
 PUNPCKL[BW,WD,DQ] 擴(kuò)展地位[字節(jié),字,雙字成字,雙字,4字]
 4、邏輯運(yùn)算:
 PAND 緊縮邏輯與
 PANDN 緊縮邏輯與非
 POR 緊縮邏輯或
 PXOR 緊縮邏輯異或
 5、位移:
 PSLL[W,D,Q] 緊縮邏輯左移[字,雙字,4字]
 PSRL[W,D,Q] 緊縮邏輯右移[字,雙字,4字]
 PSRA[W,D] 緊縮算術(shù)右移[字,雙字]
 7、數(shù)據(jù)傳送:
 MOV[D,Q] 從MMX寄存器傳人/傳出[雙字/4字]
 8、狀態(tài)清除
 EMMS 清除MMX狀態(tài)
 
 
 首先mmx指令集需要cpu的支持,但不是所有cpu都支持,不然也不會(huì)稱之為高級(jí)特性 了,所以在使用之前需要檢測(cè),檢測(cè)指令為cpuid,獲得cpu的特性,cpuid雖然只有一條指令,但是其隱含的內(nèi)容太多,這里僅僅介紹檢測(cè)SIMD指令集所需要的部分,其他一些信息可參閱Intel 手冊(cè)獲得。
 當(dāng)eax為1時(shí),cpuid指令返回cpu簽名信息,放入ecx和edx寄存器中,相應(yīng)位為1表示支持。檢測(cè)SIMD指令集的結(jié)果如下:
 寄存器 位 特性
 EDX ? ?? 23  支持MMX
 EDX 25  支持SSE
 EDX 26  支持SSE2
 ECX 0 支持SSE3
具體檢測(cè)代碼如下(AT&T 語(yǔ)法):
 .section .data
 mmxstring: .asciz "支持mmx指令集\n"
 ssestring: .asciz "支持sse指令集\n"
 sse2string: .asciz "支持sse2指令集\n"
 sse3string: .asciz "支持sse3指令集\n"
 
 .section .text
 .globl _main
 _main:
 movl $1, %eax
 cpuid
 
 mmxop:
 test $0x800000, %edx
 jz sseop
 pushl $mmxstring
 call _printf
 
 sseop:
 test $0x2000000, %edx
 jz sse2op
 pushl $ssestring
 call _printf
 
 sse2op:
 test $0x4000000, %edx
 jz sse3op
 pushl $sse2string
 call _printf
 
 sse3op:
 test $0x01, %ecx
 jz end
 pushl $sse3string
 call _printf
 end:
 pushl $0
 call _exit
 ? ? ??
? ? ? 下面正式開(kāi)始mmx指令集的介紹,使用mmx需要三個(gè)步驟:
 1、從整數(shù)值創(chuàng)建打包整數(shù),載入mmx寄存器
 2、使用mmx指令集計(jì)算
 3、從mmx獲得結(jié)果,存入內(nèi)存
 ? ? ? 第一個(gè)和最后一個(gè)步驟比較簡(jiǎn)單,僅僅是數(shù)據(jù)移動(dòng)而已,這里提到打包,因?yàn)檫@里要單指令多數(shù)據(jù),所以需要把多數(shù)據(jù)合成一個(gè)操作數(shù)進(jìn)行計(jì)算,存入64位的mmx寄存器中,打包的過(guò)程就是把 8個(gè)字節(jié)/4個(gè)字/2個(gè)雙字合成一個(gè)64位數(shù)據(jù)。
 ? ? ?從加減法說(shuō)起,對(duì)于普通數(shù)據(jù),如果數(shù)據(jù)溢出可以置標(biāo)記位,但是對(duì)于多數(shù)據(jù)的運(yùn)算,由于同時(shí)計(jì)算多個(gè)加法,就不能單純的設(shè)置標(biāo)志,對(duì)mmx計(jì)算有幾種情況:
 
 環(huán)繞運(yùn)算 截?cái)嗥渲?#xff0c;丟棄進(jìn)位
 帶符號(hào)飽和 最大/最小 帶符號(hào)值
 無(wú)符號(hào)飽和 最大/最小 無(wú)符號(hào)值
 ? ? ? 其中飽和運(yùn)算的預(yù)設(shè)值根據(jù)結(jié)果的位數(shù)決定,有符號(hào)8位最大為127,如果超過(guò)127,結(jié)果按127計(jì)算,其他情況與此類(lèi)似,這里方便與一些圖形處理,比如色彩黑色為0,為無(wú)符號(hào)最小值,小于其值也按黑色處理。
 ? ? ? 好 了,到此可以看一下具體的指令,這里的指令有相同的格式,instruction source, destination;其中source可以是mmx寄存器或者64位內(nèi)存,destination為mmx寄存器。這是AT&T語(yǔ)法,對(duì)于 MASM語(yǔ)法源目的操作數(shù)相反。
 ? ?指令 說(shuō)明
 paddb 環(huán)繞打包字節(jié)整數(shù)加法
 paddw 環(huán)繞打包字整數(shù)加法
 paddd 環(huán)繞打包雙字整數(shù)加法
 paddsb 帶符號(hào)飽和打包字節(jié)整數(shù)加法
 paddsw 帶符號(hào)飽和打包字整數(shù)加法
 paddusb ?? 無(wú)符號(hào)飽和打包字節(jié)整數(shù)加法
 paddusw 無(wú)符號(hào)飽和打包字整數(shù)加法
 psubb 環(huán)繞打包字節(jié)整數(shù)減法
 psubw 環(huán)繞打包字整數(shù)減法
 psubd 環(huán)繞打包雙字整數(shù)減法
 psubsb ? ? 帶符號(hào)飽和打包字節(jié)整數(shù)減法
 psubsw ?? 帶符號(hào)飽和打包字整數(shù)減法
 psubusb 無(wú)符號(hào)飽和打包字節(jié)整數(shù)減法
 psubusw 無(wú)符號(hào)飽和打包字整數(shù)減法
 下面以AT&T加法為例進(jìn)行說(shuō)明,這里以飽和方式計(jì)算4個(gè)無(wú)符號(hào)字之和:
 
 # add four word
 # output : result is 18932, 7631, 65535, 510
 .section .data
 value1: .short 12300, 2384, 60000, 456
 value2: .short 6632, 5247, 40000, 54
 
 outstring: .asciz "result is %u, %u, %u, %u\n"
 .section .text
 .globl _main
 _main:
 movq value1, %mm0
 movq value2, %mm1
 paddusw %mm1, %mm0
 movq %mm0, value1
 
 movl $value1, %ebx
 xorl %eax, %eax
 movw 6(%ebx), %ax
 pushl %eax
 movw 4(%ebx), %ax
 pushl %eax
 movw 2(%ebx), %ax
 pushl %eax
 movw (%ebx), %ax
 pushl %eax
 
 pushl $outstring
 call _printf
 
 pushl $0
 call _exit
 ? ? ? movq 指令把內(nèi)存中的數(shù)據(jù)傳送至mmx寄存器,如果數(shù)據(jù)之前在內(nèi)存中不是連續(xù)的,則需要集中存放,即進(jìn)行打包,之后使用paddusw進(jìn)行加法計(jì)算,輸出時(shí) word需轉(zhuǎn)化成dword放入堆棧,可以看到以飽和方式第三個(gè)結(jié)果為65535,即16位無(wú)符號(hào)數(shù)的最大值。從這里例子可以看出,通過(guò)一條指令計(jì)算了四 個(gè)word整數(shù)相加,很大程度上提高了計(jì)算的效率,但是同時(shí)需要注意,整數(shù)的打包以及傳送過(guò)程也需要耗時(shí),如果打包操作很多,結(jié)果不是提高效率而是降低效率了。
 ? ? ?mmx指令集的加法根據(jù)需要有飽和方式和環(huán)繞方式計(jì)算,但對(duì)于乘法而言,由于結(jié)果的寬度可能是操作數(shù)的兩倍,所以兩種方式看上去都不合適,所以intel提供了兩個(gè)指令,一個(gè)得到計(jì)算結(jié)果的低字節(jié),另一個(gè)得到計(jì)算結(jié)果的高字節(jié)。
 
 ? ? 指令 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?描述
 pmulluw ? ? ? ??對(duì)無(wú)符號(hào)16位整數(shù)相乘取結(jié)果低16位
 pmulhuw 對(duì)無(wú)符號(hào)16位整數(shù)相乘取結(jié)果高16位
 pmullw ? ? ? ? ?對(duì)有符號(hào)16位整數(shù)相乘取結(jié)果低16位
 pmulhw ? ? ? ??對(duì)有符號(hào)16位整數(shù)相乘取結(jié)果高16位
 pmaddwd 對(duì)4個(gè)帶符號(hào)整數(shù)相乘,高位兩個(gè)結(jié)果相加存入高32位,低位相同
 ? ? ? mmx 指令集還提供對(duì)四字值進(jìn)行布爾邏輯操作和移位指令:
 ? 指令 ? ? ? ? ? ? ? ? ? ? ?描述
 pand 對(duì)源和目標(biāo)操作數(shù)按位與操作
 pandn 對(duì)目標(biāo)操作數(shù)進(jìn)行按位邏輯非操作,然后對(duì)源和目標(biāo)操作數(shù)按位與操作
 por ? ? ? ? ? 對(duì)源和目標(biāo)操作數(shù)按位或操作
 pxor ? ? ? ??對(duì)源和目標(biāo)操作數(shù)按位異或操作
 psll ? ? ? ? ?對(duì)目標(biāo)操作數(shù)執(zhí)行邏輯左移操作,使用0填充空位
 psra 對(duì)目標(biāo)操作數(shù)執(zhí)行邏輯右移操作,使用0填充空位
 其AT&T指令格式如下:
 pand source, destination
 其中source是mmx寄存器或者64位內(nèi)存,destination必須是mmx寄存器。移位指令可以使用字,雙字或者四字操作數(shù),還有移位的位置數(shù)量。MASM格式的源目的操作數(shù)相反。
 
 mmx構(gòu)架提供了用于比較兩個(gè)值的指令:
 ? ? ?指令 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?描述
 pcmpeqb 比較打包字節(jié)整數(shù)值的相等性
 pcmpeqw 比較打包字整數(shù)值的相等性
 pcmpeqd 比較打包雙字整數(shù)值的相等性
 pcmpgtb 判斷打包字節(jié)整數(shù)值是否大于另一個(gè)
 pcmpgtw 判斷打包字整數(shù)值是否大于另一個(gè)
 pcmpgtd 判斷打包雙字整數(shù)值是否大于另一個(gè)
 ? ? 因?yàn)閙mx同時(shí)比較多個(gè)數(shù)據(jù),所以不能設(shè)置標(biāo)志,替換的做法是把判斷結(jié)果放到目標(biāo)打包整數(shù)值中,如果打包整數(shù)值滿足對(duì)比提交,就把結(jié)果設(shè)置為全1,否則設(shè)置為全0。
 ? ? 由于mmx指令集并非所有cpu都可以支持,所以對(duì)c語(yǔ)言這種編譯通用性的程序而言,是不會(huì)貿(mào)然使用mmx指令集的,這也對(duì)我們手工匯編優(yōu)化程序提供了很大的空間,但是需要注意打包整數(shù)的效率損耗。
 
 
 
 
 
總結(jié)
以上是生活随笔為你收集整理的MMX的数据结构 MMX指令集的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: OpenCV算法加速(2)使用SIMD指
- 下一篇: Intel汇编-传送MMX整数
