SIMD的编写

前言

  学习SIMD的笔记

参考教程:SIMD Tutorial.pdf

一、使用SIMD的场景

  考虑如下代码:

vec3 velocity = GetPlayerSpeed(); 
float length = velocity.Length(); 

  获取玩家速度,是个包含x,y,z三个分量的向量,然后对这个向量求长度。
这个Length让我们写的话,一般就是:

float Length(){
    return sqrt(x*x+y*y+z*z);
}

  或者:

x = velocity.x * velocity.x;
y = velocity.y * velocity.y;
z = velocity.z * velocity.z;
sum = x + y;
sum = sum + z;
length = sqrtf( sum ) 

  此时对前面三个值求平方就可以是并行的,但这同时是一种浪费。

  CPU支持的指令集可以通过CPU-Z来查看:
可以看出,我的CPU同时支持SSE和AVX指令集,其中SSE支持4字(16字节,128位)运算,AVX支持8字(32字节,256位)运算。

  三个并行的浮点运算只会占用其中的一部分插槽,这样会浪费25%的SSE数据槽位或62.5%的AVX数据槽位。
  但是如果我们用另一种方式;考虑我们如果有四个玩家,那么代码会是如下的方式组织:

x4 = GetPlayerXSpeeds();
y4 = GetPlayerYSpeeds();
z4 = GetPlayerZSpeeds();
x4squared = x4 * x4;
y4squared = y4 * y4;
z4squared = z4 * z4;
sum4 = x4squared + y4squared;
sum4 = sum4 + z4squared;
length4 = sqrtf4( sum4 );

  x4,y4,z4都是承载着四个浮点数的向量,一次取出四个玩家的同一分量,同时对这一分量做运算,从新的维度操作数据,使指令集的利用率得到提高,从这点上看,一次操作的数据数量最好是4或8的倍数。
  同时也可以看出,为了更好的SIMD使用,最好配合高效的数据结构。

二、数据操控

  C++是强类型语言,但对于一个数据,我们可以把它看做另一个类型来操控它:

int a;
float& b = (float&)a;

  也可以用联合体的方式来操控:

union { int a; float b; }

  假如我们用如下方式写出联合体,那么我们既可以当成无符号整形一次性运算或赋值,也可以当成无符号字符类型依次取值或运算:

union { unsigned int c4; unsigned char c[4]; }; 

实验代码:

union int_char { int c4; char c[4]; };
int main(){
    int_char ic;
    ic.c[0] = 0; ic.c[1] = 0;
    ic.c[2] = 0; ic.c[3] = 1;
    std::cout << ic.c4 << std::endl;
// output:
//  16777216 = 1 * (16^6)
}

  由此可见int的存储形式(英特尔CPU在PC上是小端处理方式)。

SIMD数据类型

  首先引入两个头文件:

#include "nmmintrin.h" // for SSE4.2
#include "immintrin.h" // for AVX

  其中__m128和__128i是SSE的数据类型,代表四位浮点数和四位整数,__m256和__256i则是AVX的。
  __m128包含四位浮点数,因此我们同样可以使用上面的技巧:

union float4{ __m128 f4; float f[4]; };

  这种用法称为类型双关,不过我们按ctrl点入__m128中,会发现这本身就是一个多关类型:

typedef union __declspec(intrin_type) __declspec(align(16)) __m128 {
     float               m128_f32[4];
     unsigned __int64    m128_u64[2];
     __int8              m128_i8[16];
     __int16             m128_i16[8];
     __int32             m128_i32[4];
     __int64             m128_i64[2];
     unsigned __int8     m128_u8[16];
     unsigned __int16    m128_u16[8];
     unsigned __int32    m128_u32[4];
 } __m128;

  我们甚至可以直接:__m128 f4 = {1,2,3,4};,这样会存储为float类型,用f4.m128_f32可以查看,用f4.m128_i32则会发生值的错误;存储顺序会按照数组的书写顺序存储。
  用以下的方法塞入数字:

float4 a, b;
a.f4 = _mm_set_ps(4.0f, 4.1f, 4.2f, 4.3f);
b.f4 = _mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f);

  可以塞入不同类型的数值,上例子中塞入的是float值,和数组式初始化不同的是,它的存储顺序刚好相反,类似最上边的联合体存取方式,是小端存储。
  然后调用方法使它们并行相加:

__m128 sum4 = _mm_add_ps(a.f4, b.f4);

  此时我们想办法将其打印出来:

float4 sum;
sum.f4 = sum4;
std::ostream_iterator<float> foi = { std::cout, " " };//STL中的输出迭代器
std::copy(std::begin(sum.f), std::end(sum.f), foi);//输出
//output:
//5.3 5.2 5.1 5

  同样的运算操作,还有减、乘、除、开方、取倒数:

_mm_sub_ps(a, b);
_mm_mul_ps(a, b);
_mm_div_ps(a, b);
_mm_sqrt_ps(a, b);
_mm_rcp_ps(a, b);// reciprocal

  对于AVX指令集的操作类似,不过运算函数的名称都要在"_mm"后加上256,例如:“_mm256_add_ps”

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容