AVX/AVX2/SSE/SSE2 指令集
数据类型
数据类型 | 描述 |
---|---|
__m128 | 包含 4 个 float 类型数字的向量 |
__m128d | 包含 2 个 double 类型数字的向量 |
__m128i | 包含若干整形数字的向量 |
__m256 | 包含 8 个 float 类型数字的向量 |
__m256d | 包含 4 个 float 类型数字的向量 |
__m256i | 包含若干整形数字的向量 |
- 每一种类型,2 个下划线开头,接着一个 m,然后是 vector 的长度
- 若向量类型是 d 结尾,则向量存的 double 类型的数字。若无后缀则为 float 类型的数字。
- 整型的向量可以包含各种类型的整型数,如 char,short,unsigned long long。也即, __m256i 可以包含 32 个 char,16 个 short,8 个 int,4 个 long 类型。这些整型数可以是有符号和无符号类型。
函数名约定
_mm<bit_width>_<name>_<data_type>
<bit_width>
:向量长度,对于 128 位向量,参数为空,256 位向量,参数为 256<name>
:内联函数的算数操作简述<data_type>
:函数主参数的数据类型p/s
:分别为packed
和scalar
。packed 指令是对整个向量暂存器的所有数据都进行计算。而 scalar 只计算向量暂存器的低位中的数据进行计算。s/d
:s 为 float 类型,d 为 double 类型
ps:包含 float 类型的向量
pd:包含 double 类型的向量
epi8/epi16/epi32/epi64:包含 8 位/16 位/32 位/64 位的有符号整数
epu8/epu16/epu32/epu64:包含 8 位/16 位/32 位/64 位的无符号整数
si128/si256:未指定的 128 位或者 256 位向量
m128/m128i/m128d/m256/m256i/m256d:当输入向量类型与返回向量的类型不同时,标识输入向量类型
示例 1: _mm256_srlv_epi64
,即使不知道 srlv
的含义, _mm256
前缀说明该函数返回一个256-bit向量,后缀 _epi64
表示参数包含多个64-bit整型数。
示例 2: _mm_testnzc_ps
,其中 _mm
意味着该函数返回一个128-bit向量,后缀 ps
表示该参数包含 float 类型。
写一个 AVX 程序
首先需要包含 immintrin.h
头文件。
hello_avx.cpp
#include <immintrin.h>
#include <isotream>
using namespace std;
int main(){
// Initialize the two argument vectors
__m256 evens = _mm256_set_ps(2.0,4.0,6.0,8.0,10.0,12.0,14.0,16.0);
__m256 odds = _mm256_set_ps(1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0);
// Compute the difference between the two vectors
__m256 result = _mm256_sub_ps(evens, odds);
// Show the elements of the result vector
float *f = (float*)&result;
cout << f[0] << f[0] << f[0] << f[0] << f[0] << f[0] << f[0] << f[0] << endl;
return 0;
}
函数初始化
标量初始化函数
数据类型 | 描述 |
---|---|
_mm256_setzero_ps/pd | 返回一个全 0 的 float/double 类型向量 |
_mm256_setzero_si256 | 返回一个全 0 的整型向量 |
_mm256_set1_ps/pd | 用一个 float 类型数填充向量 |
_mm256_set1_epi8/epi16/epi32/epi64x | 用整型数填充向量 |
_mm256_set_epi8/epi16/epi32/epi64x | 用一个整形数初始化向量 |
_mm256_set_ps/pd | 用 8 个 float 或 4 个 double 类型数字初始化向量 |
_mm256_set_m128/m128d/m128i | 用 2 个 128 位的向量初始化一个 256 位向量 |
_mm256_setr_ps/pd | 用 8 个 float 或者 4 个 double 的转置顺序初始化向量 |
_mm256_setr_epi8/epi16/epi32/epi64x | 用若干个整形数的转置顺序初始化向量 |
setzero
#include <iostream>
#include <immintrin.h>
using namespace std;
int setzero() {
//单精度
__m256 float_vec = _mm256_setzero_ps();
float *flo = (float*)&float_vec;
printf("float:\t%f, %f, %f, %f, %f, %f, %f, %f\n", flo[0], flo[1], flo[2], flo[3], flo[4], flo[5], flo[6], flo[7]);
//双精度
__m256d double_vec = _mm256_setzero_pd();
double *dou = (double*)&double_vec;
printf("double:\t%lf, %lf, %lf, %lf\n", dou[0], dou[1], dou[2], dou[3]);
//整型
__m256i int_vec = _mm256_setzero_si256();
int* i = (int*)&int_vec;
printf("int:\t%d, %d, %d, %d, %d, %d, %d, %d\n", i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]);
system("pause");
return 0;
}
输出:
float: 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000
double: 0.000000, 0.000000, 0.000000, 0.000000
int: 0, 0, 0, 0, 0, 0, 0, 0
set1
#include <iostream>
#include <immintrin.h>
using namespace std;
int set1() {
//单精度
__m256 float_vec = _mm256_set1_ps(1.0);
float *flo = (float*)&float_vec;
printf("float:\t\t%f, %f, %f, %f, %f, %f, %f, %f\n", flo[0], flo[1], flo[2], flo[3], flo[4], flo[5], flo[6], flo[7]);
//双精度
__m256d double_vec = _mm256_set1_pd(2.0);
double *dou = (double*)&double_vec;
printf("double:\t\t%lf, %lf, %lf, %lf\n", dou[0], dou[1], dou[2], dou[3]);
//8-bit 整型
__m256i char_vec = _mm256_set1_epi8(3);
char* c = (char*)&char_vec;
printf("char:\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15], c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23], c[24], c[25], c[26], c[27], c[28], c[29], c[30], c[31]);
//16-bit 整型
__m256i short_vec = _mm256_set1_epi16(4);
short *sho = (short*)&short_vec;
printf("short:\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", sho[0], sho[1], sho[2], sho[3], sho[4], sho[5], sho[6], sho[7], sho[8], sho[9], sho[10], sho[11], sho[12], sho[13], sho[14], sho[15]);
//32-bit 整型
__m256i int_vec = _mm256_set1_epi32(5);
int *i = (int*)&int_vec;
printf("int:\t\t%d, %d, %d, %d, %d, %d, %d, %d\n", i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]);
//64-bit 整数
__m256i long_vec = _mm256_set1_epi64x(6);
long long *lo = (long long*)&long_vec;
printf("long long:\t%lld, %lld, %lld, %lld\n", lo[0], lo[1], lo[2], lo[3]);
system("pause");
return 0;
}
输出:
float: 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000
double: 2.000000, 2.000000, 2.000000, 2.000000
char: 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
short: 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
int: 5, 5, 5, 5, 5, 5, 5, 5
long long: 6, 6, 6, 6
set
#include <iostream>
#include <immintrin.h> //AVX/AVX2
#include <xmmintrin.h> //SSE
#include <emmintrin.h> //SSE2
using namespace std;
int main() {
//单精度
__m256 float_vec = _mm256_set_ps(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
float *flo = (float *)&float_vec;
printf("float:\t\t%f, %f, %f, %f, %f, %f, %f, %f\n", flo[0], flo[1], flo[2], flo[3], flo[4], flo[5], flo[6], flo[7]);
//双精度
__m256d double_vec = _mm256_set_pd(9.0, 10.0, 11.0, 12.0);
double *dou = (double*)&double_vec;
printf("double:\t\t%lf, %lf, %lf, %lf\n", dou[0], dou[1], dou[2], dou[3]);
//8-bit 整型
__m256i char_vec = _mm256_set_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
char *c = (char*)&char_vec;
printf("char:\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15], c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23], c[24], c[25], c[26], c[27], c[28], c[29], c[30], c[31]);
//16-bit 整型
__m256i short_vec = _mm256_set_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
short *sho = (short *)&short_vec;
printf("short:\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", sho[0], sho[1], sho[2], sho[3], sho[4], sho[5], sho[6], sho[7], sho[8], sho[9], sho[10], sho[11], sho[12], sho[13], sho[14], sho[15]);
//32-bit 整型
__m256i int_vec = _mm256_set_epi32(1, 2, 3, 4, 5, 6, 7, 8);
int *i = (int*)&int_vec;
printf("int:\t\t%d, %d, %d, %d, %d, %d, %d, %d\n", i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]);
//64-bit 整型
__m256i long_vec = _mm256_set_epi64x(9, 10, 11, 12);
long long *lo = (long long*)&long_vec;
printf("long long:\t%lld, %lld, %lld, %lld\n", lo[0], lo[1], lo[2], lo[3]);
//从 128-bit 单精度向量初始化值
__m128 float_vec_128_0 = _mm_set_ps(1.0, 2.0, 3.0, 4.0);
__m128 float_vec_128_1 = _mm_set_ps(5.0, 6.0, 7.0, 8.0);
__m256 float_vec_256 = _mm256_set_m128(float_vec_128_1, float_vec_128_0);
float *flo_256 = (float*)&float_vec_256;
printf("float:\t\t%f, %f, %f, %f, %f, %f, %f, %f\n", flo_256[0], flo_256[1], flo_256[2], flo_256[3], flo_256[4], flo_256[5], flo_256[6], flo_256[7]);
//从 128-bit 双精度向量初始化值
__m128d double_vec_128_0 = _mm_set_pd(9.0, 10.0);
__m128d double_vec_128_1 = _mm_set_pd(11.0, 12.0);
__m256d double_vec_256 = _mm256_set_m128d(double_vec_128_1, double_vec_128_0);
double *dou_256 = (double*)&double_vec_256;
printf("double:\t\t%lf, %lf, %lf, %lf\n", dou_256[0], dou_256[1], dou_256[2], dou_256[3]);
//从 128-bit 整型向量初始化值
__m128i int_vec_128_0 = _mm_set_epi32(1, 2, 3, 4);
__m128i int_vec_128_1 = _mm_set_epi32(5, 6, 7, 8);
__m256i int_vec_256 = _mm256_set_m128i(int_vec_128_1, int_vec_128_0);
int *i_256 = (int*)&int_vec_256;
printf("int:\t\t%d, %d, %d, %d, %d, %d, %d, %d\n", i_256[0], i_256[1], i_256[2], i_256[3], i_256[4], i_256[5], i_256[6], i_256[7]);
system("pause");
return 0;
}
输出:
float: 8.000000, 7.000000, 6.000000, 5.000000, 4.000000, 3.000000, 2.000000, 1.000000
double: 12.000000, 11.000000, 10.000000, 9.000000
char: 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
short: 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
int: 8, 7, 6, 5, 4, 3, 2, 1
long long: 12, 11, 10, 9
float: 4.000000, 3.000000, 2.000000, 1.000000, 8.000000, 7.000000, 6.000000, 5.000000
double: 10.000000, 9.000000, 12.000000, 11.000000
int: 4, 3, 2, 1, 8, 7, 6, 5
setr
#include <iostream>
#include <immintrin.h> //AVX/AVX2
#include <xmmintrin.h> //SSE
#include <emmintrin.h> //SSE2
using namespace std;
int main() {
//单精度
__m256 float_vec = _mm256_setr_ps(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
float* flo = (float*)&float_vec;
printf("float:\t\t%f, %f, %f, %f, %f, %f, %f, %f\n", flo[0], flo[1], flo[2], flo[3], flo[4], flo[5], flo[6], flo[7]);
//双精度
__m256d double_vec = _mm256_setr_pd(9.0, 10.0, 11.0, 12.0);
double* dou = (double*)&double_vec;
printf("double:\t\t%lf, %lf, %lf, %lf\n", dou[0], dou[1], dou[2], dou[3]);
//32-bit 整型
__m256i int_vec = _mm256_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8);
int* i = (int*)&int_vec;
printf("int:\t\t%d, %d, %d, %d, %d, %d, %d, %d\n", i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]);
//64-bit 整型
__m256i long_vec = _mm256_setr_epi64x(9, 10, 11, 12);
long long* lo = (long long*)&long_vec;
printf("long long:\t%d, %d, %d, %d\n", lo[0], lo[1], lo[2], lo[3]);
//16-bit 整型
__m256i short_vec = _mm256_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
short* sho = (short*)&short_vec;
printf("short:\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", sho[0], sho[1], sho[2], sho[3], sho[4], sho[5], sho[6], sho[7], sho[8], sho[9], sho[10], sho[11], sho[12], sho[13], sho[14], sho[15]);
//8-bit 整型
__m256i char_vec = _mm256_setr_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32);
char* c = (char*)&char_vec;
printf("char:\t\t%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15], c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23], c[24], c[25], c[26], c[27], c[28], c[29], c[30], c[31]);
// Set value from 128-bit single-precision vectors
__m128 float_vec_128_0 = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
__m128 float_vec_128_1 = _mm_setr_ps(5.0, 6.0, 7.0, 8.0);
__m256 float_vec_256 = _mm256_setr_m128(float_vec_128_1, float_vec_128_0);
float* flo_256 = (float*)&float_vec_256;
printf("float:\t\t%f, %f, %f, %f, %f, %f, %f, %f\n", flo_256[0], flo_256[1], flo_256[2], flo_256[3], flo_256[4], flo_256[5], flo_256[6], flo_256[7]);
// Set value from 128-bit double-precision vectors
__m128d double_vec_128_0 = _mm_setr_pd(9.0, 10.0);
__m128d double_vec_128_1 = _mm_setr_pd(11.0, 12.0);
__m256d double_vec_256 = _mm256_setr_m128d(double_vec_128_1, double_vec_128_0);
double* dou_256 = (double*)&double_vec_256;
printf("double:\t\t%lf, %lf, %lf, %lf\n", dou_256[0], dou_256[1], dou_256[2], dou_256[3]);
// Set value from 128-bit integer vectors
__m128i int_vec_128_0 = _mm_setr_epi32(1, 2, 3, 4);
__m128i int_vec_128_1 = _mm_setr_epi32(5, 6, 7, 8);
__m256i int_vec_256 = _mm256_setr_m128i(int_vec_128_1, int_vec_128_0);
int* i_256 = (int*)&int_vec_256;
printf("int:\t\t%d, %d, %d, %d, %d, %d, %d, %d\n", i_256[0], i_256[1], i_256[2], i_256[3], i_256[4], i_256[5], i_256[6], i_256[7]);
system("pause");
return 0;
}
输出:
float: 1.000000, 2.000000, 3.000000, 4.000000, 5.000000, 6.000000, 7.000000, 8.000000
double: 9.000000, 10.000000, 11.000000, 12.000000
int: 1, 2, 3, 4, 5, 6, 7, 8
long long: 9, 10, 11, 12
short: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
char: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
float: 5.000000, 6.000000, 7.000000, 8.000000, 1.000000, 2.000000, 3.000000, 4.000000
double: 11.000000, 12.000000, 9.000000, 10.000000
int: 5, 6, 7, 8, 1, 2, 3, 4
从内存中加载数据
数据类型 | 描述 |
---|---|
_mm256_load_ps/pd | 从对齐的内存地址加载 float/double 向量 |
_mm256_load_si256 | 从对齐的内存地址加载整形向量 |
_mm256_loadu_ps/pd | 从未对齐的内存地址加载浮点向量 |
_mm256_loadu_si256 | 从未对齐的内存地址加载整形向量 |
_mm_maskload_ps/pd | 根据掩码加载 128 位浮点向量的部分 |
_mm256_maskload_ps/pd | 根据掩码加载 256 位浮点向量的部分 |
_mm_maskload_epi32/64(只在 avx2 中支持) | 根据掩码加载 128 位整形向量的部分 |
_mm256_maskload_epi32/64(只在 avx2 中支持) | 根据掩码加载 256 位整形向量的部分 |
调用:
float *aligned_floats = (float*)aligned_alloc(32, 64*sizeof(float));
// Initialize data
__m256 vec = _mm256_load_ps(aligned_floats);
float *unaligned_floats = (float*)malloc(64*sizeof(float));
// Initialize data
__m256 vec = _mm256_loadu_ps(unaligned_floats);
若要处理的 float 数组长度为 11 不能被 8 整除。那么最后 5 个浮点数需要置 0。或者使用上表中的 _maskload_
。
_maskload_
函数有两个参数:内存地址、相同元素数目的整型向量作为返回。整型向量中每个元素的最高位为 1,返回的向量中对应元素是从内存中读取的。若整型向量中每个元素最高位为 0,则返回的向量对应元素置 0。
mask_load.cpp
读入 8 个 int 到向量,最后 3 个应该置 0。使用了 _mm256_maskload_epi32
,第二个参数应为 __m256i
mask 向量。该 mask 向量包含 5 个整型,其最高位是 1,剩下 3 个整型的最高位置 0.
#include <immintrin.h>
#include <iostram>
using namespace std;
int main(){
int int_array[8] = {100,200,300,400,500,600,700,800};
// Initialize the mask vector
__m256i mask = _mm256_setr_epi32(-20, -70, -48, -9, -100, 3, 5, 8);
// or
__m256i mask_1 = _mm256_set_epi32(3,5,8,-100,-9,-48,-70,-20);
// Selectively load data to the vector
__m256i result = _mm256_maskload_epi32(int_array, mask);
// Selectively load data into reuslt vector
int *res = (int*)&result;
printf("%d %d %d %d %d %d %d %d\n",
res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7]);
return 0;
}
输出:
100 200 300 400 500 0 0 0
说明:
- 负整型的最高位总为 1。所以 mask vector 选用 5 个负数,3 个正数
_mm256_maskload_epi32
是 AVX2 函数,因此用 gcc 编译加-mavx2
参数
算术本质
加减法
数据类型 | 描述 |
---|---|
_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 | 水平方向上对两个 float 类型向量做加法 |
_mm256_hsub_ps/pd | 垂直方向上最两个 float 类型向量做减法 |
(2)_mm256_hadd_epi16/32 | 水平方向上对两个整形向量做加法 |
(2)_mm256_hsub_epi16/32 | 水平方向上最两个整形向量做减法 |
(2)_mm256_hadds_epi16 | 对两个包含 short 类型的向量做加法且考虑内存饱和的问题 |
(2)_mm256_hsubs_epi16 | 对两个包含 short 类型的向量做减法且考虑内存饱和的问题 |
_mm256_addsub_ps/pd | 加上和减去两个 float 类型的向量、(在偶数位置减去,奇数位置加上,获最后得目标向量。) |
前面有一个(2),代表函数只在 AVX2 中支持。
_add_/_sub_
函数和 _adds_/_subs_
函数的区别在于。 s
表示饱和,即当结果需要更多的内存来保存结果也能存下。
例 1:一个向量包含 signed bytes,因此每个元素最大值是 127(0x7F).若有 98 加 85 的操作,结果是 183(0xB7).
- 若用
_mm256_add_epi8
,溢出部分会被忽略存储结果为**-73(0xB7)** - 若用
_mm256_adds_epi8
,结果会被限制在最大值即127(0x7F)
例 2:两个 signed short 整型向量,最小值为-32768。若计算-18000-19000,结果为-37000(0xFFFF6F78 as a 32-bit integer)
- 若用
_mm256_sub_epi16
,溢出会被忽略存储结果为 28536(0x6F78) - 若用
_mm256_subs_epi16
,结果会被限制在最小值**-32768(0x8000)**
_hadd_/_hsub_
函数为水平加减。即向量相邻元素做加减,而不是向量间做加减。
而在水平方向上做加减法的意思如下图:
乘除法
数据类型 | 描述 |
---|---|
_mm256_mul_ps/pd | 对两个 float 类型的向量进行相乘 |
(2)_mm256_mul_epi32 (2)_mm256_mul_epu32 | 将包含 32 位整数的向量的最低四个元素相乘 |
(2)_mm256_mullo_epi16/32 | Multiply integers and store low halves |
(2)_mm256_mulhi_epi16 (2)_mm256_mulhi_epu16 | Multiply integers and store high halves |
(2)_mm256_mulhrs_epi16 | Multiply 16-bit elements to form 32-bit elements |
_mm256_div_ps/pd | 对两个 float 类型的向量进行想除 |
复合运算
数据类型 | 描述 |
---|---|
(2)_mm_fmadd_ps/pd/ (2)_mm256_fmadd_ps/pd | 将两个向量相乘,再将积加上第三个。(res=a*b+c) |
(2)_mm_fmsub_ps/pd/ (2)_mm256_fmsub_ps/pd | 将两个向量相乘,然后从乘积中减去一个向量。(res=a*b-c) |
(2)_mm_fmadd_ss/sd | 将向量中最低的元素相乘并相加(res[0]=a[0]*b[0]+c[0]) |
(2)_mm_fmsub_ss/sd | 将向量中最低的元素相乘并相减(res[0]=a[0]*b[0]-c[0]) |
(2)_mm_fnmadd_ps/pd (2)_mm256_fnmadd_ps/pd | 将两个向量相乘,并将负积加到第三个。(res = -(a * b) + c) |
(2)_mm_fnmsub_ps/pd/ (2)_mm256_fnmsub_ps/pd | 将两个向量相乘,并将负积加到第三个 (res = -(a * b) - c) |
(2)_mm_fnmadd_ss/sd | 将两个向量的低位相乘,并将负积加到第三个向量的低位。(res[0] = -(a[0] * b[0]) + c[0]) |
(2)_mm_fnmsub_ss/sd | 将最低的元素相乘,并从求反的积中减去第三个向量的最低元素。(res[0] = -(a[0] * b[0]) - c[0]) |
(2)_mm_fmaddsub_ps/pd/ (2)_mm256_fmaddsub_ps/pd | 将两个矢量相乘,然后从乘积中交替加上和减去(res=a*b+/-c) |
(2)_mm_fmsubadd_ps/pd/ (2)_mmf256_fmsubadd_ps/pd | 将两个向量相乘,然后从乘积中交替地进行减法和加法(res=a*b-/+c)(奇数次方,偶数次方) |
unpack、permute、shuffle、blend
unpack
permute
数据类型 | 描述 |
---|---|
_mm_permute_ps/pd _mm256_permute_ps/pd | 根据 8 位控制值从输入向量中选择元素 |
(2)_mm256_permute4x64_pd/ (2)_mm256_permute4x64_epi64 | 根据 8 位控制值从输入向量中选择 64 位元素 |
_mm256_permute2f128_ps/pd | 基于 8 位控制值从两个输入向量中选择 128 位块 |
_mm256_permute2f128_si256 | 基于 8 位控制值从两个输入向量中选择 128 位块 |
_mm_permutevar_ps/pd _mm256_permutevar_ps/pd | 根据整数向量中的位从输入向量中选择元素 |
(2)_mm256_permutevar8x32_ps (2)_mm256_permutevar8x32_epi32 | 使用整数向量中的索引选择 32 位元素(浮点和整数) |
shuffle
数据类型 | 描述 |
---|---|
_mm256_shuffle_ps/pd | 根据 8 位值选择浮点元素 |
_mm256_shuffle_epi8/ _mm256_shuffle_epi32 | 根据 8 位值选择整数元素 |
(2)_mm256_shufflelo_epi16/ (2)_mm256_shufflehi_epi16 | 基于 8 位控制值从两个输入向量中选择 128 位块 |
对于_mm256_shuffle_pd,只使用控制值的高 4 位。如果输入向量包含 int 或 float,则使用所有控制位。对于 _mm256_shuffle_ps,前两对位从第一个矢量中选择元素,第二对位从第二个矢量中选择元素。
blend
Reference
https://software.intel.com/sites/landingpage/IntrinsicsGuide/
https://software.intel.com/en-us/articles/introduction-to-intel-advanced-vector-extensions/
https://www.codeproject.com/Articles/874396/Crunching-Numbers-with-AVX-and-AVX
https://blog.triplez.cn/avx-avx2-learning-notes/#Shuffling
https://github.com/Triple-Z/AVX-AVX2-Example-Code
https://blog.csdn.net/just_sort/article/details/94393506
https://www.jianshu.com/p/64ef4d304e17
https://www.officedaytime.com/tips/simd.html
https://github.com/microsoft/SPTAG/blob/master/AnnService/inc/Core/Common/DistanceUtils.h
CPU 指令集介绍
https://blog.csdn.net/gengshenghong/article/details/7006817
在 C/C++代码中使用 SSE 等指令集的指令(1) 介绍
https://blog.csdn.net/gengshenghong/article/details/7007100
在 C/C++代码中使用 SSE 等指令集的指令(2) 参考手册
https://blog.csdn.net/gengshenghong/article/details/7008682
在 C/C++代码中使用 SSE 等指令集的指令(3)SSE 指令集基础
https://blog.csdn.net/gengshenghong/article/details/7008704
在 C/C++代码中使用 SSE 等指令集的指令(4)SSE 指令集 Intrinsic 函数使用
https://blog.csdn.net/gengshenghong/article/details/7010615
在 C/C++代码中使用 SSE 等指令集的指令(5)SSE 进行加法运算简单的性能测试
https://blog.csdn.net/gengshenghong/article/details/7011373
Writing C++ Wrappers for SIMD Intrinsics (1-5)
https://johanmabille.github.io/blog/2014/10/09/writing-c-plus-plus-wrappers-for-simd-intrinsics-1/
https://johanmabille.github.io/blog/2014/10/10/writing-c-plus-plus-wrappers-for-simd-intrinsics-2/
https://johanmabille.github.io/blog/2014/10/10/writing-c-plus-plus-wrappers-for-simd-intrinsics-3/
https://johanmabille.github.io/blog/2014/10/13/writing-c-plus-plus-wrappers-for-simd-intrinsics-4/
https://johanmabille.github.io/blog/2014/10/25/writing-c-plus-plus-wrappers-for-simd-intrinsics-5/
Performance Considerations About SIMD Wrappers
https://johanmabille.github.io/blog/2014/11/20/performance-considerations-about-simd-wrappers/
Aligned Memory Allocator
https://johanmabille.github.io/blog/2014/12/06/aligned-memory-allocator/
Ubuntu SSE 指令集 编程实例—复数乘法与共轭乘法
https://blog.csdn.net/jxwxg/article/details/53091376
AVX2 整数向量运算
https://blog.csdn.net/tigerisland45/article/details/54671536
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Delaunay 三角剖分
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论