最近根据开发任务安排了对C++的代码用SSE指令优化的计划,自己在这方面完全是新手,所以只能从0开始,一步步学习。特此记录自己学习的点点滴滴。
SSE(Stream SIMD Extensions)是Intel在其计算机芯片Pentium3中引入的指令集,是继MMX的扩充指令集。提供了70条新指令。
SIMD,single instruction multiple data,单指令流多数据流,一次运算指令可以执行多个数据流,可以提高程序的运算速度,是实现DLP(Data Level Parallelism)的关键。
SSE本质上类似于一个向量处理器,包括了4个主要部分:单精确度浮点数运算指令、整数运算指令(为MMX的延伸,并与MMX使用同样的暂存器)、Cache控制指令、状态控制指令。
SSE浮点运算指令分为两大类:packed和scalar
packed指令是一次对XMM暂存器中的四个浮点数(DATA0~DATA3)均进行计算,而scalar只对XMM暂存器中的DATA0进行计算,见下图。
SSE指令的一般格式由三部分组成,第一部分表示指令的作用,第二部分是s或者p分别表示scalar或packed,第三部分为s,表示单精度浮点数(single precision floating point data)
SSE定址/寻址方式:
SSE指令和一般的x86指令很类似,基本包括两种定址方式:寄存器-寄存器方式(reg-reg)和寄存器-内存方式(reg-mem):
addps xmm0,xmm1;reg-reg
addps xmm0,[ebx]; reg-mem
SSE指令表
浮点指令
记忆体到暂存器/暂存器到记忆体/暂存器之间的资料搬移
纯量(scalar):MOVSS
包裹式(packed):MOVAPS,MOVUPS,MOVLPS,MOVHPS,MOVLHPS,MOVHLPS数学运算
纯量:ADDSS,SUBSS,MULSS,DIVSS,RCPSS,SQRTSS,MAXSS,MINSS,RSQRTSS
包裹式:ADDPS,SUBPS,MULPS,DIVPS,RCPPS,SQRTPS,MAXPS,MINPS,RSQRTPS比较
纯量:CMPSS,COMISS,UCOMISS
包裹式:CMPPS资料拆包(unpack)与随机搬移(shuffle)
包裹式:SHUFPS,UNPCKHPS,UNPCKLPS资料形态转换
纯量:CVTSI2SS,CVTSS2SI,CVTTSS2SI
包裹式:CVTPI2PS,CVTPS2PI,CVTTPS2PI逐位逻辑运算
包裹式:ANDPS,ORPS,XORPS,ANDNPS
整数指令
- 数学运算
PMULHUW,PSADBW,PAVGB,PAVGW,PMAXUB,PMINUB,PMAXSW,PMINSW - 资料搬移
PEXTRW,PINSRW - 其它
PMOVMSKB,PSHUFW
其它指令
- MXCSR管理
LDMXCSR,STMXCSR - 快取与记忆体管理(SSE除了运算的指令外,还支持了cache控制指令)
MOVNTQ,MOVNTPS,MASKMOVQ,PREFETCH0,PREFETCH0,PREFETCH1,PREFECTCH2,PREFETCHNTA,SFENCE
prefetch指令的主要目的,是提前让CPU载入稍后运算所需要的数据。通常是在对目前的资料进行与运算之前,告诉CPU载入下一批数据。这样就可以让目前的运算和载入下一批数据的动作可以同时进行。不同prefetch指令则是告诉CPU将数据载入不同层次的cache。prefetch指令不会产生任何exception。
除了prefetch之外,另一個指令是movntps,它的intrinsics是 _mm_stream_ps。這個指令的用途,是要求 CPU 在写入数据的時候,不要把数据写到 cache 中,而是直接將数据写到主记忆体中。实际上它以 write combining 的方式写入的。为什麼要这样做呢?這是因为,很多时候计算的結果并不是立刻需要用到的,通常是很久以后才会用到。所以,这些数据如果被放在 cache 中,完全是浪费空间。而且,更糟的是,它们可能会把 cache 中有用的数据挤掉,而使得这些数据常常需要重新从主记忆体中载入。因此,如果让这些数据不要被放在 cache 中,就可以避免这种問題。
参考阅读:
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 (对字节对齐不清的童鞋可以参考这篇文章)