SIMD指令

转载:https://www.sunxidong.com/357.html

SIMD原理
1、SIMD简介
SIMD全称Single Instruction Multiple Data,单指令多数据流,即一条指令处理多条数据,是对CPU基本指令集对扩展。

Intel的初代SIMD指令集是MMX,Multi-Media Extension, 即多媒体扩展,因为它的首要目标是为了支持MPEG视频解码。MMX将64位寄存当作2X32或8X8来用,只能处理整型计算。

后来Intel进一步实现了SSE、SSE2~SSE4以及AVX系列指令集,给了他们单独的寄存器。

SSE首先就是有了属于自己的16个128位长的寄存器,被称为XMM0XMM15,其中XMM8XMM15只有系统是64位模式时才有效。SSE指令要求数据是16byte对齐的。
SSE2进一步支持双精度浮点数,由于寄存器长度没有变长,所以只能支持2个双精度浮点计算或是4个单精度浮点计算。另外,它在这组寄存器上实现了整型计算,从而代替了MMX。
SSE3支持一些更加复杂的算术计算。
SSE4增加了更多指令,并且在数据搬移上下了一番工夫,支持不对齐的数据迁移。
AVX系列指令集将寄存器从128位扩展到256位,同时引入了16个256位的寄存器,被称为YMM0~YMM15。
说起AVX来,还有一个有意思的故事:
SSE及其后面的进化过程中一直是增加其后面的数字,即SSE2, SSE3, SSE4,按理说下一次进化应该称为SSE5。实际上SSE5是存在的,只不过仅存在于AMD的处理器里。前几代SSE处理器都是Intel先出,然后AMD跟随,然而到SSE4之后,突然AMD先出了SSE5,抢了Intel的先。Intel不能忍,于是SSE5就没了。

2、判断当前设备CPU的支持能力
在命令行通过以下命令:

cat /proc/cpuinfo

在输出中查看flags一项,看是否包含avx、avx2等。

3、SIMD的数据类型
在SIMD相关函数中,经常能看到__m128、__m128d、__m128i、__m256、__m256d、__m256i等数据类型,这几种分别表示128位和256位的浮点型与整型数据,它们的定义如下:

typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__));
typedef double __m128d __attribute__ ((__vector_size__ (16), __may_alias__)); 
typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__));
typedef float __m256 __attribute__ ((__vector_size__ (32), __may_alias__));
typedef double __m256d __attribute__ ((__vector_size__ (32), __may_alias__)); 
typedef long long __m256i __attribute__ ((__vector_size__ (32), __may_alias__));

其中typedef后面的数据类型如long long或double等,指定了新定义的数据类型的基础类型,属性中指定的__vector_size__指定了新类型的实际大小,以字节为单位。

3.1 128位与256位的vector floating-point数据

从SSE到SSE4.2的指令集里,使用128位XMM寄存器,支持128位的vector(矢量)浮点数据,在AVX和FMA指令里增加到了256位的YMM寄存器,可以使用256位的vector数据。
在128位的vector数据里,可以容纳4个单精度浮点数或者2个双精度浮点数。在AVX和VMA指令使用的YMM寄存器里面可以容纳8个单精度浮点数或者4个双精度浮点数。
在这里插入图片描述

3.2 128位的scalar floating-point数据

在SSE系统指令和AVX/FMA指令里处理的scalar数据是128位宽,如下图所示:
在这里插入图片描述

在128位的scalar数据里,单精度scalar只使用低32位,双精度scalar只使用低64位,高位不作为数据进行运算。

3.3 128位与256位的packed integer数据

SSE系列指令与AVX指令里处理的packed integer数据也是128位宽,包含以下几种:

  • packed byte
  • packed word
  • packed doubleword
  • packed quadword

多数情况下这些整型数据也区分unsigned和signed版本,由对应的SIMD指令使用。
在Ivy Bridge微架构及以后的微构架中,增加了AVX2指令,能够处理256位的packed integer数据。

128位的packed integer数据能容纳16个byte,或8个word,或4个doubleword,或2个quadword整 型值,如下图所示:
在这里插入图片描述

4、SIMD指令运算示例

比较两个IPv6地址:

int ipv6_addr_cmp_eq(struct in6_addr ip6_addr1, 
        struct in6_addr ip6_addr2)
{
    __m128i addr1 = _mm_set_epi32(ip6_addr1.s6_addr32[0],
            ip6_addr1.s6_addr32[1],
            ip6_addr1.s6_addr32[2],
            ip6_addr1.s6_addr32[3]);

    __m128i addr2 = _mm_set_epi32(ip6_addr2.s6_addr32[0],
            ip6_addr2.s6_addr32[1],
            ip6_addr2.s6_addr32[2],
            ip6_addr2.s6_addr32[3]);

    __m128i vcmp = _mm_cmpeq_epi32(addr1, addr2);

    int16_t mask = _mm_movemask_epi8(vcmp);

    return (mask != 0);
}

4.1 _mm_set_epi32()

该函数的声明原型及函数实现原理如下:

在这里插入图片描述

即用4个32位整型,构造成一个128位的数据。

4.2 _mm_cmpeq_epi32()

该函数的声明原型及函数实现原理如下:

在这里插入图片描述

该函数的作用是,对a和b两个128位的数据,以32位为一组进行比较,比较的结果放到dst数组的对应位。如果比较的两部分值相等,则dst值为0xFFFFFFFF。

4.3 _mm_movemask_epi8()

该函数的声明原型及函数实现原理如下:
在这里插入图片描述

该函数的返回值是一个int整型,但通过操作原理可以看到,返回值只用了前16位,因此将该函数返回值赋值给一个16位整型也不会出问题。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值