SIMD(Single Instruction Multiple Data)指令集,指单指令多数据流技术,可用一组指令对多组数据通进行并行操作。SIMD指令可以在一个控制器上控制同时多个平行的处理微元,一次指令运算执行多个数据流,这样在很多时候可以提高程序的运算速度。先行大部分的密码算法库都使用了SIMD加速。
AVX为在Inter CPU处理器上实现SIMD操作的指令集。主要衍化流程为:
AVX,全称为:Advanced Vector Extensions(又名,Sandy Bridge New Extensions),是Intel和AMD微服务器x86指令集的extension扩展。
AVX2扩充到了支持256bit的整数运算指令,引入了Fused-Multiply-Add(FMA)运算。所谓FMA,即可通过单一指令实现A = A ∗ B + C A=A*B+CA=A∗B+C计算。
AVX-512通过使用新的EVEX prefix编码方式,将AVX扩充到了支持512-bit运算。
在C++中使用AVX(Advanced Vector Extensions)指令集,需要包含相应的头文件以使用AVX指令:
#include <immintrin.h>
immintrin.h 头文件包含了许多 AVX、AVX2 和 AVX-512 指令的声明,以及相应的数据类型和函数。这个头文件提供了对 AVX 指令的访问和使用所需的所有定义和声明。
在包含了 immintrin.h 后,可以在代码中使用 AVX 指令了。请注意,使用 AVX 指令需要确保编译器支持 AVX 指令集,并且需要在编译选项中启用相应的优化标志,如 -mavx
| 数据类型 | 描述 | 元素个数 | 元素大小 | 总大小 |
|---|---|---|---|---|
| __m128 | 包含 4 个单精度浮点数的向量 | 4 | 32 位 | 128 位 |
| __m128d | 包含 2 个双精度浮点数的向量 | 2 | 64 位 | 128 位 |
| __m128i | 包含若干个整型数字的向量 | - | 128 位 | 128 位 |
| __m256 | 包含 8 个单精度浮点数的向量 | 8 | 32 位 | 256 位 |
| __m256d | 包含 4 个双精度浮点数的向量 | 4 | 64 位 | 256 位 |
| __m256i | 包含若干个整型数字的向量 | - | 256 位 | 256 位 |
前面带**两个**下划线
名字里带128的 = 一个向量包含128个bit = 32 byte
名字里带256的 = 一个向量包含256个bit = 64 byte
尾巴啥也不带的 = 里面都是float,一个float=32bit
尾巴带d的 = 里面都是double,一个double=64bit
尾巴带i的 = 里面都是整型,根据整型的类型不同,个数也不同
_mm<bit_width>_<name>_<data_type>
<bit_width> 返回的向量的类型,返回的是256bit大小的就是256,返回128大小的,这里就是空的。还有一些特殊的:store没有返回(void);test系列比较两个输入是否相同,返回0或1。<name> 函数的名字,基本通过名字就可以看出功能啦~<data_type> 表示这个函数在处理数据时,会把输入的数据当作什么类型去处理关于**<data_type>**,因为m256i / m128i中的整型多种多样,需要告诉AVX里面的整型大小(size)是多少。
ps:里面都是float,把32bits当成一个数看pd:里面都是double,把64bits当成一个数看epi8/epi16/epi32/epi64:向量里每个数都是整型,一个整型8bit/16bit/32bit/64bitepu8/epu16/epu32/epu64:向量里每个数都是无符号整型(unsigned),一个整型8bit/16bit/32bit/64bitm128/m128i/m128d/m256/m256i/m256d:输入值与返回类型不同时会出现 ,例如__m256i_mm256_setr_m128i(__m128ilo,__m128ihi),输入两个__m128i向量 ,把他们拼在一起,变成一个__m256i返回 。另外这种结尾只见于loadsi128/si256:不care向量里到底都是些啥类型,反正128bit/256bit,例如:__m256i _mm_broadcastsi128_si256 (__m128i a)
此函数接收一个128-bit的__m128i,然后将这__m128i的128位,按位放入返回的__m256i 类型的前128位(127-0)中,再按位放入(复制到)后128位(255-128)中。因为不涉及单个数操作,将128位看成整体操作,所以不用在意其中每个数的数据类型。
si128/si256基本只见于
broadcast:复制2遍__m128i,放入 __m256i;cast:
__m128i转型__m256i(upper 128 bit undefined) ,__m256i转型 __m128i总而言之5 & 6两种并不太常见。
| 数据类型 | 描述 |
|---|---|
| _mm256_setzero_ps/pd | 返回一个全0的 float 类型的向量 |
| _mm256_setzero_si256 | 返回一个全0的整型向量 |
| _mm256_set1_ps/pd | 用一个 float 类型的数填充向量 |
| _mm256_set1_epi8/epi16/epi32/epi64x | 用整型数填充向量 |
| _mm256_set_ps/pd | 用8个 float 或者4个 double 类型数字初始化向量 |
| _mm256_set_epi8/epi16/epi32/epi64x | 用一个整型数初始化向量 |
| _mm256_set_m128/m128d/m128i | 用2个128位的向量初始化一个256位向量 |
| _mm256_setr_ps/pd | 用8个 float 或者4个 double 的转置顺序初始化向量 |
| _mm256_setr_epi8/epi16/epi32/epi64x | 用若干个整型数的转置顺序初始化向量 |
| 数据类型 | 描述 |
|---|---|
| _mm256_load_ps/pd | 从对齐的内存地址加载浮点向量 |
| _mm256_load_si256 | 从对齐的内存地址加载整型向量 |
| _mm256_loadu_ps/pd | 从未对齐的内存地址加载浮点向量 |
| _mm256_loadu_si256 | 从未对齐的内存地址加载整型向量 |
| _mm_maskload_ps/pd | 根据掩码加载128位浮点向量的部分 |
| _mm256_maskload_ps/pd | 根据掩码加载256位浮点向量的部分 |
| (2)_mm_maskload_epi32/64 | 根据掩码加载128位整型向量的部分 |
| (2)_mm256_maskload_epi32/64 | 根据掩码加载256位整型向量的部分 |
最后2个函数前面有一个(2),代表这两个函数只在AVX2中支持,下面(2)同理
| 数据类型 | 描述 |
|---|---|
| _mm256_mul_ps/pd | 对两个 float 类型的向量进行相乘 |
| (2)_mm256_mul_epi32 | 将包含 32 位整数的向量的最低四个元素相乘 |
| (2)_mm256_mul_epu32 | 将无符号 32 位整数的向量的最低四个元素相乘 |
| (2)_mm256_mullo_epi16/32 | 将整数相乘并存储低半部分 |
| (2)_mm256_mulhi_epi16 | 将整数相乘并存储高半部分 |
| (2)_mm256_mulhi_epu16 | 将无符号整数相乘并存储高半部分 |
| (2)_mm256_mulhrs_epi16 | 将16位元素相乘以形成32位元素 |
| _mm256_div_ps/pd | 对两个 float 类型的向量进行除法 |
| 数据类型 | 描述 |
|---|---|
| _mm256_add_ps/pd | 对两个浮点向量做加法 |
| _mm256_sub_ps/pd | 对两个浮点向量做减法 |
| (2)_mm256_add_epi8/16/32/64 | 对两个整型向量做加法 |
| (2)_mm256_sub_epi8/16/32/64 | 对两个整型向量做减法 |
| (2)_mm256_adds_epi8/16 | 两个整数向量相加且考虑内存饱和问题 |
| (2)_mm256_adds_epu8/16 | 两个无符号整数向量相加且考虑内存饱和问题 |
| (2)_mm256_subs_epi8/16 | 两个整数向量相减且考虑内存饱和问题 |
| (2)_mm256_subs_epu8/16 | 两个无符号整数向量相减且考虑内存饱和问题 |
| _mm256_hadd_ps/pd | 水平方向上对两个浮点向量做加法 |
| _mm256_hsub_ps/pd | 垂直方向上对两个浮点向量做减法 |
| (2)_mm256_hadd_epi16/32 | 水平方向上对两个整型向量做加法 |
| (2)_mm256_hsub_epi16/32 | 水平方向上对两个整型向量做减法 |
| (2)_mm256_hadds_epi16 | 对两个包含 short 类型的向量做加法且考虑内存饱和问题 |
| (2)_mm256_hsubs_epi16 | 对两个包含 short 类型的向量做减法且考虑内存饱和问题 |
| _mm256_addsub_ps/pd | 加上和减去两个浮点类型的向量 |
| 指令 | 描述 |
|---|---|
_mm_fmadd_ps/pd | 将两个向量相乘,再将第三个向量的对应元素加到乘积中。 |
_mm256_fmadd_ps/pd | 将两个向量相乘,再将第三个向量的对应元素加到乘积中。 |
_mm_fmsub_ps/pd | 将两个向量相乘,然后将第三个向量的对应元素从乘积中减去。 |
_mm256_fmsub_ps/pd | 将两个向量相乘,然后将第三个向量的对应元素从乘积中减去。 |
_mm_fmadd_ss/sd | 将两个向量的最低元素相乘并相加。 |
_mm_fmsub_ss/sd | 将两个向量的最低元素相乘并相减。 |
_mm_fnmadd_ps/pd | 将两个向量相乘,并将负乘积加到第三个向量中。 |
_mm256_fnmadd_ps/pd | 将两个向量相乘,并将负乘积加到第三个向量中。 |
_mm_fnmsub_ps/pd | 将两个向量相乘,并将负乘积减去第三个向量。 |
_mm256_fnmsub_ps/pd | 将两个向量相乘,并将负乘积减去第三个向量。 |
_mm_fmaddsub_ps/pd | 将两个向量相乘,然后交替地将第三个向量的对应元素加到或减去乘积中。 |
_mm256_fmaddsub_ps/pd | 将两个向量相乘,然后交替地将第三个向量的对应元素加到或减去乘积中。 |
_mm_fmsubadd_ps/pd | 将两个向量相乘,然后交替地将第三个向量的对应元素减去或加到乘积中,取决于元素的位置(奇数次方或偶数次方)。 |
_mmf256_fmsubadd_ps/pd | 将两个向量相乘,然后交替地将第三个向量的对应元素减去或加到乘积中,取决于元素的位置(奇数次方或偶数次方)。 |
| 指令 | 描述 |
|---|---|
_mm_permute_ps/pd | 根据8位控制值从输入向量中选择元素。 |
_mm256_permute_ps/pd | 根据8位控制值从输入向量中选择元素。 |
_mm256_permute4x64_pd | 根据8位控制值从输入向量中选择64位元素。 |
_mm256_permute4x64_epi64 | 根据8位控制值从输入向量中选择64位元素。 |
_mm256_permute2f128_ps/pd | 基于8位控制值从两个输入向量中选择128位块。 |
_mm256_permute2f128_si256 | 基于8位控制值从两个输入向量中选择128位块。 |
_mm_permutevar_ps/pd | 根据整数向量中的位从输入向量中选择元素。 |
_mm256_permutevar_ps/pd | 根据整数向量中的位从输入向量中选择元素。 |
_mm256_permutevar8x32_ps | 使用整数向量中的索引选择32位元素(浮点)。 |
_mm256_permutevar8x32_epi32 | 使用整数向量中的索引选择32位元素(整数)。 |
想要使用SSE指令,则需要包含对应的头文件:
#include <mmintrin.h> //mmx
#include <xmmintrin.h> //sse
#include <emmintrin.h> //sse2
#include <pmmintrin.h> //sse3