我的理解是,在处理器管道开始时,指令指针(指向要执行的下一条指令的地址(在获取后由分支预测器更新,以便可以在下一个周期中获取此新地址。
但是,如果在管道的早期修改了指令指针,这是否会影响当前处于执行阶段的可能依赖于旧指令指针值的指令?例如,在执行call
时,需要将当前 EIP 推送到堆栈中,但是在分支预测期间更新指令指针时,这不会受到影响吗?
您似乎假设整个 CPU 内核只使用一个物理 EIP 寄存器。
这是行不通的,因为每个可能出现异常的指令都需要知道自己的地址。 或者,当外部中断到达时,CPU 可以决定在任何指令之后为中断提供服务,使该中断成为架构 EIP。 在长模式 (x86-64( 中,还有 RIP 相对寻址模式,因此call
不是唯一需要当前程序计数器作为数据的指令。
简单的流水线 CPU 可能为每个流水线阶段都有一个 EIP。
现代超标量无序 x86 将 EIP(或 RIP(与每个动态指令相关联(或者可能是每个uop;但多 uop 指令的所有 uop 都相互关联,因此指令不能部分停用。
与架构状态的其他部分(例如 EFLAGS、EAX 等(不同,该值在解码后是静态已知的。 实际上甚至早于即时值;指令边界在预解码阶段检测(或在L1i缓存中标记(,以便可以将多个指令并行馈送到多个解码器。
早期的获取/解码阶段可能只跟踪 16 字节或 32 字节获取块的地址,但在解码后,我假设内部 uop 表示中有一个地址字段。 对于非分支指令,它可能只是与之前的一个小偏移量(以节省空间(,因此如果需要,可以计算它,但我们在这里深入研究了实现细节。 乱序执行保持了指令按程序顺序运行的错觉,并且它们确实按顺序发出和停用(进入/离开核心的无序执行部分(。
相关:x86寄存器:MBR/MDR和指令寄存器基于玩具CPU做出了类似的错误假设。 也没有保存机器代码字节的"当前指令"寄存器。 在我的回答中查看更多链接,以获取有关 OoO/流水线 CPU 的更多信息。
分支预测必须在块被解码之前起作用。 即,假设我们刚刚在地址abc处获取了一个块,我们需要预测接下来要获取的块。 即预测必须预测将并行解码的 16 字节指令块中是否存在跳转。
相关:为什么英特尔在这些年改变了静态分支预测机制?