中央处理器很可能会丢弃ROB的内容,回滚到服务中断之前的最新退役状态。
正在执行的分支错误不会改变这一点。根据CPU(旧/简单),当中断到达时,它可能已经在回滚到退役状态和清除流水线的过程中因为分支错误而进行了。
正如@Hadi所说,CPU可以选择在那时退役分支(中断推送指向正确分支目标的CS:RIP),而不是让其在从中断返回后重新执行。
但是,这只有在分支指令已经准备好退役的情况下才有效:没有比该分支更旧的指令尚未执行。由于尽早发现分支错误非常重要,我假设当它在执行期间发现错误预测时,分支恢复就会开始,而不是等待到达退役。 (这与其他类型的故障不同:例如,Meltdown和
L1TF基于故障负载
不触发
#PF
故障处理,直到它到达退役,因此CPU确信真实执行路径上确实存在故障。在您确定它不在错误预测或更早的故障的阴影之前,不要启动昂贵的管道清除。)
但是,由于分支错误不会引发异常,因此在我们确定分支指令首先属于正确路径之前,可以尽早开始重定向前端。
例如:cmp byte [cache_miss_load],123
/ je
错误预测但很长一段时间内不会被发现。然后,在那个错误预测的阴影下,一个在“错误”的路径上运行的 cmp eax,1
/ je
被发现也出现了错误预测。通过快速恢复,超过该点的uops将被清除,并且从“正确”路径提取/解码/执行可以在早期的错误预测甚至被发现之前开始。
为了保持中断请求延迟低,CPU不会给已经执行的指令额外时间去完成。此外,任何已经完成但是其数据仍在存储缓冲区的写入操作(还未提交给L1d)都需要在中断处理程序的写操作之前提交。但中断是串行化的(我认为),处理程序中的任何MMIO或端口IO可能涉及内存屏障或强顺序存储,因此如果这些指令涉及写操作,让更多指令完成可能会影响中断请求延迟。(一旦一个写入操作完成,即使它的数据仍在存储缓冲区中,它也绝对需要发生)。
强调:乱序的后端总是知道如何回滚到已知的良好退役状态; ROB的整个内容始终被视为推测性的,因为任何负载或存储都可能出错,许多其他指令也可能出错。超越分支的推断并不是特别特殊的。
分支只有在具有额外的跟踪以进行快速恢复时才是特殊的(Nehalem和更新版本中的Branch Order Buffer),因为它们在正常操作期间预计会发生错误预测的频率是非常高的。有关详细信息,请参见
当skylake CPU错误预测分支时会发生什么?尤其是David Kanter的引用:
"Nehalem增强了从分支错误预测中恢复的能力,这一能力已经延续到Sandy Bridge。一旦发现分支错误预测,核心就能够在已知正确路径的同时重新启动解码,同时乱序机器正在清除来自错误推测路径的uops。此前,解码将不会恢复,直到管道完全刷新。"
(这个答案有意地以英特尔为中心,因为您标记了
intel,而不是
x86。我假设AMD也会做类似的事情,其他ISA的乱序uarch大致相似。除了在具有较弱内存模型的CPU上不存在内存顺序错误规范,其中CPU被允许可见地重新排序负载之外。)
注1:如果FP异常未被屏蔽,
div
或任何FPU指令都可以执行。即使像默认情况下那样屏蔽FP异常,一个非规格化的FP结果也可能需要微码协助处理。
在英特尔CPU上,内存顺序错误也可能导致流水线故障(在早期进行了负载推测,而之前的负载尚未完成,但是高速缓存失去了行的副本,此时x86内存模型表示负载可以获取其值)。
IRET
是完全序列化的。 - Hadi Braisiret
,但如果我们直到IRQ处理程序完成工作后才进行序列化,那么它对于中断延迟就不会有太大问题(只有吞吐量成本)。这就是为什么我提到IRQ处理程序存储必须等待缓冲区刷新的原因。 - Peter Cordescpuid
一样。有关内存序列化与指令的区别,请参见MFENCE/SFENCE/etc“序列化内存但不执行指令”?。此外,有关屏障与完全序列化的一些提及,请参见一个x86 CPU有多少内存屏障指令?。 - Peter Cordes