微码分支显然很特别。
根据 Andy Glew 对原始 P6 (What setup does REP do?) 的描述,英特尔的 P6 和 SnB 系列不支持微码分支的动态预测。鉴于 SnB 系列 rep-string 指令的类似性能,我认为这一 PPro 事实甚至适用于最新的 Skylake / CoffeeLake CPU1。
但是微码分支错误预测会受到惩罚,因此它们是静态(?)预测的。 (这就是为什么 rep movsb 在 ECX 中的低/中/高计数的启动成本以 5 个周期为增量,并且对齐与未对齐。)
微编码指令在 uop 缓存中占用整行。 当它到达 IDQ 的前面时,它会接管发布/重命名阶段,直到完成发布微码 uops。(有关更多详细信息,另请参阅 How are microcodes executed during an instruction cycle?,以及来自性能事件描述的一些证据,例如 @ 987654332@ 表明 IDQ 可以接受来自 uop 缓存的新 uop而问题/重命名阶段正在从微码序列器读取。)
对于rep-string 指令,我认为循环的每次迭代都必须通过前端实际发出,而不仅仅是在后端循环内部并重用这些微指令。所以这涉及到来自 OoO 后端的反馈,以找出指令何时完成执行。
我不知道当问题/重命名切换到从 MS-ROM 而不是 IDQ 读取 uops 时会发生什么的详细信息。
即使每个 uop 没有自己的 RIP(作为单个微编码指令的一部分),我猜分支错误预测检测机制的工作方式与普通分支类似。
rep movs 某些 CPU 上的设置时间似乎以 5 个周期为步长,具体取决于具体情况(小与大、对齐等)。如果这些来自微码分支错误预测,那似乎意味着错误预测惩罚是固定数量的周期,除非这只是rep movs 的特例。可能是因为 OoO 后端跟不上前端?并且从 MS-ROM 读取比从 uop 缓存读取更能缩短路径,从而使未命中惩罚如此之低。
在rep movsb 附近运行一些 OoO exec 可能会很有趣,例如有两条依赖的imul指令链,看看它是否(部分)serializes them like lfence。我们希望不会,但为了实现 ILP,后面的imul uops 必须在不等待后端耗尽的情况下发出。
我在 Skylake (i7-6700k) 上做了一些实验。初步结果:95 字节及以下的副本大小便宜且被 IMUL 链的延迟隐藏,但它们基本上完全重叠。 96 字节或更大的复制大小会耗尽 RS,序列化两个 IMUL 链。 无论是 RCX=95 与 96 的 rep movsb 还是 RCX=23 与 987654341@ 都无关紧要. 24. 有关我的发现的更多总结,请参见 cmets 中的讨论;如果我有时间,我会发布更多详细信息。
“耗尽 RS”行为是用 rs_events.empty_end:u 测量的,甚至每 rep movsb 变为 1 而不是 ~0.003。 other_assists.any:u 为零,所以它不是“辅助”,或者至少不算作一。
如果微代码分支不支持通过 BoB 进行快速恢复,可能涉及的任何 uop 都只会在达到退休时检测到错误预测? 96 字节阈值可能是某些替代策略的截止值。 RCX=0 也会耗尽 RS,大概是因为它也是一种特殊情况。
用rep scas 测试会很有趣(它不支持快速字符串,只是缓慢而愚蠢的微代码。)
Intel's 1994 Fast Strings patent 描述了 P6 中的实现。它没有 IDQ(因此现代 CPU 在阶段之间有缓冲区和 uop 缓存会有一些变化是有道理的),但他们描述的避免分支的机制很简洁,可能仍然用于现代 ERMSB:第一个n 复制迭代是后端的谓词微指令,因此可以无条件地发出它们。还有一个 uop 会导致后端将其 ECX 值发送到微码定序器,然后微码定序器使用它来提供正确数量的额外复制迭代。只是复制微指令(可能是 ESI、EDI 和 ECX 的更新,或者可能只在中断或异常时这样做),而不是微码分支微指令。
这个最初的n uops 与阅读 RCX 后输入更多可能是我看到的 96 字节阈值;它带有一个额外的idq.ms_switches:urep movsb(从 4 个增加到 5 个)。
https://eprint.iacr.org/2016/086.pdf 建议微码在某些情况下可以触发辅助,这可能是较大副本大小的现代机制,并且可以解释耗尽 RS(显然是 ROB),因为它只会触发当 uop committed(退休)时,它就像一个没有快速恢复的分支。
执行单元可以通过将事件代码与微操作的结果相关联来发出辅助或发出故障信号。当微操作被提交时(第 2.10 节),事件代码会导致乱序调度程序压缩 ROB 中所有正在运行的微操作。事件代码被转发到微码定序器,它读取相应事件处理程序中的微操作"
此专利与 P6 专利之间的区别在于,此辅助请求可能发生在来自后续指令的一些非微码微指令已经发出之后,预计微码指令仅在第一批微码指令中完成。或者,如果它不是来自微码的批次中的最后一个微指令,它可以用作选择不同策略的分支。
但这就是为什么它必须刷新 ROB。
我对 P6 专利的印象是,对 MS 的反馈发生在后续指令发出微指令之前,以便在需要时及时发出更多的微指令。如果我错了,那么也许它已经是 2016 年论文中描述的相同机制了。
通常,当一个分支错误预测为被采用时,那么当指令退出,
自从 Nehalem 以来,英特尔实现了“快速恢复”,当预测错误的分支执行时开始恢复,而不是像例外一样等待它退休。
这是在通常的 ROB 退休状态之上拥有一个分支订单缓冲区的关键,它允许您在任何其他类型的意外事件变得非推测性时回滚。 (What exactly happens when a skylake CPU mispredicts a branch?)
脚注 1:IceLake 应该具有“快速短代表”功能,这可能是处理 rep 字符串的不同机制,而不是对微码的更改。例如也许像安迪这样的硬件状态机提到他希望自己一开始就设计。
我没有任何关于性能特征的信息,但是一旦我们知道了一些事情,我们或许能够对新的实现做出一些猜测。