我在阅读关于分支预测的文章,我想知道分支预测器是否会“推测性地”执行任何类型的指令。特别是,我想知道它是否会,例如,与硬件通信。
假设你有这样的东西:
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
如果分支在执行时发现它的预测是错误的,则保证下一条指令在它们退役/提交之前或以后沿着管道的任何内容(包括执行任何较年轻的存储)被刷新。在更简单的有序机器中,执行本身是有序的,因此分支将在任何较年轻的指令执行之前执行(并且分支解析将是已知的)。