主流 Intel CPU 没有任何很长延迟的单微指令整数指令。所有 ALU 端口上都有用于 1 周期延迟微指令的整数 ALU,端口 1 上有一个 3 周期延迟流水线 ALU。我认为 AMD 类似。
div/sqrt 单元是唯一真正高延迟的 ALU,但整数 div/idiv 在 Intel 上进行了微编码,因此可以使用 FP,其中 div/sqrt 通常是单 uop 指令。
AMD 的整数div
/ idiv
是 2 个 uop 指令(大概是写入 2 个输出),具有数据相关的延迟。
此外,AMD Bulldozer/Piledriver(其中 2 个整数核心共享一个 SIMD/FP 单元)具有相当高的延迟movd xmm, r32
(10c 2 uop)和movd r32, xmm
(8c 1 uop)。压路机将其缩短 1c。 Ryzen 在任一方向上都有 3 周期 1 uop。
movd
到/从 XMM 寄存器在 Intel 上很便宜:具有 1 周期(Broadwell 及更早版本)或 2 周期延迟(Skylake)的单微指令。 (https://agner.org/optimize/ https://agner.org/optimize/)
sqrtss
具有固定延迟(在 IvB 及更高版本上),除了次正常输入之外。如果你的整数链只涉及movd xmm, r32
对于任意整数位模式,您可能需要设置 DAZ/FTZ 以消除 FP 辅助的可能性。 NaN 输入没问题;这不会导致 SSE/AVX 数学速度减慢,只会导致 x87 速度减慢。
其他 CPU(Sandybridge 及更早版本,以及所有 AMD)具有可变延迟sqrtss
所以你可能想控制那里的起始位模式。
如果你愿意的话也一样use sqrtsd
每微操作的延迟高于sqrtss
。即使在 Skylake 上,它仍然是可变的延迟。 (15-16 个周期)。
您可以假设延迟是输入位模式的纯函数,所以开始一个链sqrtss
每次具有相同输入的指令将给出相同的延迟序列。或者起始输入为0.0
, 1.0
, +inf
, or NaN
, 你会得到the same序列中每个微操作的延迟。
(像 1.0 和 0.0 这样的简单输入(输入和输出中很少有有效数字)大概以最低的延迟运行。sqrt(1.0) = 1.0 和 sqrt(0) = 0,所以这些是自我延续的。sqrt(NaN 也一样) ) = 南)
你可能会使用and reg, 0
或其他非深度破坏归零作为链的一部分来控制输入位模式。也许or reg, -1
创建 NaN。然后,您可以在 Sandybridge 或更早版本以及包括 Zen 在内的 AMD 上获得固定延迟。
也许pinsrw xmm0, eax, 7
(Intel 上的端口 5 为 2 uop)仅修改 XMM 的高 qword,将底部保留为已知0.0
or 1.0
。可能更便宜and
与 0 并使用movd
,除非端口 5 压力不是问题。
创建吞吐量瓶颈(不是延迟),您对 Skylake 的最佳选择是vsqrtpd ymm
- p0 为 1 uop,延迟 = 15-16,吞吐量 = 9-12。
在 Broadwell 及更早版本上,它是 3 uops (2p0 p15),但我认为 Skylake 拓宽了 SIMD 分频器(我猜是为 AVX512 做准备)。