向量化计算 2

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

posted @ 2021-03-28 18:17  stdpain  阅读(188)  评论(0编辑  收藏  举报