为什么 x86_64 CPU 上的通用寄存器没有融合乘加法?
Why is there no fused multiply-add for general-purpose registers on x86_64 CPUs?
在 Intel 和 AMD x86_64 处理器上,SIMD 矢量化寄存器具有特定的融合乘加功能,但通用(标量、整数)寄存器 don't - 您基本上需要乘法,然后添加(除非您可以将内容放入 lea
)。
这是为什么?我的意思是,它是否无用以至于不值得开销?
整数乘法很常见,但不是 最 最常见的整数乘法之一。但是对于浮点数,一直使用乘法和加法,FMA 为大量 ALU-bound FP 代码提供 主要 加速。
此外,浮点数实际上避免了 FMA 的精度损失(x*y
内部临时变量在添加之前根本没有四舍五入)。这就是 the ISO C99 / C++ fma()
math library function 存在的原因,也是为什么在没有硬件 FMA 支持的情况下实施起来很慢的原因。
整数 FMA(或 multiply-accumulate,又名 MAC)与单独的乘法和加法相比没有任何精度优势。
一些非 x86 ISA 确实提供整数 FMA。它不是没用,但 Intel 和 AMD 都没有费心将它包括在内until AVX512-IFMA(而且这仍然仅适用于 SIMD,基本上暴露了 double-precision FMA/[=12 所需的 52 位尾数乘法器电路=] 供整数指令使用)。
非 x86 示例包括:
MIPS32, madd
/ maddu
(unsigned) to multiply-accumulate into the hi
/ lo
registers (常规乘法和除法指令用作目标的特殊寄存器)。
ARM smlal
和朋友(32x32=>64 位 MAC,或 16x16=>32 位),也可用于无符号整数。操作数是常规的 R0..R15 通用寄存器。
整数寄存器 FMA 在 x86 上很有用,但具有 3 个整数输入的 uops 很少见。 CMOV 和 ADC 有 3 个输入,但其中一个是标志。即便如此,在为 Haswell 中的 FP FMA 添加了 3 输入微指令支持之后,直到 Broadwell,他们才在英特尔上解码为单个微指令。
Haswell 及更高版本可以使用 3 个整数输入跟踪 fused-domain 微指令,不过 for (some) micro-fused instructions with indexed addressing modes。 Sandybridge/Ivybridge un-laminate 指令如 add eax, [rdx+rcx]
。 (但 Nehalem 可以像 Haswell 一样保留它们 micro-fused;SnB 简化了 fused-domain uop 格式)。无论如何,那是融合域,不在调度程序中。只有 Broadwell/Skylake 可以在调度程序中跟踪 3 输入整数 uops,并且仅适用于 2 个整数 + 标志,而不是 3 个整数寄存器。
英特尔确实使用了 "unified" 调度器,其中 FP 和整数运算使用相同的调度器,并且它可以跟踪适当的 3 输入 FP FMA。如果存在技术障碍,那么 IDK。如果不是,IDK 为什么英特尔没有将整数 FMA 作为 BMI2 或其他东西的一部分,它添加了东西 like mulx
(2 输入 2 输出 mul
,主要是显式操作数,与传统 mul
使用 rdx:rax
.)
SSE2/SSSE3 是否有向量寄存器的整数mul-add指令,但只有在加宽16x16后水平相加=> 32 位 (SSE2 pmaddwd
) or (unsigned)8x(signed)8=>16-bit (SSSE3 pmaddubsw
).
但这些只是 2 个输入指令,所以即使有乘法和加法,它也与 FMA 有很大不同。
脚注:问题标题原来说没有FMA "for scalars"。标量 FP FMA 具有相同的 FMA3 扩展,添加了这些的打包版本:VFMADD231SD
和朋友在标量 double-precision 上运行,并且相同风格的 vfmaddXXXss 可用于 XMM 寄存器中的标量浮点数。
在 Intel 和 AMD x86_64 处理器上,SIMD 矢量化寄存器具有特定的融合乘加功能,但通用(标量、整数)寄存器 don't - 您基本上需要乘法,然后添加(除非您可以将内容放入 lea
)。
这是为什么?我的意思是,它是否无用以至于不值得开销?
整数乘法很常见,但不是 最 最常见的整数乘法之一。但是对于浮点数,一直使用乘法和加法,FMA 为大量 ALU-bound FP 代码提供 主要 加速。
此外,浮点数实际上避免了 FMA 的精度损失(x*y
内部临时变量在添加之前根本没有四舍五入)。这就是 the ISO C99 / C++ fma()
math library function 存在的原因,也是为什么在没有硬件 FMA 支持的情况下实施起来很慢的原因。
整数 FMA(或 multiply-accumulate,又名 MAC)与单独的乘法和加法相比没有任何精度优势。
一些非 x86 ISA 确实提供整数 FMA。它不是没用,但 Intel 和 AMD 都没有费心将它包括在内until AVX512-IFMA(而且这仍然仅适用于 SIMD,基本上暴露了 double-precision FMA/[=12 所需的 52 位尾数乘法器电路=] 供整数指令使用)。
非 x86 示例包括:
MIPS32,
madd
/maddu
(unsigned) to multiply-accumulate into thehi
/lo
registers (常规乘法和除法指令用作目标的特殊寄存器)。ARM
smlal
和朋友(32x32=>64 位 MAC,或 16x16=>32 位),也可用于无符号整数。操作数是常规的 R0..R15 通用寄存器。
整数寄存器 FMA 在 x86 上很有用,但具有 3 个整数输入的 uops 很少见。 CMOV 和 ADC 有 3 个输入,但其中一个是标志。即便如此,在为 Haswell 中的 FP FMA 添加了 3 输入微指令支持之后,直到 Broadwell,他们才在英特尔上解码为单个微指令。
Haswell 及更高版本可以使用 3 个整数输入跟踪 fused-domain 微指令,不过 for (some) micro-fused instructions with indexed addressing modes。 Sandybridge/Ivybridge un-laminate 指令如 add eax, [rdx+rcx]
。 (但 Nehalem 可以像 Haswell 一样保留它们 micro-fused;SnB 简化了 fused-domain uop 格式)。无论如何,那是融合域,不在调度程序中。只有 Broadwell/Skylake 可以在调度程序中跟踪 3 输入整数 uops,并且仅适用于 2 个整数 + 标志,而不是 3 个整数寄存器。
英特尔确实使用了 "unified" 调度器,其中 FP 和整数运算使用相同的调度器,并且它可以跟踪适当的 3 输入 FP FMA。如果存在技术障碍,那么 IDK。如果不是,IDK 为什么英特尔没有将整数 FMA 作为 BMI2 或其他东西的一部分,它添加了东西 like mulx
(2 输入 2 输出 mul
,主要是显式操作数,与传统 mul
使用 rdx:rax
.)
SSE2/SSSE3 是否有向量寄存器的整数mul-add指令,但只有在加宽16x16后水平相加=> 32 位 (SSE2 pmaddwd
) or (unsigned)8x(signed)8=>16-bit (SSSE3 pmaddubsw
).
但这些只是 2 个输入指令,所以即使有乘法和加法,它也与 FMA 有很大不同。
脚注:问题标题原来说没有FMA "for scalars"。标量 FP FMA 具有相同的 FMA3 扩展,添加了这些的打包版本:VFMADD231SD
和朋友在标量 double-precision 上运行,并且相同风格的 vfmaddXXXss 可用于 XMM 寄存器中的标量浮点数。