14

有人可以向我解释为什么融合乘法累加指令有 3 种变体:vfmadd132pd,vfmadd231pdvfmadd213pd, 而只有一个 C 内在函数_mm256_fmadd_pd

为简单起见,(在 AT&T 语法中)有什么区别

vfmadd132pd  %ymm0, %ymm1, %ymm2
vfmadd231pd  %ymm0, %ymm1, %ymm2
vfmadd213pd  %ymm0, %ymm1, %ymm2

我没有从英特尔的内在指南中得到任何想法。我问是因为我在我编写的一段 C 代码的汇编器输出中看到了所有这些。谢谢。


一个干净的答案(在下面重新格式化答案)

对于变体ijk,的含义vfmaddijkpd

  • 英特尔语法:op(i) * op(j) + op(k) -> op(1)
  • AT&T 语法:op(4-i) * op(4-j) + op(4-k) -> op(3)

其中op(n)表示指令后的第 n 个操作数。所以两者之间有一个逆变换:

n <- 4 - n
4

2 回答 2

14

融合乘加指令将两个(打包的)值相乘,将第三个值相加,然后用结果覆盖其中一个值。这三个值中只有一个可以是内存操作数而不是寄存器。

它的工作方式是所有三个指令都覆盖ymm0并只允许ymm2作为内存操作数。指令的选择决定了两个操作数相乘和相加。

假设 ymm0 是 Intel 语法中的第一个操作数(或 AT&T 语法中的最后一个):

vfmadd132pd:  ymm0 = ymm0 * ymm2/mem + ymm1
vfmadd231pd:  ymm0 = ymm1 * ymm2/mem + ymm0
vfmadd213pd:  ymm0 = ymm1 * ymm0 + ymm2/mem 

当使用 C 内部函数时,这个选择不是必需的:内部函数不会覆盖一个值,而是返回它的结果,它允许从内存中读取所有三个值。如果需要,编译器将添加内存读取/写入,如果不希望三个值中的任何一个被覆盖,编译器将分配一个临时寄存器来存储结果。它将选择它认为合适的三个指令之一。

于 2016-04-03T22:07:11.903 回答
4

这是在汇编指令集参考中,也在它的 HTML 摘录中,例如VFMADD*PD的条目:

VFMADD132PD:将第一个源操作数中的两个或四个压缩双精度浮点值乘以第三个源操作数中的两个或四个压缩双精度浮点值,将无限精度中间结果添加到两个或四个第二个源操作数中的压缩双精度浮点值 ,执行舍入并将生成的两个或四个压缩双精度浮点值存储到目标操作数(第一个源操作数)。

VFMADD213PD:将来自第二个 源操作数的两个或四个压缩双精度浮点值乘以第一个源操作数中的两个或四个压缩双精度浮点值,将无限精度中间结果与两个或四个相加第三个源操作数中的压缩双精度浮点值,执行舍入并将生成的两个或四个压缩双精度浮点值存储到目标操作数(第一个源操作数)。

VFMADD231PD:将来自第二个源的两个或四个压缩双精度浮点值乘以第三个 源操作数中的两个或四个压缩双精度浮点值,将无限精度中间结果添加到两个或四个压缩第一个源操作数中的双精度浮点值 ,执行舍入并将生成的两个或四个压缩双精度浮点值存储到目标操作数(第一个源操作数)。

于 2016-04-03T22:06:03.937 回答