360精选
CPU依靠指令来计算和控制系统,指令集是指CPU能执行的所有指令的集合,每一类CPU都有其支持的指令集。比如说目前intel和AMD的绝大部分处理器都使用X86指令集,因为它们都源自于X86架构。 但无论CPU有多快,X86指令也只能一次处理一个数据,但这种单指令单数据(SISD)的指令集效率并不高,因此,为了提高CPU的工作效率,需要增加一些特殊的指令满足时代进步的需求,这些新增的指令就构成了扩展指令集。 一条指令操作多个数据(SIMD).是CPU基本指令集的扩展.主要用于提供fine grain parallelism,即小碎数据的并行操作.比如说图像处理。Intel的SIMD指令集有MMX、SSE、SSE2、SSE4指令集,AVX指令集也是Intel的一类SIMD指令集。 AVX指令集是Sandy Bridge和Larrabee架构下的新指令集。AVX是在之前的128位扩展到和256位的单指令多数据流。而Sandy Bridge的单指令多数据流演算单元扩展到256位的同时数据传输也获得了提升,所以从理论上看CPU内核浮点运算性能提升到了2倍。 Intel AVX指令集,在单指令多数据流计算性能增强的同时也沿用了的MMX/SSE指令集。不过和MMX/SSE的不同点在于增强的AVX指令,从指令的格式上就发生了很大的变化。x86(IA-32/Intel 64)架构的基础上增加了prefix(Prefix),所以实现了新的命令,也使更加复杂的指令得以实现,从而提升了x86 CPU的性能。 AVX(Advanced Vector Extensions,高级矢量扩展)指令集借鉴了一些AMD SSE5的设计思路,进行扩展和加强,形成一套新一代的完整SIMD指令集规范。 指令集需要CPU的支持才能执行,在Linux系统下可以执行以下指令查看CPU支持的指令集,而Windows可以使用CPU-Z软件查看。 gcc -march=native -Q --help=target grep march 或 cat /proc/cpuinfo _mmbit_width_name_data_type 函数由_mm开头,后面接上向量长度、操作类型、参数类型: bit_width 表明了向量的位长度,对于128位的向量,这个参数为空,对于256位的向量,这个参数为256。 name描述了内联函数的算术操作。 data_type 标识函数主参数的数据类型,参数含义如下: 1、ps:里面都是float,把32bits当成一个数看 2、pd:里面都是double,把64bits当成一个数看 3、epi8/epi16/epi32/epi64:向量里每个数都是整型,一个整型8bit/16bit/32bit/64bit 4、epu8/epu16/epu32/epu64:向量里每个数都是无符号整型(unsigned),一个整型8bit/16bit/32bit/64bit 5、m128/m128i/m128d/m256/m256i/m256d:输入值与返回类型不同时会出现 ,例如__m256i_mm256_setr_m128i(__m128ilo,__m128ihi),输入两个__m128i向量 ,把他们拼在一起,变成一个__m256i返回 。另外这种结尾只见于load 6、si128/si256:不care向量里到底都是些啥类型,反正128bit/256bit,例如: __m256i _mm_broadcastsi128_si256 (__m128i a) __m256d _mm256_setzero_pd (void) __m256 _mm256_setzero_ps (void) __m256i _mm256_setzero_si256 (void) 用一个标量初始化: __m256i _mm256_set1_epi16 (short a) __m256i _mm256_set1_epi32 (int a) __m256i _mm256_set1_epi64x (long long a) __m256i _mm256_set1_epi8 (char a) __m256d _mm256_set1_pd (double a) __m256 _mm256_set1_ps (float a) 用多个标量初始化: __m256i _mm256_set_epi16 (short e15, short e14, short e13, short e12, short e11, short e10, short e9, short e8, short e7, short e6, short e5, short e4, short e3, short e2, short e1, short e0) __m256i _mm256_set_epi32 (int e7, int e6, int e5, int e4, int e3, int e2, int e1, int e0) __m256i _mm256_set_epi64x (__int64 e3, __int64 e2, __int64 e1, __int64 e0) __m256d _mm256_set_pd (double e3, double e2, double e1, double e0) __m256 _mm256_set_ps (float e7, float e6, float e5, float e4, float e3, float e2, float e1, float e0) __m256i _mm256_set_epi8 (char e31, char e30, char e29, char e28, char e27, char e26, char e25, chare24, char e23, char e22, char e21, char e20, char e19, char e18, char e17, char e16, char e15, char e14, char e13, char e12, char e11, char e10, char e9, char e8, char e7, char e6, char e5, char e4, char e3, char e2, char e1, char e0) 注意形参的顺序,初始位置的值位于最后 用128bit向量初始化: __m256 _mm256_set_m128 (__m128 hi, __m128 lo) __m256d _mm256_set_m128d (__m128d hi, __m128d lo) __m256i _mm256_set_m128i (__m128i hi, __m128i lo) __m256d _mm256_load_pd (double const * mem_addr) __m256 _mm256_load_ps (float const * mem_addr) __m256i _mm256_load_si256 (__m256i const * mem_addr) __m256d _mm256_loadu_pd (double const * mem_addr) __m256 _mm256_loadu_ps (float const * mem_addr) __m256i _mm256_loadu_si256 (__m256i const * mem_addr) 从两个内存地址分别读取至向量的高128bit和低128bit: __m256 _mm256_loadu2_m128 (float const* hiaddr, float const* loaddr) __m256d _mm256_loadu2_m128d (double const* hiaddr, double const* loaddr) __m256i _mm256_loadu2_m128i (__m128i const* hiaddr, __m128i const* loaddr) load和loadu分别对应内存地址的是否对齐,一般使用loadu,否则会出现段错误; 加载整型指针时,需要先进行显式类型转换(const __m256i*)x,否则编译器会报错: int *x = new i[10]{0}; __m256i v1 = _mm256_loadu_si256 ( (const __m256i*)x ); 分别读取/写入的函数都是未对齐形式。
查看更多
没有更多结果了~