4

假设我有两个向量,由两个类型的数组表示double,每个数组的大小为 2。我想添加相应的位置。所以假设向量i0and i1,我想把 and 加i0[0] + i1[0]在一起i0[1] + i1[1]

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

我的问题是,如果我调用_mm_load_ps(i0[0])then _mm_load_ps(i1[0]),那会将它们分别放在低位和高位 64 位中,还是会用第二个替换寄存器load?我如何将两个双打放在同一个寄存器中,这样我就可以打电话add_ps了?

谢谢,

4

2 回答 2

8

我想你想要的是这样的:

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

当您执行 a_mm_load_pd时,它将第一个 double 放入寄存器的低 64 位,第二个放入高 64 位。因此,在上面的负载之后,x1保存两个doublei0[0]i0[1](和类似的x2)。调用垂直添加and_mm_add_pd中的相应元素,因此在添加之后,在其低 64 位和高 64 位中保持不变。x1x2sumi0[0] + i1[0]i0[1] + i1[1]

编辑:我应该指出,使用_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

于 2012-02-13T03:34:00.150 回答
3

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

相反,你想要_mm_load_pd(). 这个函数接受一个 16 字节对齐的指针,指向两个 s 数组的第一个成员double,并加载它们。所以你会像这样使用它:

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

v0 = _mm_add_pd(v0, v1);
于 2012-02-13T03:37:59.480 回答