SSE指令集学习:Compiler Intrinsic

本文介绍了SSE Intrinsics,一种内联函数,用于提高代码性能,避免函数调用开销。SSE Intrinsics在编译器内部,允许优化器针对特定上下文进行优化。SSE Intrinsics在不同数据类型间转换、内存操作和计算效率方面与SSE汇编指令对比,展示了其在简单计算中与SSE指令相当,但在复杂逻辑和多次内存读写时可能效率较低。文章通过双线性插值的Intrinsic实现举例,探讨了Intrinsic在实际应用中的挑战和考虑因素。
摘要由CSDN通过智能技术生成

大多数的函数是在库中,Intrinsic Function却内嵌在编译器中(built in to the compiler)。

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位平台已经不再支持内联汇编。

2. SSE Intrinsic

VS和GCC都支持SSE指令的Intrinsic,SSE有多个不同的版本,其对应的Intrinsic也包含在不同的头文件中,如果确定只使用某个版本的SSE指令则只包含相应的头文件即可。


引用自:http://www.cnblogs.com/zyl910/archive/2012/02/28/vs_intrin_table.html

例如,要使用SSE3,则

#include <tmmintrin.h>

如果不关心使用那个版本的SSE指令,则可以包含所有

#include <intrin.h> 
2.1 数据类型

Intrinsic使用的数据类型和其寄存器是想对应,有
* 64位 MMX指令集使用
* 128位 SSE指令集使用
* 256位 AVX指令集使用

甚至AVX-512指令集有512位的寄存器,那么相对应Intrinsic的数据也就有512位。
具体的数据类型及其说明如下:
1. __m64 64位对应的数据类型,该类型仅能供MMX指令集使用。由于MMX指令集也能使用SSE指令集的128位寄存器,故该数据类型使用的情况较少。
2. __m128 / __m128i / __m128d 这三种数据类型都是128位的数据类型。由于SSE指令集即能操作整型,又能操作浮点型(单精度和双精度),这三种数据类型根据所带后缀的不同代表不同类型的操作数。__m128是单精度浮点数,__m128i是整型,__m128d是双精度浮点数。

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下面可以根据需要使用不使用这种抽取数据的方法,但是这种功能在调试代码时是非常方便的,如上图可以很容

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
给出下列代码在OpenCL中的运行结果:#include "stdio.h" #include <xmmintrin.h> // Need this for SSE compiler intrinsics #include <math.h> // Needed for sqrt in CPU-only version #include <time.h> int main(int argc, char* argv[]) { printf("Starting calculation...\n"); const int length = 64000; // We will be calculating Y = SQRT(x) / x, for x = 1->64000 // If you do not properly align your data for SSE instructions, you may take a huge performance hit. float *pResult = (float*) _aligned_malloc(length * sizeof(float), 16); // align to 16-byte for SSE __m128 x; __m128 xDelta = _mm_set1_ps(4.0f); // Set the xDelta to (4,4,4,4) __m128 *pResultSSE = (__m128*) pResult; const int SSELength = length / 4; clock_t clock1=clock(); #define TIME_SSE // Define this if you want to run with SSE #ifdef TIME_SSE // lots of stress loops so we can easily use a stopwatch for (int stress = 0; stress < 1000; stress++) { // Set the initial values of x to (4,3,2,1) x = _mm_set_ps(4.0f, 3.0f, 2.0f, 1.0f); for (int i=0; i < SSELength; i++) { __m128 xSqrt = _mm_sqrt_ps(x); // Note! Division is slow. It's actually faster to take the reciprocal of a number and multiply // Also note that Division is more accurate than taking the reciprocal and multiplying #define USE_DIVISION_METHOD #ifdef USE_FAST_METHOD __m128 xRecip = _mm_rcp_ps(x); pResultSSE[i] = _mm_mul_ps(xRecip, xSqrt); #endif //USE_FAST_METHOD #ifdef USE_DIVISION_METHOD pResultSSE[i] = _mm_div_ps(xSqrt, x); #endif // USE_DIVISION_METHOD // Advance x to the next set of numbers x = _mm_add_ps(x, xDelta); } } clock_t clock2=clock(); printf("SIMDtime:%d ms\n",1000*(clock2-clock1)/CLOCKS_PER_SEC); #endif // TIME_SSE #define TIME_NoSSE #ifdef TIME_NoSSE clock_t clock3=clock(); // lots of stress loops so we can easily use a stopwatch for (int stress = 0; stress < 1000; stress++) { clock_t clock3=clock(); float xFloat = 1.0f; for (int i=0 ; i < length; i++) { // Even though division is slow, there are no intrinsic functions like there are in SSE pResult[i] = sqrt(xFloat) / xFloat; xFloat += 1.0f; } } clock_t clock4=clock(); printf("noSIMDtime:%d ms\n",1000*(clock4-clock3)/CLOCKS_PER_SEC); #endif // TIME_noSSE return 0; }   
06-12
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值