64位跳跃的成本,第一次总是10-22个周期?

时间:2016-09-25 00:22:12

标签: x86 x86-64 micro-optimization

在x86_64中,没有64位地址的直接跳转。只有32位一个。 通过间接跳转,我理解在分支预测发挥作用之前,管道必须被解决。 我的问题是:在第一次执行时,64位是否无法进行1-3次跳转?

1 个答案:

答案 0 :(得分:3)

即使没有I-cache未命中,直接跳转并不总是那么便宜"第一次"他们仍然需要分支预测。

在长模式下,jcc rel32jmp rel32(以及rel8紧凑版本)使用RIP的符号扩展相对位移。您可以跳转到任何64位地址,只要您来自2GB以内的地址即可。因此,请将代码保存在其他代码的2GB范围内,以便可以使用rel32替换。

长模式没有绝对的直接跳跃。 32位模式远JMP ptr16:32 (opcode 0xEA)和远CALL 16:32根本没有64位版本。 (无论如何,为了性能和方便,你不想要一个远jmp。)SYSCALL和INT之类的指令是间接跳转(带隐式目的地),并且无论如何都不是很有用。

还没有指令预取/预编码指令来使L1 I-cache或uop缓存中的目标热,或者提示将很快需要来自给定地址的解码指令的管道的任何方式。 (请参阅PREDECODE wishlist section in Darek Mihocka's article关于模拟器中的间接跳转,将一个guest虚拟机指令的处理程序直接跳转到下一个guest虚拟机指令的处理程序是有用的,而不是有一个间接调用分派指令几乎总是会误判。)

即使是直接跳转也需要分支目标缓冲区来预测下一个获取块应来自其他地方。这个信息比解码阶段早得多,因此必须预测它可以避免显着的前端气泡。最近提出了一个有趣的问题:Slow jmp-instructionRealworldtech forum thread上的回复清楚地表明,分支预测需要处理获取块,而不仅仅是指令,即使在简单到解码的固定宽度ISA上(与x86不同),您需要进行预测早于解码结果。

对于新见的直接(rel32)跳转,1-3个周期对于代码获取气泡的大小是不现实的。但是,解密的uop队列可能会隐藏部分气泡。

解码的代码获取可能至少有5或6个周期,甚至可能更多。让我们说L1-I命中时间是4个周期,与Haswell的L1D负载使用延迟相同。然后Intel CPU进行预解码以标记指令边界,然后解码阶段解码最多4个uop。 David Kanter's Haswell writeup has a diagram of the frontend

来自Slow jmp-instruction问题的OP的数据表明除了JMP指令之外什么都没有,只有一个JMP指令在英特尔布罗德威尔每12个时钟运行一个JMP (带有分支目标) = next insn),这是你最糟糕的情况,因为你没有做任何让前端有时间赶上的事情,因此根本无法隐藏获取/解码气泡。< / p>

我假设我们正在谈论从传统解码器运行。运行from the uop cache时BTB未命中可能会略短,因为解码后的uop可用得更快。如果分支目标也在uop缓存中命中,则解码后的uop可以开始进入解码的uop队列(用作循环缓冲区的相同缓冲区)之前的周期也更少)。

如果在代码获取泡沫期间解码的uop队列没有空,那么在发布阶段可能没有任何气泡(将uops发送到CPU的无序部分)。 / p>

或者如果OOO部分有很多未执行的微操作(即CPU正在执行一些带有瓶颈的代码,将IPC限制为远低于前端带宽),前端气泡可能不会影响太多了。

间接分支更糟糕。无法检测到正确的目标,直到最后几个周期。您的基本前提是正确的:它们并不便宜,应该尽可能避免。