SSE && AVX 寄存器
SSE 和 AVX 每个都有16个寄存器,SSE 的有 XMM0 ~ XMM15,AVX 有 YMM0 ~ YMM15,XMM都是128 bit的,avx都是 256 bit的
SSE 有三种类型定义 _m128
,__m128d
,__m128i
,float,double,int
AVX 是 __m256
,__m256d
,__m256i
__m128
,__m128d
,__m256
,__m256d
比较简单,里面都是相同的float/double,编程的时候把里面当成float/double的数组基本就可以了,但是__m128i
和__m256i
有点特殊,举个例子就是 __m128
可以看成2个int64_t
或者4个int32_t
或者8个 int16_t
或者16个int8_t
需要用_mm256_extract_epiXX
取出来需要的类型。
__m256 fltx16 = _mm256_set1_ps(3.14f); // Create a vector with all elements equal to 3.14
fltx16[0] = 1.32f;
float f = fltx16[1];
__m256i int32x8 = _mm256_set1_epi32(0x3355ff);
int i = _mm256_extract_epi32(int32x8, 0); // value == 0x003355ff
int16_t i = _mm256_extract_epi32(int32x8, 0) // value == 0x55ff
一些内置函数:
SSE/AVX 指令的格式通常都是这样的:
_<vector_size>_<intrin_op>_<suffix>
对于浮点类型来讲,加减乘除都有对应的向量化函数指令
但是对于整形来说,除法就比较尴尬了,除法一般用libdevide
来实现,另外对于int16来说,溢出表现跟非向量计算的表现不一样。
auto res0 = _mm256_adds_epi8(_mm256_set1_epi8( 100 ), _mm256_set1_epi8( 100 ));
int16_t v = _mm256_extract_epi8(res0, 0); // value == 127
但是还有其他指令,可以处理溢出的情况 (avx2)
auto res0 = _mm256_add_epi8(_mm256_set1_epi8( 100 ), _mm256_set1_epi8( 100 ));
int8_t v = _mm256_extract_epi8(res0, 0); // value == -56
load 和 store
float fary[4];
__m128 f = _mm_loadu_ps(fary);
_mm_storeu_ps(fary, f);
reference
https://software.intel.com/sites/landingpage/IntrinsicsGuide