0

我正在用 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

4

1 回答 1

1

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

另外,我对 Go 不熟悉;它float真的是 IEEE binary64,大多数语言(包括 x86 asm)都调用double吗?float在 asm 中使用的源代码和pd(打包双)指令中看到很奇怪。


为此调用独立的手写 asm 函数的开销将高于让编译器使用 scalarminsd来执行单个对的开销。尤其是 Go 糟糕的调用约定,在内存中传递 args 并将返回值存储到内存中。

具有 LLVM 或 gcc 后端的优化 Go 编译器应该使用内联代码完成工作,与调用此函数相比,具有更低的延迟和更少的吞吐量成本,即使使用下面给出的优化也是如此。或者,如果你幸运的话,编译器会minpd为你使用。


但对于实际问题,在 之后minpd x0, x1,您需要的是 的水平总和xmm1在 x86 上进行水平浮点向量求和的最快方法

您应该使用movaps复制 xmm 寄存器,即使您只关心低 64 位。 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, x2and unpckhpd x2,x2,但这会花费额外的费用,movapd或者movaps您可以通过使用movhps.

movaps/movups比 更短movapd,代码大小更小,否则在所有 CPU 上完全等同于movapd/movupd用于加载、存储和 reg-reg 副本。)

于 2018-10-03T20:02:55.730 回答