是的,每个 uop 都是独立调度的,只需要等待其输入准备好。(对于执行端口上的一个空闲周期,当它发布到无序后端时,它被分配了。) x86 uops 是如何调度的,确切地说? 指令边界与 RS aka 调度程序无关。
对于许多多微指令,微指令对早期指令具有数据依赖性。 但有时早期的微指令只需要准备好一个输入,因此每个输入到输出都有单独的最小延迟。 多个值或范围作为单个指令的延迟意味着什么?
例如,仅需要在加载 uop 完成后add eax, [rdi]
准备好 EAX 。所以通过 EAX 的关键路径延迟只有 1 个周期。但是如果 RDI 没有准备好,或者 RDI 指向的内存没有准备好,那么 add ALU uop 就不能执行。但是,这仍然是对 uops 进行解码的重点,这与 P5 Pentium 不同,后者必须在其有序管道1中进行加载和相加。
(例如,对于 Intel CPU 上的可变计数移位,额外的 uop 仅用于 FLAGS输出;GP 整数部分已准备好,有 1 个周期延迟,但 FLAGS 结果稍后准备好。产生 GP- 的 uop整数结果与唯一的 uop BMI2 解码结果基本相同shlx
。)
但有些确实有一些ILP(实际上是 uop 级并行性)。例如xchg eax, ecx
,在 Intel CPU 上解码为 3 个寄存器复制微指令,我们可以分别测量 EAX->ECX 和 ECX->EAX 方向在 1 和 2 个周期(分别)的延迟。为什么 XCHG reg, reg 是现代英特尔架构上的 3 条微操作指令?
另一个例子是phaddd
;它的解码方式很像两个shufps
uop(2 输入 shuffle)和一个paddd
取决于两个 shuffle 的 uop。两个 shuffle 都在读取两个输入以提供 shuffle。Ice Lake 在 2 个端口上有 shuffle 单元,实际上可以并行运行 shuffle uops,给它 2 个周期延迟 ( uops.info ),低于早期英特尔的 3 个周期,因为单个 shuffle 端口的资源冲突。(冰湖的额外洗牌端口只运行一些整数洗牌,所以haddps
在冰湖上仍然和以前一样糟糕)
请注意,我们无法准确证明每个 uop 在做什么,但考虑到测量的延迟和每个端口的总 uop 计数,对于许多指令来说,只有一个合理的设计可以解释行为。例如,因为phaddd
我们知道 CPU 具有 SIMD 整数加法执行单元和整数 shuffle 单元,因此phaddd
最明显可以通过解码为两个硬连线 shuffle 模式和一个普通 uop 来实现 3 paddd
uop。
脚注 1:
针对 P5 进行优化显然涉及使用 x86 的 RISCier 子集,例如避免使用除 之外的内存源操作数mov
,并且绝对避免使用内存目标指令。那是因为它是一个有序的管道,并且无法将多指令分解以独立调度它们。
进一步阅读:p5 与后来的微架构:https ://agner.org/optimize/ 。https://www.realworldtech.com/sandy-bridge/也很好。
http://www.lighterra.com/papers/modernmicroprocessors/如果您还没有阅读它,那么它是一个很好的选择,但它并没有涉及到您的问题所涉及的详细程度。