最近根據(jù)開(kāi)發(fā)任務(wù)安排了對(duì)C++的代碼用SSE指令優(yōu)化的計(jì)劃,自己在這方面完全是新手,所以只能從0開(kāi)始,一步步學(xué)習(xí)。特此記錄自己學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。
SSE(Stream SIMD Extensions)是Intel在其計(jì)算機(jī)芯片Pentium3中引入的指令集,是繼MMX的擴(kuò)充指令集。提供了70條新指令。
SIMD,single instruction multiple data,單指令流多數(shù)據(jù)流,一次運(yùn)算指令可以執(zhí)行多個(gè)數(shù)據(jù)流,可以提高程序的運(yùn)算速度,是實(shí)現(xiàn)DLP(Data Level Parallelism)的關(guān)鍵。
SSE本質(zhì)上類似于一個(gè)向量處理器,包括了4個(gè)主要部分:?jiǎn)尉_度浮點(diǎn)數(shù)運(yùn)算指令、整數(shù)運(yùn)算指令(為MMX的延伸,并與MMX使用同樣的暫存器)、Cache控制指令、狀態(tài)控制指令。
SSE浮點(diǎn)運(yùn)算指令分為兩大類:packed和scalar
packed指令是一次對(duì)XMM暫存器中的四個(gè)浮點(diǎn)數(shù)(DATA0~DATA3)均進(jìn)行計(jì)算,而scalar只對(duì)XMM暫存器中的DATA0進(jìn)行計(jì)算,見(jiàn)下圖。

SSE指令的一般格式由三部分組成,第一部分表示指令的作用,第二部分是s或者p分別表示scalar或packed,第三部分為s,表示單精度浮點(diǎn)數(shù)(single precision floating point data)

SSE定址/尋址方式:
SSE指令和一般的x86指令很類似,基本包括兩種定址方式:寄存器-寄存器方式(reg-reg)和寄存器-內(nèi)存方式(reg-mem):
addps xmm0,xmm1;reg-reg
addps xmm0,[ebx]; reg-mem
SSE指令表
浮點(diǎn)指令
記憶體到暫存器/暫存器到記憶體/暫存器之間的資料搬移
純量(scalar):MOVSS
包裹式(packed):MOVAPS,MOVUPS,MOVLPS,MOVHPS,MOVLHPS,MOVHLPS數(shù)學(xué)運(yùn)算
純量:ADDSS,SUBSS,MULSS,DIVSS,RCPSS,SQRTSS,MAXSS,MINSS,RSQRTSS
包裹式:ADDPS,SUBPS,MULPS,DIVPS,RCPPS,SQRTPS,MAXPS,MINPS,RSQRTPS比較
純量:CMPSS,COMISS,UCOMISS
包裹式:CMPPS資料拆包(unpack)與隨機(jī)搬移(shuffle)
包裹式:SHUFPS,UNPCKHPS,UNPCKLPS資料形態(tài)轉(zhuǎn)換
純量:CVTSI2SS,CVTSS2SI,CVTTSS2SI
包裹式:CVTPI2PS,CVTPS2PI,CVTTPS2PI逐位邏輯運(yùn)算
包裹式:ANDPS,ORPS,XORPS,ANDNPS
整數(shù)指令
- 數(shù)學(xué)運(yùn)算
PMULHUW,PSADBW,PAVGB,PAVGW,PMAXUB,PMINUB,PMAXSW,PMINSW - 資料搬移
PEXTRW,PINSRW - 其它
PMOVMSKB,PSHUFW
其它指令
- MXCSR管理
LDMXCSR,STMXCSR - 快取與記憶體管理(SSE除了運(yùn)算的指令外,還支持了cache控制指令)
MOVNTQ,MOVNTPS,MASKMOVQ,PREFETCH0,PREFETCH0,PREFETCH1,PREFECTCH2,PREFETCHNTA,SFENCE
prefetch指令的主要目的,是提前讓CPU載入稍后運(yùn)算所需要的數(shù)據(jù)。通常是在對(duì)目前的資料進(jìn)行與運(yùn)算之前,告訴CPU載入下一批數(shù)據(jù)。這樣就可以讓目前的運(yùn)算和載入下一批數(shù)據(jù)的動(dòng)作可以同時(shí)進(jìn)行。不同prefetch指令則是告訴CPU將數(shù)據(jù)載入不同層次的cache。prefetch指令不會(huì)產(chǎn)生任何exception。
除了prefetch之外,另一個(gè)指令是movntps,它的intrinsics是 _mm_stream_ps。這個(gè)指令的用途,是要求 CPU 在寫(xiě)入數(shù)據(jù)的時(shí)候,不要把數(shù)據(jù)寫(xiě)到 cache 中,而是直接將數(shù)據(jù)寫(xiě)到主記憶體中。實(shí)際上它以 write combining 的方式寫(xiě)入的。為什麼要這樣做呢?這是因?yàn)?,很多時(shí)候計(jì)算的結(jié)果并不是立刻需要用到的,通常是很久以后才會(huì)用到。所以,這些數(shù)據(jù)如果被放在 cache 中,完全是浪費(fèi)空間。而且,更糟的是,它們可能會(huì)把 cache 中有用的數(shù)據(jù)擠掉,而使得這些數(shù)據(jù)常常需要重新從主記憶體中載入。因此,如果讓這些數(shù)據(jù)不要被放在 cache 中,就可以避免這種問(wèn)題。
參考閱讀:
http://dev.gameres.com/Program/Other/SSEjianjie.htm http://blog.csdn.net/gengshenghong/article/details/7008704
http://www.cnblogs.com/clover-toeic/p/3853132.html (對(duì)字節(jié)對(duì)齊不清的童鞋可以參考這篇文章)