全称Streaming SIMD Extension,是x86上对SIMD指令集的一个扩展,主要用于处理单精度浮点数。Intel陆续推出SSE2、SSE3、SSE4版本。其中,SSE主要处理单精度浮点数,SSE2引入了整数的处理,SSE指令集引入了8个128bit的寄存器,称为
XMM0到XMM7。正因为这些寄存器存储了多个数据,使用一条指令处理,因此称这项功能为SIMD。
Intel指令集C库Doc:https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=SSE,SSE2,SSE3,SSSE3,SSE4_1,SSE4_2
<aside> 🔥 头文件
</aside>
| 指令集 | 头文件 | 编译器参数 |
|---|---|---|
| SSE | xmmintrin.h | -msse |
| SSE2 | emmintrin.h | -msse2 |
| SSE3 | pmmintrin.h | |
| SSSE3 | tmmintrin.h | |
| SSE4.1 | smmintrin.h | |
| SSE4.2 | nmmintrin.h | -msse4.2 |
| SSE4A | ammintrin.h |
<aside> 🔥 数据结构
</aside>
__m128:保存4个单精度浮点数__m128d:保存2个双精度浮点数__m128i:保存整数,如4个32bit、8个16bit和2个64bit整数对于
__m128d和__m128i,编译器自动把局部和全局变量在栈上对齐16字节。若需要对齐整型、float和double数组,使用__declspec(align)
<aside> 🔥 函数
</aside>
_<mm/mm256/mm512>_<intrin_op>_<suffix>
<suffix>为操作数的类型,有两部分
前一个或前两个字母代表这个操作数是packed(p),还是extended packed(ep),还是scaler(s)
pack即SIMD,同时计算好几对数据。scaler只操作最低位的一组数据。extended packed??TODO
<aside> ⚠️ 注意pack的内存序列
**double** a[2] **=** {1.0, 2.0};
__m128d t **=** _mm_load_pd(a);
那么在寄存器中,就是这样的
127----063----000
| 2.0 | 1.0 |
</aside>
后面的字母代表数据类型。如下:
SIMD指令家族
| MMX | 64位整型 |
|---|---|
| SSE | 128位浮点运算,整数运算仍然要使用MMX 寄存器,只支持单精度浮点运算 |
| SSE2 | 对整型数据的支持,支持双精度浮点数运算,CPU快取的控制指令 |
| SSE3 | 扩展的指令包含寄存器的局部位之间的运算,例如高位和低位之间的加减运算;浮点数到整数的转换,以及对超线程技术的支持。 |
| SSE4 | |
| AVX | 256位浮点运算 |
| AVX2 | 对256位整型数据的支持,三运算指令(3-Operand Instructions) |
| AVX512 | 512位运算 |

<aside> 🔥 寄存器与指令数据细节
</aside>
在MMX指令集中,使用的寄存器称作MM0到MM7,实际上借用了浮点处理器的8个寄存器的低64Bit,这样导致了浮点运算速度降低。
SSE指令集推出时,Intel公司在Pentium III CPU中增加了8个128位的SSE指令专用寄存器,称作XMM0到XMM7。这样SSE指令寄存器可以全速运行,保证了与浮点运算的并行性。这些XMM寄存器用于4个单精度浮点数运算的SIMD执行,并可以与MMX整数运算或x87浮点运算混合执行。
2001年在Pentium 4上引入了SSE2技术,进一步扩展了指令集,使得XMM寄存器上可以执行8/16/32位宽的整数SIMD运算或双精度浮点数的SIMD运算。对整型数据的支持使得所有的MMX指令都是多余的了,同时也避免了占用浮点数寄存器。SSE2为了更好地利用高速寄存器,还新增加了几条寄存指令,允许程序员控制已经寄存过的数据。这使得 SIMD技术基本完善。
SSE3指令集扩展的指令包含寄存器的局部位之间的运算,例如高位和低位之间的加减运算;浮点数到整数的转换,以及对超线程技术的支持。
AVX是Intel的SSE延伸架构,把寄存器XMM 128bit提升至YMM 256bit,以增加一倍的运算效率。此架构支持了三运算指令(3-Operand Instructions),减少在编码上需要先复制才能运算的动作。在微码部分使用了LES LDS这两少用的指令作为延伸指令Prefix。AVX的256bit的YMM寄存器分为两个128bit的lanes,AVX指令并不支持跨lanes的操作。其中YMM寄存器的低128位与Intel SSE指令集的128bitXMM寄存器复用。尽管VGX并不要求内存对齐,但是内存对齐有助于提升性能。如对于128-bit访问的16字节对齐和对于256-bit访问的32字节对齐。
AVX虽然已经将支持的SIMD数据宽度增加到了256位,但仅仅增加了对256位的浮点SIMD支持,整点SIMD数据的宽度还停留在128位上,AVX2支持的整点SIMD数据宽度从128位扩展到256位。同时支持了跨lanes操作,加入了增强广播、置换指令支持的数据元素类型、移位操作对各个数据元素可变移位数的支持、跨距访存支持。AVX硬件由16个256bitYMM寄存器(YMM0~YMM15)组成。
每一代的指令集都是对上一代兼容的,支持上一代的指令,也可以使用上一代的寄存器,也就是说,AVX2也依然支持128位,64位的操作,也可以使用上一代的寄存器(当然,寄存器的硬件实现可能有区别)。AVX也对部分之前的指令接口进行了重构,所以可以在指令文档中找到几个处于不同代际有着相同功能调用接口却不相同的函数。
另外,不同代际的指令不要混用,每次状态切换将消耗 50-80 个时钟周期,会拖慢程序的运行速度。
| MMX | SSE | SSE2 | AVX | AVX2 | |
|---|---|---|---|---|---|
| 寄存器 | MM0-MM7 | XMM0-XMM7 | XMM0-XMM7 | YMM0-YMM15 | YMM0-YMM15 |
| 浮点 | 128bit | 128bit | 256bit | 256bit | |
| 整型 | 64bit | 128bit | 128bit | 256bit |