SSE2从golang中的打包数据中提取浮点数

时间:2018-10-03 19:47:42

标签: go assembly sse plan-9

我正在用Golang写一个汇编函数。为了简化,假设我要执行以下功能:

func sseSumOfMinimums (d1, d2 [2]float64) float64

它将计算d1 [0],d2 [0]的最小值以及d1 [1]和d2 [1]的最小值并计算总和

在汇编中,我这样做:

TEXT ·sseSum(SB), $0-40
MOVUPD d1+0(FP), X0 // loading d1 to X0
MOVUPD d2+16(FP), X1 // loading d1 to X1
MINPD X0, X1 // compute pair minimums and store to X1
MOVSD X1, X2 // move first min to X2
// How do I move second float of X1 to X3?
ADDSD X2, X3
MOVSD X3, ret+32(FP)

我缺少的部分是如何从X1提取第二个标量到X3

1 个答案:

答案 0 :(得分:1)

Go不能保证堆栈对齐,因此您可以为minpd使用内存源操作数吗?

此外,我对Go并不熟悉;它的float是真正的IEEE binary64,大多数语言(包括x86 asm)都称为double吗?奇怪的是,在源代码中看到float而在汇编中使用了pd(压缩双倍)指令。


为此,调用一个独立的手写asm函数的开销将比让编译器对一个单独的标量minsd进行的开销更高。尤其是在Go糟糕的调用约定下,将args传递到内存中并将返回值存储到内存中。

具有LLVM或gcc后端的经过优化的Go编译器应使用内联代码完成工作,该内联代码比调用此函数具有更低的延迟和更低的吞吐量成本,即使进行以下优化。或者,如果您很幸运,编译器会为您使用minpd


但是对于实际问题,在minpd x0, x1之后,您需要的是xmm1的水平和。 Fastest way to do horizontal float vector sum on x86

即使您只关心低64位,也应该使用movaps复制xmm寄存器。 movsd x1, x2合并到xmm2的低64位中,从而对旧值产生了错误的依赖关系,并耗费了shuffle uop。

minpd   x0, x1
movhps  x1, x0        // high 64 bits of xmm1  => low 64 of xmm0
addsd   x1, x0

您可以使用movaps x1, x2unpckhpd x2,x2,但这会花费额外的movapdmovaps,而使用movhps可以避免。

({movaps / movups短于movapd,代码大小更小,否则在所有CPU上完全等效于movapd / movupd ,商店和reg-reg副本。)