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