SSE intrinsic的几个指令_mm_prefetch/_mm_movehl_ps/_mm_shuffle_ps

来源:互联网 发布:java从键盘输入数字 编辑:程序博客网 时间:2024/06/05 15:49

 

1_mm_prefetch

void_mm_prefetch(char *p, int i)

The argument "*p" gives the address of the byte (andcorresponding cache line) to be prefetched. The value "i" gives aconstant (_MM_HINT_T0, _MM_HINT_T1, _MM_HINT_T2, or _MM_HINT_NTA) thatspecifies the type of prefetch operation to be performed.

T0 (temporal data)--prefetchdata into all cache levels.

T1 (temporal data with respectto first level cache)--prefetch data in all cache levels except 0th cache level

T2 (temporal data with respectto second level cache) --prefetch data in all cache levels, except 0th and 1stcache levels.

NTA (non-temporal data withrespect to all cache levels)--prefetch data into non-temporal cache structure.(This hint can be used to minimize pollution of caches.)

  
void _mm_prefetch(char *p, int i) 

 从地址P处预取尺寸为cache line大小的数据缓存,参数i指示预取方式(_MM_HINT_T0, _MM_HINT_T1, _MM_HINT_T2, _MM_HINT_NTA,分别表示不同的预取方式)
T0 预取数据到所有级别的缓存,包括L0。
T1 预取数据到除L0外所有级别的缓存。
T2 预取数据到除L0和L1外所有级别的缓存。
NTA  预取数据到非临时缓冲结构中,可以最小化对缓存的污染。 
       如果在CPU操作数据之前,我们就已经将数据主动加载到缓存中,那么就减少了由于缓存不命中,需要从内存取数的情况,这样就可以加速操作,获得性能上提升。使用主动缓存技术来优化内存拷贝。
 
注意,CPU对数据操作拥有绝对自由!使用预取指令只是按我们自己的想法对CPU的数据操作进行补充,有可能CPU当前并不需要我们加载到缓存的数据,这样,我们的预取指令可能会带来相反的结果,比如对于多任务系统,有可能我们冲掉了有用的缓存。不过,在多任务系统上,由于线程或进程的切换所花费的时间相对于预取操作来说太长了, 所以可以忽略线程或进程切换对缓存预取的影响。


2_mm_movehl_ps

Moves the upper two single-precision,floating-point values of b tothe lower two single-precision, floating-point values of the result. The upper two single-precision, floating-point valuesof a are passed through to the result.

b的高64位移至结果的低64位,a的高64位传递给结果。

如:

r = __m128_mm_movehl_ps( __m128 a, __m128 b ); //r = {a3, a2, b3, b2} //

s = _mm_movehl_ps( x , x );//--s = {x3, x2, x3, x2}

 

例:(代码)

 

 


3_mm_shuffle_ps

Selectsfour specific single-precision, floating-point values from a and b,  based on the mask  i. 其中,i是一个8 bit的常量,这个常量的1~8位分别控制了从两个操作数中选择分量的情况。

__m128_mm_shuffle_ps(__m128 a , __m128 b , int i );

 

s = _mm_shuffle_ps( r , r , 1 )//r = {r3, r2, r1, r0}, s = {r0,r0, r0, r1}

 

它可以把两个操作数的分量以特定的顺序排列并赋予给目标数。比如

__m128 b = _mm_shuffle_ps ( a , a , 0 );

  

b 的所有分量都是 a 中下标为0的分量。第三个参数控制分量分配,是一个8bit的常量,这个常量的1~8位分别控制了从两个操作数中选择分量的情况。而在使用intrinsic的时候,最好使用_MM_SHUFFLE 宏,它可以定义分配情况。

Shuffle Function Macro

_MM_SHUFFLE(z,y, x, w)

/* expandsto the following value */

(z<<6)| (y<<4) | (x<<2) | w

 

m3 = _mm_shuffle_ps(m1, m2, _MM_SHUFFLE(1, 0, 3, 2))

_mm_shuffle_ps

 It is a simple selection operation of the operands m1 and m2.

So, _MM_SHUFFLE(z,y,x,w) selects x&w 32 bit double words from m1 and z&y from m2. How simple!!.

 

one little very formal suggestion: 
_MM_SHUFFLE(z,y,x,w) does not select anything, this macro just creates a mask. SHUFPS instruction (or _mm_shuffle_ps wrapper function) performs selection, using mask created by _MM_SHUFFLE macro.

 

例:

如果定义一个共同体

typedef union {  __m128 m;  float m128_f32[4];  } my_m128;

 __m128 m1 = { 1.0f, 2.0f, 3.0f, 4.0f };

那么, m128_f32[0] = 4, m128_f32[1] = 3, m128_f32[2] = 2, m128_f32[4] = 1

 


 

 

附: 

下面我们来复习一下叉积的求法。

c = a x b

可以写成:

那么写成SSE intrinsic形式则是:

 

三分量的向量求点积,可以写成:

 

通过这两个例子,可以留意到向量内元素的垂直相加一般形式,即:

那么通过扩展,可以得到求向量长度的函数,首先是求分量平方和函数:

 

 

参考:MSDN

http://hi.baidu.com/sige_online/blog/item/a80522ceec812433b700c829.html

http://www.codeguru.com/forum/archive/index.php/t-337156.html

http://blog.csdn.net/igame/archive/2007/08/21/1752430.aspx

 

原创粉丝点击