在x86_64中没有64位地址的直接跳转。只有32位的。对于间接跳转,我理解管道必须在分支预测开始发挥作用之前解决一次。我的问题是:在64位中没有办法在第一次执行时进行1-3个周期的跳转吗?
第一次直接跳转并不总是那么便宜,即使没有I-cache丢失。他们仍然需要分支预测。
在长模式下,jcc rel32
和jmp rel32
(以及rel8紧凑型版本)使用来自RIP的符号扩展相对位移。您可以跳转到任何64位地址,只要您来自2GB以内的地址。因此,请将您的代码与其他代码保持在2GB以内,以便您可以使用rel32置换。
在长模式下没有绝对的直接跳转。32位模式的远JMP ptr16:32
(操作码0xEA)和远CALL ptr16:32根本没有64位版本。(无论如何,为了性能和方便,您都不希望跳跃太远。)像SYSCALL和INT这样的指令是间接跳转(带有隐式目标),并且无论如何都没有用。
也没有指令预取/预取指令来获取L1 I-cache或top cache中的目标,也没有任何方式来暗示流水线将很快需要从给定地址解码指令。
请参阅Darek Mihocka关于模拟器中间接跳转的文章中的"预知列表"部分,在这里,让一个来宾指令的处理程序直接跳转到下一个来宾指令的处理程序是很有用的,而不是让一个几乎总是预测错误的间接调用调度指令。(或者至少当Mihocka在it - tage分支预测器或多或少解决这个问题之前(在Intel Haswell和后来的AMD Zen或Zen2中)写时是有用的):分支预测和解释器的性能不要相信民间传说2015年由Rohou, Swamy和Seznec。
直接跳转
即使直接跳转也需要branch-target-buffer来预测下一个取块应该来自其他地方。在解码阶段之前就需要这些信息,因此必须对其进行预测以避免显著的前端气泡。最近出现了一个有趣的问题:缓慢的jsp指令。Realworldtech论坛上的回复清楚地表明,分支预测需要在获取块上工作,而不仅仅是指令,并且即使在简单解码的固定宽度ISA(不像x86)上,您也需要在解码结果可用之前进行预测。
1-3个周期对于新看到的直接(rel32)跳转的代码获取气泡的大小是不现实的。不过,部分气泡可能会被解码队列隐藏。
Code-fetch到decode可能至少需要5或6个周期,甚至更多。假设L1-I命中时间为4个周期,与Haswell的L1D负载使用延迟相同。然后Intel cpu预解码以标记指令边界,然后解码阶段最多解码4个上限。David Kanter的Haswell写了一个前端图。
OP的数据从缓慢的JMP指令问题表明,一个巨大的块,但JMP指令运行在英特尔Broadwell(分支目标=next insn)每12时钟一个JMP,所以这是你最坏的情况下,取/解码气泡不能被隐藏,因为你没有做任何其他事情,给前端时间赶上。
我假设我们正在谈论从遗留解码器运行。从顶部缓存运行时的BTB丢失可能会稍短一些,因为解码后的顶部可用得更快。如果分支目标也在uop缓存中命中,那么在解码的uop可以开始进入解码的uop队列(与用作循环缓冲区的缓冲区相同)之前也会有更少的周期。
如果在取代码的过程中,解码的up队列没有清空,那么在问题阶段(将up发送到CPU的无序部分)可能没有任何气泡。
或者如果OOO部分有很多未执行的up要处理(即CPU正在执行一些具有瓶颈的代码,限制IPC远小于前端带宽),前端泡沫可能不会对其产生太大影响。
间接分支更糟糕。正确的目标最多要在几个周期之后才能被检测到,当jump up 在后端执行以检查预测时。从错误预测中恢复涉及回滚从错误路径执行的任何独立工作,不像在任何错误路径指令/up发出之前重新转向前端。
你的基本前提是正确的:间接分支不便宜,应该尽可能避免。(尽管一个间接分支可能比一个短链的条件分支更便宜,例如在这个例子中。)
相关:
- 当skylake CPU错误预测分支时会发生什么? 为什么英特尔这些年改变了静态分支预测机制?
- 分支目标预测与分支预测相结合?
- CPU架构的演变如何影响虚拟函数调用性能?