我正在阅读关于分支预测的文章,我想知道分支预测器是否会"推测"地执行任何类型的指令。特别是,我想知道它是否会,例如,与硬件通信。
让我们假设你有这样的东西:
while (true) {
if (condition)
SendPacketOverNetwork()
DoSomethingElse()
}
(在汇编级,if之后的第一条指令引发中断,或者与硬件通信)。在这种情况下,如果分支预测器碰巧"猜错了"会发生什么?如果这不能发生,为什么?分支预测器将执行哪种指令?我是否误解了分支预测器的作用?
首先,分支预测器不执行任何操作,它只是告诉CPU下一个要获取和执行的指令是什么。然后,CPU将获取并插入下一组指令到它的管道中,并开始执行它们。
所有对外部世界有任何影响的操作(即在核心之外可观察到的操作),只有在相应的指令退役并提交后才会执行。如果CPU在核心之外有一些专用的缓冲来防止推测状态泄漏,则可能存在一些小的例外,但效果是一样的——即使操作是在内部执行的,在提交之前也无法观察到它。存储到内存、输出、断点或任何其他可观察的操作都包括在内。
在分支预测错误时,推测状态被刷新,机器中的任何虚假结果,包括比错误预测的分支年轻的所有操作都被回滚(在无序的cpu上,通常通过排序缓冲区进行管理)。确切的细节当然取决于实际的微架构。由于提交是按顺序执行的(即使执行是乱序的),它们的功能是作为一个收敛点——错误预测分支的执行必须在管道中的那个点之前完成,因此在任何年轻指令的退役和提交之前完成(它们通常被认为是在该分支的"阴影"中)。因此,任何外部可观察的操作都不可能被执行,除非它比错误预测的分支更早。
示例(在无序机器上,因为这是更有趣的情况):
op1 | exec retire
op2 | exec retire
branch| exec retire
op3 | exec retire
op4 | exec retire
store | retire dispatch
---------------------------> Time
如果分支在执行时发现它的预测是错误的,则保证在下一个指令在其退役/提交之前或之后沿着管道(包括执行任何较年轻的存储)刷新。在有序机器中,执行本身是有序的,因此分支将在任何较年轻的指令执行之前执行(并且分支解析将是已知的)。