美文网首页
在C/C++代码中使用SSE等指令集的指令 2020-05-07

在C/C++代码中使用SSE等指令集的指令 2020-05-07

作者: OTTFFIVE | 来源:发表于2020-05-07 14:01 被阅读0次

    SSE(Stream SIMD Extensions)是Intel在其计算机芯片Pentium3中引入的指令集,是继MMX的扩充指令集。提供了70条新指令。
    SIMD,single instruction multiple data,单指令流多数据流,一次运算指令可以执行多个数据流,可以提高程序的运算速度,是实现DLP(Data Level Parallelism)的关键。

    SSE本质上类似于一个向量处理器,包括了4个主要部分:单精确度浮点数运算指令、整数运算指令(为MMX的延伸,并与MMX使用同样的暂存器)、Cache控制指令、状态控制指令。

    SSE浮点运算指令分为两大类:packed和scalar
    packed指令是一次对XMM暂存器中的四个浮点数(DATA0~DATA3)均进行计算,而scalar只对XMM暂存器中的DATA0进行计算,见下图。

    sse1.png sse2.png

    SSE指令的一般格式由三部分组成,第一部分表示指令的作用,第二部分是s或者p分别表示scalar或packed,第三部分为s,表示单精度浮点数(single precision floating point data)

    大多数SSE指令是使用的xmm0到xmm8的暂存器,那么使用之前,就需要将数据从内存加载到这些暂存器。

    1. load系列,用于加载数据,从内存到暂存器

    __m128 _mm_load_ss (float *p)  
    __m128 _mm_load_ps (float *p)  
    __m128 _mm_load1_ps (float *p)  
    __m128 _mm_loadh_pi (__m128 a, __m64 *p)  
    __m128 _mm_loadl_pi (__m128 a, __m64 *p)  
    __m128 _mm_loadr_ps (float *p)  
    __m128 _mm_loadu_ps (float *p)
    

    其中,
    _mm_load_ss用于scalar的加载,所以,加载一个单精度浮点数到暂存器的低字节,其它三个字节清0,(r0 := *p, r1 := r2 := r3 := 0.0)。

    _mm_load_ps用于packed的加载(下面的都是用于packed的),要求p的地址是16字节对齐,否则读取的结果会出错,(r0 := p[0], r1 := p[1], r2 := p[2], r3 := p[3])。

    _mm_load1_ps表示将p地址的值,加载到暂存器的四个字节,需要多条指令完成,所以,从性能考虑,在内层循环不要使用这类指令。(r0 := r1 := r2 := r3 := *p)。

    _mm_loadh_pi和_mm_loadl_pi分别用于从两个参数高底字节等组合加载。具体参考手册。

    _mm_loadr_ps表示以_mm_load_ps反向的顺序加载,需要多条指令完成,当然,也要求地址是16字节对齐。(r0 := p[3], r1 := p[2], r2 := p[1], r3 := p[0])。

    _mm_loadu_ps和_mm_load_ps一样的加载,但是不要求地址是16字节对齐,对应指令为movups。

    2. set系列,用于加载数据,大部分需要多条指令完成,但是可能不需要16字节对齐。

    __m128 _mm_set_ss (float w)  
    __m128 _mm_set_ps (float z, float y, float x, float w)  
    __m128 _mm_set1_ps (float w)  
    __m128 _mm_setr_ps (float z, float y, float x, float w)  
    __m128 _mm_setzero_ps ()  
    

    这一系列函数主要是类似于load的操作,但是可能会调用多条指令去完成,方便的是可能不需要考虑对齐的问题。
    _mm_set_ss对应于_mm_load_ss的功能,不需要字节对齐,需要多条指令。(r0 = w, r1 = r2 = r3 = 0.0)
    _mm_set_ps对应于_mm_load_ps的功能,参数是四个单独的单精度浮点数,所以也不需要字节对齐,需要多条指令。(r0=w, r1 = x, r2 = y, r3 = z,注意顺序)
    _mm_set1_ps对应于_mm_load1_ps的功能,不需要字节对齐,需要多条指令。(r0 = r1 = r2 = r3 = w)
    _mm_setzero_ps是清0操作,只需要一条指令。(r0 = r1 = r2 = r3 = 0.0)

    (2)算术指令

    SSE提供了大量的浮点运算指令,包括加法、减法、乘法、除法、开方、最大值、最小值、近似求倒数、求开方的倒数等等,可见SSE指令的强大之处。那么在了解了上面的数据加载和数据保存的指令之后,使用这些算术指令就很容易了,下面以加法为例。

    SSE中浮点加法的指令有:

    __m128 _mm_add_ss (__m128 a, __m128 b)  
    __m128 _mm_add_ps (__m128 a, __m128 b)
    

    其中,_mm_add_ss表示scalar执行模式,_mm_add_ps表示packed执行模式。

    一般而言,使用SSE指令写代码,步骤为:使用load/set函数将数据从内存加载到SSE暂存器;使用相关SSE指令完成计算等;使用store系列函数将结果从暂存器保存到内存,供后面使用。

    相关文章

      网友评论

          本文标题:在C/C++代码中使用SSE等指令集的指令 2020-05-07

          本文链接:https://www.haomeiwen.com/subject/plwoghtx.html