SSE加载和添加
假设我有两个向量由两个double
类型的数组表示,每个数组大小为2.我想添加相应的位置。 因此假设向量i0
和i1
,我想将i0[0] + i1[0]
和i0[1] + i1[1]
在一起。
由于类型是double
,我需要两个寄存器。 诀窍是将i0[0]
和i1[0]
,以及i0[1]
和i1[1]
放在另一个中,只需添加寄存器即可。
我的问题是,如果我调用_mm_load_ps(i0[0])
然后_mm_load_ps(i1[0])
,它会将它们分别置于低位和高位64位,还是会用第二次load
替换寄存器? 如何将两个双打放在同一个寄存器中,以便我可以在之后调用add_ps
?
谢谢,
我想你想要的是这个:
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
,它将第一个双_mm_load_pd
放入寄存器的低64位,第二个放入高16位。 因此,在上面的负载之后, x1
保持两个double
值i0[0]
和i0[1]
(并且类似于x2
)。 对_mm_add_pd
的调用会在x1
和x2
垂直添加相应的元素,因此在sum
后, sum
在其低64位中保持i0[0] + i1[0]
在高64位中保持i0[1] + i1[1]
。
编辑:我应该指出使用_mm_load_pd
而不是_mm_load_ps
没有任何好处。 正如函数名称所示, pd
种类显式加载两个打包的双精度数, ps
版本加载四个打包的单精度浮点数。 由于这些是纯粹的逐位内存移动并且它们都使用SSE浮点单元,因此使用_mm_load_ps
加载double
数据_mm_load_ps
受到惩罚。 并且, _mm_load_ps
有一个好处:它的指令编码比_mm_load_pd
短一个字节,因此它从指令高速缓存的意义上来说更有效(并且可能是指令解码;我不是现代x86处理器所有复杂function的专家)。 使用_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
演员没有隐含的function; 它只是让编译器将SSE寄存器的内容重新解释为保持双精度而不是浮点数,以便它可以传递给双精度算术函数_mm_add_pd
。
_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);