在 Intel 和 AMD x86_64 处理器上,SIMD 矢量化寄存器具有特定的融合乘加功能,但通用(标量、整数)寄存器 don't - 您基本上需要乘以,然后添加(除非您可以将事物放入 lea
)。
这是为什么?我的意思是,它是无用的以至于不值得开销吗?
最佳答案
整数乘法很常见,但不是整数最常见的事情之一。但是对于浮点数,一直使用乘法和加法,并且FMA大大提高了许多ALU绑定(bind)FP代码的速度。
另外,浮点数实际上避免了FMA造成的精度损失(添加之前,odt_code内部临时临时文件没有全部取整)。这就是the ISO C99 / C++ x*y
math library function存在的原因,并且为什么在没有硬件FMA支持的情况下实现起来很慢。
与单独的乘法和加法相比,整数FMA(或乘法累加,又称为MAC)没有任何精度优势。
一些非x86 ISA确实提供了整数FMA。它不是没有用的,但是Intel和AMD都没有费心将它包括until AVX512-IFMA(而且仍然仅适用于SIMD,基本上公开了 double FMA/fma()
所需的52位尾数乘法器电路以供整数指令使用)。
非x86的示例包括:
vmulpd
/madd
(无符号)乘以累加到maddu
/hi
寄存器(通过常规乘法和除法指令用作目标的特殊寄存器)。 lo
和 friend (32x32 => 64位MAC或16x16 => 32位),也可用于无符号整数。操作数是常规的R0..R15通用寄存器。 整数寄存器FMA在x86上很有用,但是具有3个整数输入的uops很少使用。 CMOV和ADC具有3个输入,但其中之一是标志。即使那样,在Haswell中为FP FMA添加了3输入uop支持之后,直到Broadwell才将它们解码为Intel的单个uop。
Haswell和更高版本可以使用3个整数输入for (some) micro-fused instructions with indexed addressing modes来跟踪融合域uops。 Sandybridge/Ivybridge取消分层指令,例如
smlal
。 (但是Nehalem可以像Haswell一样使它们保持微融合; SnB简化了融合域uop格式)。无论如何,这是融合域,不在调度程序中。只有Broadwell/Skylake可以在调度程序中跟踪3输入整数,这仅适用于2个整数+标志,而不是3个整数寄存器。英特尔确实使用“统一”调度程序,其中FP和整数运算使用相同的调度程序,并且它可以跟踪正确的3输入FP FMA。因此,如果存在技术障碍,则IDK。如果不是这样,那么IDK为什么Intel不将整数FMA作为BMI2的一部分或类似的东西而添加了东西like
add eax, [rdx+rcx]
(与使用mulx
的传统mul
不同的是,2输入2输出mul
具有大部分显式操作数)。SSE2/SSSE3确实具有用于向量寄存器的整数mul-add指令,但只有在加宽16x16 => 32位(SSE2
rdx:rax
)或(unsigned)8x(signed)8 => 16位(SSSE3 pmaddwd
)后才进行水平加法。但是,这些只是2输入指令,因此即使有乘法和加法,也与FMA有很大不同。
脚注:问题标题最初表示没有FMA“用于标量”。标量FP FMA具有相同的FMA3扩展名,这些扩展名添加了打包版本:
pmaddubsw
和friends以标量 double 操作,并且相同样式的vfmaddXXXss可用于XMM寄存器中的标量浮点。关于x86-64 - 为什么 x86_64 CPU 上的通用寄存器没有融合乘加?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49253907/