文章目录
什么是SIMD
SIMD是什么意思
SIMD 是 Single Instruction, Multiple Data 的缩写,意思是单指令多数据,是一种在计算机或微处理器中实现并行处理的设计方式,它可以同时对多个数据执行相同的操作,提高处理效率。SIMD 也有时被称为向量运算或向量处理,在图像处理应用以及多媒体处理上应用非常多。
SIMD指令集有哪些?
SIMD指令集有很多种,不同的CPU架构有不同的SIMD指令集。
以x86架构为例,常见的SIMD指令集有:
MMX:MultiMedia eXtensions,是Intel在1997年推出的第一个SIMD指令集,主要使用64位的MM0~MM7寄存器34。
SSE:Streaming SIMD Extensions,是Intel在1999年推出的一系列SIMD指令集,主要使用128位的XMM0~XMM15寄存器,分为SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2等版本154。
AVX:Advanced Vector Extensions,是Intel在2011年推出的一系列SIMD指令集,主要使用256位的YMM0~YMM15寄存器,分为AVX,AVX2,AVX-512等版本54。
ARM的NEON。
这些指令集的发展过程?
SIMD指令集的发展历程可以大致分为以下几个阶段:
年份 | 指令集 |
---|---|
1997 | Intel推出了第一个SIMD指令集——MultiMedia eXtensions(MMX),主要用于图像、音频、视频等多媒体处理,使用了8个64位的MM0~MM7寄存器 |
1999 | Intel在Pentium III对SIMD做了扩展,名为Streaming SIMD eXtensions(SSE),增加了8个128位的XMM0~XMM7寄存器,以及一些新的指令,主要用于浮点数的运算 |
2001 | Intel在Pentium 4中推出了SSE2,扩展了XMM寄存器的数量到16个,并且增加了对整数的支持,以及一些新的指令 |
2004 | Intel在Pentium 4中推出了SSE3,增加了一些新的指令,主要用于改善线程切换和循环展开等 |
2006 | Intel在Core 2 Duo中推出了Supplemental SSE3(SSSE3),增加了一些新的指令,主要用于加密解密和字符串处理等 |
2008 | Intel在Core i7中推出了SSE4,分为SSE4.1和SSE4.2,增加了一些新的指令,主要用于视频编解码和文本处理等 |
2011 | Intel在Sandy Bridge中推出了Advanced Vector Extensions(AVX),扩展了XMM寄存器的大小到256位,并且增加了一些新的指令,主要用于浮点数的运算 |
2013 | Intel在Haswell中推出了AVX2,扩展了对整数的支持,并且增加了一些新的指令,主要用于矩阵乘法和混合运算等 |
2015 | Intel在Broadwell中推出了Advanced Vector Extensions 512(AVX-512),扩展了XMM寄存器的大小到512位,并且增加了一些新的指令,主要用于科学计算和机器学习等 |
AVX2
immintrin.h
c++中提供了库函数,在immintrin.h头文件中定义,把汇编指令进行了打包,便于编写SIMD函数。
immintrin全称是immediate intrinsics,意为直接的内部函数。
immintrin.h头文件是AVX指令集的头文件,它包含了之前的所有SIMD指令集的头文件,比如MMX,SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2等12。
变量
主要变量:
__m256,是一个256位的向量,可以存储8个单精度浮点数,比如__m256 a = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f}。
__m256d,是一个256位的向量,可以存储4个双精度浮点数,比如__m256d b = {1.0, 2.0, 3.0, 4.0}。
__m256i,是一个256位的向量,可以存储8个32位整数,或者4个64位整数,或者16个16位整数,或者32个8位整数,比如__m256i c = {1, 2, 3, 4, 5, 6, 7, 8}。
__m128,是一个128位的向量,可以存储4个单精度浮点数,或者2个双精度浮点数,或者4个32位整数,或者2个64位整数,或者8个16位整数,或者16个8位整数,比如__m128 d = {1.0f, 2.0f, 3.0f, 4.0f}。
__m128d,是一个128位的向量,可以存储2个双精度浮点数,或者4个32位整数,或者2个64位整数,或者8个16位整数,或者16个8位整数,比如__m128d e = {1.0, 2.0}。
__m128i,是一个128位的向量,可以存储4个32位整数,或者2个64位整数,或者8个16位整数,或者16个8位整数,比如__m128i f = {1, 2, 3, 4}。
命名规则:
_ + _ + m + 位数 + [类型]
函数
函数类型
类型 | 功能 |
---|---|
加载和存储函数 | 用于将内存中的数据加载到向量变量中,或者将向量变量中的数据存储到内存中 |
算术函数 | 用于对向量变量中的元素进行加减乘除等基本运算 |
逻辑函数 | 用于对向量变量中的元素进行按位与或非等逻辑运算 |
比较函数 | 用于对向量变量中的元素进行大小或相等等比较 |
转换函数 | 用于将向量变量中的元素转换为不同的类型 |
置换函数 | 用于对向量变量中的元素进行重新排列或复制 |
广播函数 | 用于将向量变量中的某个元素复制到其他位置 |
混合函数 | 用于将不同的向量变量中的元素按照一定的规则组合起来 |
缩减函数 | 用于将向量变量中的元素进行求和或求最大最小值等操作 |
其他函数 | 用于实现一些特殊的功能,比如_mm256_extractf128_pd,_mm256_zeroall等。 |
加载和存储函数
函数名 | 函数解释 |
---|---|
_mm256_load_pd | 用于将内存中的4个连续的双精度浮点数加载到一个__m256d变量中,要求内存地址对齐。 |
_mm256_loadu_pd | 用于将内存中的4个连续的双精度浮点数加载到一个__m256d变量中,不要求内存地址对齐。 |
_mm256_load_ps | 用于将内存中的8个连续的单精度浮点数加载到一个__m256变量中,要求内存地址对齐。 |
_mm256_loadu_ps | 用于将内存中的8个连续的单精度浮点数加载到一个__m256变量中,不要求内存地址对齐。 |
_mm256_load_si256 | 用于将内存中的256位整数加载到一个__m256i变量中,要求内存地址对齐。 |
_mm256_loadu_si256 | 用于将内存中的256位整数加载到一个__m256i变量中,不要求内存地址对齐。 |
_mm256_store_pd | 用于将一个__m256d变量中的4个双精度浮点数存储到内存中,要求内存地址对齐。 |
_mm256_storeu_pd | 用于将一个__m256d变量中的4个双精度浮点数存储到内存中,不要求内存地址对齐。 |
_mm256_store_ps | 用于将一个__m256变量中的8个单精度浮点数存储到内存中,要求内存地址对齐。 |
_mm256_storeu_ps | 用于将一个__m256变量中的8个单精度浮点数存储到内存中,不要求内存地址对齐。 |
_mm256_store_si256 | 用于将一个__m256i变量中的256位整数存储到内存中,要求内存地址对齐。 |
_mm256_storeu_si256 | 用于将一个__m256i变量中的256位整数存储到内存中,不要求内存地址对齐。 |
函数名理解:
|函数名分解|解释|
|_mm|内部指令函数,用于操作多媒体指令集(MMX),用于直接操作寄存器或内存的数据|
|256|用于处理256位的数据|
|load|加载函数,将内存中的数据加载到寄存器中|
|u|这是一个不对齐函数 unaligned,不要求地址对齐|
|ps|这是一个单精度浮点数,packed single|
si:signed int
ps: packed single
pd: packed double
算术函数
函数名 | 函数解释 |
---|---|
_mm256_add_epi8/16/32/64 | 这些函数可以对两个 __m256i 类型的变量进行 8/16/32/64 位的整数加法 |
_mm256_sub_epi8/16/32/64 | 这些函数可以对两个 __m256i 类型的变量进行 8/16/32/64 位的整数减法 |
_mm256_mul_epi32/lo_epi32/lo_epi16 | 这些函数可以对两个 __m256i 类型的变量进行 32/32/16 位的整数乘法 |
_mm256_div_epi8/16/32/64 | 这些函数可以对两个 __m256i 类型的变量进行 8/16/32/64 位的整数除法 |
_mm256_add_ps/pd | 这些函数可以对两个 __m256/ __m256d 类型的变量进行单精度/双精度的浮点数加法 |
_mm256_sub_ps/pd | 这些函数可以对两个 __m256/ __m256d 类型的变量进行单精度/双精度的浮点数减法 |
_mm256_mul_ps/pd | 这些函数可以对两个 __m256/ __m256d 类型的变量进行单精度/双精度的浮点数乘法 |
_mm256_div_ps/pd | 这些函数可以对两个 __m256/ __m256d 类型的变量进行单精度/双精度的浮点数除法 |
ep:扩展精度(extended precision)的缩写,它是一种表示高精度的数据的方法
epi:扩展精度的整数
epu:扩展精度的无符号整数
逻辑函数
函数名 | 函数解释 |
---|---|
_mm256_and_si256 | 这个函数可以对两个 __m256i 类型的变量进行按位与(bitwise and)运算 |
_mm256_or_si256 | 这个函数可以对两个 __m256i 类型的变量进行按位或(bitwise or)运算 |
_mm256_xor_si256 | 这个函数可以对两个 __m256i 类型的变量进行按位异或(bitwise xor)运算 |
_mm256_andnot_si256 | 这个函数可以对两个 __m256i 类型的变量进行按位与非(bitwise andnot)运算 |
_mm256_testz_si256 | 这个函数可以对两个 __m256i 类型的变量进行按位测试(bitwise test),并返回一个布尔值(boolean value) |
按位测试的意思是,如果两个变量的所有位都为 0,那么返回 1,否则返回 0。这个函数可以用来判断两个变量是否相等,或者是否有某些位被设置
比较函数
函数名 | 函数解释 |
---|---|
_mm256_cmp_ps | 比较两个256位的单精度浮点向量,根据指定的条件返回一个掩码向量。 |
_mm256_cmp_pd | 比较两个256位的双精度浮点向量,根据指定的条件返回一个掩码向量。 |
_mm256_cmpeq_epi8 | 比较两个256位的8位整数向量,返回一个包含相等比较结果的向量。 |
_mm256_cmpeq_epi16 | 比较两个256位的16位整数向量,返回一个包含相等比较结果的向量。 |
_mm256_cmpeq_epi32 | 比较两个256位的32位整数向量,返回一个包含相等比较结果的向量。 |
_mm256_cmpeq_epi64 | 比较两个256位的64位整数向量,返回一个包含相等比较结果的向量。 |
_mm256_cmpgt_epi8 | 比较两个256位的8位整数向量,返回一个包含大于比较结果的向量。 |
_mm256_cmpgt_epi16 | 比较两个256位的16位整数向量,返回一个包含大于比较结果的向量。 |
_mm256_cmpgt_epi32 | 比较两个256位的32位整数向量,返回一个包含大于比较结果的向量。 |
_mm256_cmpgt_epi64 | 比较两个256位的64位整数向量,返回一个包含大于比较结果的向量。 |
_mm256_cmplt_epi8 | 比较两个256位的8位整数向量,返回一个包含小于比较结果的向量。 |
_mm256_cmplt_epi16 | 比较两个256位的16位整数向量,返回一个包含小于比较结果的向量。 |
_mm256_cmplt_epi32 | 比较两个256位的32位整数向量,返回一个包含小于比较结果的向量。 |
_mm256_cmplt_epi64 | 比较两个256位的64位整数向量,返回一个包含小于比较结果的向量。 |
eq:表示相等的比较条件
neq:表示不相等的比较条件
le:表示小于等于的比较条件
ge:表示大于等于的比较条件
gt:表示大于的比较条件
lt:less than 表示小于的比较条件
转换函数
函数名 | 函数解释 |
---|---|
从整数到浮点的转换 | 例如_mm256_cvtepi32_ps可以将一个256位的32位整数向量转换为一个256位的单精度浮点向量。 |
从浮点到整数的转换 | 例如_mm256_cvtps_epi32可以将一个256位的单精度浮点向量转换为一个256位的32位整数向量。 |
从浮点到浮点的转换 | 例如_mm256_cvtpd_ps可以将一个256位的双精度浮点向量转换为一个256位的单精度浮点向量。 |
从整数到整数的转换 | 例如_mm256_cvtepi8_epi16可以将一个256位的8位整数向量转换为一个256位的16位整数向量。 |
从整数到掩码的转换 | 例如_mm256_movemask_epi8可以将一个256位的整数向量转换为一个32位的掩码整数。 |
从掩码到整数的转换 | 例如_mm256_maskz_loadu_epi8可以根据一个32位的掩码整数,从一个地址加载一个256位的8位整数向量。 |
置换函数
函数名 | 函数解释 |
---|---|
单向量置换 | 例如_mm256_permutevar8x32_epi32可以根据一个256位的32位整数向量中的索引,从另一个256位的32位整数向量中选择元素,形成一个新的256位的32位整数向量。 |
双向量置换 | 例如_mm256_permute2x128_si256可以根据一个8位的控制整数,从两个256位的整数向 |
单向量广播 | 例如_mm256_broadcastb_epi8可以将一个8位的整数复制到一个256位的8位整数向量的所有元素中。 |
双向量广播 | 例如_mm256_broadcastsi128_si256可以将一个128位的整数向量复制到一个256位的整数向量的两个子向量中。 |
单向量混合 | 例如_mm256_blend_epi16可以根据一个16位的掩码整数,从两个256位的16位整数向量中选择元素,形成一个新的256位的16位整数向量。 |
双向量混合 | 例如_mm256_blendv_epi8可以根据一个256位的整数向量中的符号位,从两个256位的8位整数向量中选择元素,形成一个新的256位的8位整数向量。 |
广播函数
函数名 | 函数解释 |
---|---|
单向量广播 | 例如_mm256_broadcastb_epi8可以将一个8位的整数复制到一个256位的8位整数向量的所有元素中。 |
双向量广播 | 例如_mm256_broadcastsi128_si256可以将一个128位的整数向量复制到一个256位的整数向量的两个子向量中。 |
单标量广播 | 例如_mm256_broadcastss_ps可以将一个32位的浮点数复制到一个256位的32位浮点数向量的所有元素中。 |
双标量广播 | 例如_mm256_broadcastsd_pd可以将一个64位的浮点数复制到一个256位的64位浮点数向量的两个子向量中。 |
ss是single scalar的缩写,表示单标量,即一个32位的浮点数。
sd是double scalar的缩写,表示一个64位的浮点数
si是integer scalar的缩写,表示一个整数