先挖个坑,记录下资料。
2020/03/24
继续记录,争取这周搞定SSE!
1. Intrinsic Function
Intrinsic Function作为内联函数,直接在调用的地方插入代码,即避免了函数调用的额外开销,又能够使用比较高效的机器指令对该函数进行优化。优化器(Optimizer)内置的一些Intrinsic Function行为信息,可以对Intrinsic进行一些不适用于内联汇编的优化,所以通常来说Intrinsic Function要比等效的内联汇编(inline assembly)代码快。优化器能够根据不同的上下文环境对Intrinsic Function进行调整,例如:以不同的指令展开Intrinsic Function,将buffer存放在合适的寄存器等。
使用 Intrinsic Function对代码的移植性会有一定的影响,这是由于有些Intrinsic Function只适用于Visual C++,在其他编译器上是不适用的;更有些Intrinsic Function面向的是特定的CPU架构,不是全平台通用的。上面提到的这些因素对使用Intrinsic Function代码的移植性有一些不好的影响,但是和内联汇编相比,移植含有Intrinsic Function的代码无疑是方便了很多。另外,64位平台已经不再支持内联汇编。
引用自:https://www.cnblogs.com/wangguchangqing/p/5466301.html
2. SSE Intrinsic
VS和GCC都支持SSE指令的Intrinsic,SSE有多个不同的版本,其对应的Intrinsic也包含在不同的头文件中,如果确定只使用某个版本的SSE指令则只包含相应的头文件即可。
引用自:https://www.cnblogs.com/zyl910/archive/2012/02/28/vs_intrin_table.html
2.1 数据类型
Intrinsic使用的数据类型和其寄存器是想对应,有
甚至AVX-512指令集有512位的寄存器,那么相对应Intrinsic的数据也就有512位。
具体的数据类型及其说明如下:
256和512的数据类型和128位的类似,只是存放的个数不同,这里不再赘述。
知道了各种数据类型的长度以及其代码的意义,那么它的表现形式到底是怎么样的呢?看下图
__m128i yy;
yy是__m128i型,从上图可以看出__m128i是一个联合体(union),根据不同成员包含不同的数据类型。看其具体的成员包含了8位、16位、32位和64位的有符号/无符号整数(这里__m128i是整型,故只有整型的成员,浮点数的使用__m128)。而每个成员都是一个数组,数组中填充着相应的数据,并且根据数据长度的不同数组的长度也不同(数组长度 = 128 / 每个数据的长度(位))。在使用的时候一定要特别的注意要操作数据的类型,也就是数据的长度,例如上图同一个变量yy当作4个32位有符号整型使用时其数据是:0,0,1024,1024;但是当做64位有符号整型时其数据为:0,4398046512128,大大的不同。
在MSVC下可以使用yy.m128i_i32[0]
取出第一个32位整型数据,原生的Intrinsic函数是没有提供该功能的,这是在MSVC的扩展,比较像Microsoft的风格,使用及其的方便但是效率很差,所以这种方法在GCC/Clang下面是不可用的。在MSVC下面可以根据需要使用不使用这种抽取数据的方法,但是这种功能在调试代码时是非常方便的,如上图可以很容易的看出128位的数据在不同数据类型下其值的不同。
Intrinsic使用的数据类型和其寄存器是想对应,有
甚至AVX-512指令集有512位的寄存器,那么相对应Intrinsic的数据也就有512位。
具体的数据类型及其说明如下:
256和512的数据类型和128位的类似,只是存放的个数不同,这里不再赘述。
知道了各种数据类型的长度以及其代码的意义,那么它的表现形式到底是怎么样的呢?看下图
__m128i yy;
yy是__m128i型,从上图可以看出__m128i是一个联合体(union),根据不同成员包含不同的数据类型。看其具体的成员包含了8位、16位、32位和64位的有符号/无符号整数(这里__m128i是整型,故只有整型的成员,浮点数的使用__m128)。而每个成员都是一个数组,数组中填充着相应的数据,并且根据数据长度的不同数组的长度也不同(数组长度 = 128 / 每个数据的长度(位))。在使用的时候一定要特别的注意要操作数据的类型,也就是数据的长度,例如上图同一个变量yy当作4个32位有符号整型使用时其数据是:0,0,1024,1024;但是当做64位有符号整型时其数据为:0,4398046512128,大大的不同。
在MSVC下可以使用yy.m128i_i32[0]
取出第一个32位整型数据,原生的Intrinsic函数是没有提供该功能的,这是在MSVC的扩展,比较像Microsoft的风格,使用及其的方便但是效率很差,所以这种方法在GCC/Clang下面是不可用的。在MSVC下面可以根据需要使用不使用这种抽取数据的方法,但是这种功能在调试代码时是非常方便的,如上图可以很容易的看出128位的数据在不同数据类型下其值的不同。
引用自:https://www.cnblogs.com/wangguchangqing/p/5466301.html
2.2 Intrinsic 函数的命名
Intrinsic函数的命名也是有一定的规律的,一个Intrinsic通常由3部分构成,这个三个部分的具体含义如下:
将这三部分组合到以其就是一个完整的Intrinsic函数,如_mm_mul_epi32 对参数中所有的32位有符号整数进行乘法运算。
SSE指令集对分支处理能力非常的差,而且从128位的数据中提取某些元素数据的代价又非常的大,因此不适合有复杂逻辑的运算。
引用自:https://www.cnblogs.com/wangguchangqing/p/5466301.html
REF
1、(c/c++ 代码中使用sse指令集加速)https://www.cnblogs.com/dragon2012/p/5200698.html
2、SSE指令指令集进行程序加速、DCT的优化处理(https://blog.csdn.net/yangdashi888/article/details/53376367)
3、SSE指令集学习:Compiler Intrinsic(https://www.cnblogs.com/wangguchangqing/p/5466301.html)
4、https://www.cnblogs.com/zyl910/archive/2012/04/26/md00.html(本博客包含许多关于SSE相关的资料)