2012-02-13 67 views
4

假设我有两个向量由两个数组double两个数组表示,每个数组的大小为2.我想添加相应的位置。所以假设矢量i0i1,我想添加i0[0] + i1[0]i0[1] + i1[1]在一起。SSE加载和添加

由于类型是double,我需要两个寄存器。诀窍是将i0[0]i1[0],i0[1]i1[1]放在另一个中,并将其与自身相加。

我的问题是,如果我打电话_mm_load_ps(i0[0]),然后_mm_load_ps(i1[0]),将它们分别放在较低和较高的64位,或将它替换为第二个load?我如何将两个双打放在同一个寄存器中,所以我可以在拨打add_ps之后?

感谢,

回答

7

我想你想要的是这样的:

double i0[2]; 
double i1[2]; 

__m128d x1 = _mm_load_pd(i0); 
__m128d x2 = _mm_load_pd(i1); 
__m128d sum = _mm_add_pd(x1, x2); 
// do whatever you want to with "sum" now 

当你做一个_mm_load_pd,它把第一双入册和第二的低64位到上16位。因此,在上述负荷后,x1保留两个doublei0[0]i0[1](以及类似的x2)。对_mm_add_pd的调用垂直添加了x1x2中的相应元素,因此在添加之后,sumi0[0] + i1[0]保留在其较低的64位中,将i0[1] + i1[1]保留在其较高的64位中。

编辑:我应该指出,有使用_mm_load_pd代替_mm_load_ps没有好处。如函数名称所示,pd类显式加载两个压缩双精度,并且ps版加载四个压缩单精度浮点数。由于这些都是纯位移内存,并且都使用SSE浮点单元,所以使用_mm_load_ps加载double数据没有任何损失。而且,_mm_load_ps还有一个好处:它的指令编码比_mm_load_pd短一个字节,所以它从指令高速缓存意义上讲效率更高(可能还有指令解码;我不是现代x86处理器所有复杂性的专家)。使用_mm_load_ps上面的代码看起来像:

double i0[2]; 
double i1[2]; 

__m128d x1 = (__m128d) _mm_load_ps((float *) i0); 
__m128d x2 = (__m128d) _mm_load_ps((float *) i1); 
__m128d sum = _mm_add_pd(x1, x2); 
// do whatever you want to with "sum" now 

没有被蒙上暗示的功能;它只是让编译器重新解释SSE寄存器的内容为保持双精度而不是浮点数,以便它可以传递到双精度算术函数_mm_add_pd

+0

你当然可以使用'_mm_load_ps',但风险在其上设计了这样一种方式的假设未来处理器性能的下降,有单间域旁路处罚和双精度浮点运算。我知道没有这样的处理器的计划,但这并不是说永远不会实施;这就是为什么有不同的加载操作。诚然,这是一个遥远的可能性,但为什么冒这个险呢? – 2012-02-13 15:32:51

+0

我同意未来的处理器存在性能下降的风险。我建议人们考虑(即衡量)通过在特定应用的基础上使用“MOVPS”而不是“MOVPD”来获得任何性能优势。如果今天使用它是有好处的,并且没有迹象表明即将到来的架构会有这样的惩罚,我会这样做。像这样的负载可以很容易地被抽象化,以允许将来自动切换到不同的实现。 – 2012-02-13 16:41:58

3

_ps前缀是的缩写“packed single”,意思是它用于单精度浮点而不是双精度。

取而代之,你想要_mm_load_pd()。该函数将一个16字节的对齐指针指向两个double的数组中的第一个成员,并加载它们。所以,你可以使用这个像这样:

__m128d v0 = _mm_load_pd(i0); 
__m128d v1 = _mm_load_pd(i1); 

v0 = _mm_add_pd(v0, v1); 
+0

'_mm_load_ps'实际上可以用于双精度值(并且这样做有好处);看到我的答案。 – 2012-02-13 15:27:12