执行is mov rax,0x12345678; jmp rax是否仍会破坏分支预测?

4

我在寻找特定于上述两种情况的信息方面遇到了困难,希望听取你的专家意见。

首先:我知道间接跳转会损害分支预测,即使间接跳转的结果是常量,仍需要进行预测维护缓冲等操作,与绝对跳转相比。我的问题是,是否有人知道:

mov rax, 1234567812345678h;
jmp rax;

处理器的分支预测仍然认为这是间接跳转,或者在这种情况下它会计算数学运算..我这样做是因为x64没有直接的“jmp absolute 64”指令,只有间接的。:/(如何执行带有64位绝对地址的调用指令?如果您无法将跳转放得足够靠近目标并使用jmp rel32,则建议使用此方法。)


其次,在这种程度上,jmp 0x1234和call 0x1234之间是否存在任何真正的区别(就处理器优化而言(指令缓存,预取器及其提示,分支预测))?(vc2012“速度优化”产生的是call,“min_size opt”产生的是jmp,“mixed optimization”产生的是x64的jmp,x86的call)


7
不要混淆分支预测和分支目标预测。分支预测是指分支是否会跳转。分支目标预测是指分支将跳转到哪里。在这种情况下,没有分支预测 - 它是一个无条件跳转。 - Mysticial
我还想补充的是,在这种情况下,分支目标预测很可能会非常好(如果CPU记得上次的分支目标,那么...)。 - Brendan
所以如果我理解正确的话,从 CPU 硬件资源的角度来看,那个 RAX 被硬编码预初始化到一个固定地址和那个 RAX 是易失性的并没有太大的区别,它们都会使用 CPU 的目标预测资源?(后一种情况的唯一额外成本将是从另一个变量间接读取 RAX,例如),或者说“它在一行之前被硬编码预初始化了,所以我不需要占用分支目标历史缓冲区”更明智吗? - win32 devPart
我所关心的是预取器/流水线早期阶段是否会认为由于jmp是基于eax的,因此它不是“绝对”的,因此它不能预取目标指令,直到最后一刻才到达jmp(当它确切知道rax值时),而不是得出rax是硬编码的结论,因此jmp是绝对的。 - win32 devPart
2个回答

2
英特尔的分支目标(和分支)预测既非常复杂,又是一个严格保密的商业机密。并不一定有单一的算法,也就是说,你可以期望预测机制在不同的CPU上有所变化;这取决于英特尔为给定处理器解决问题投入的晶体管数量。当然,除了英特尔之外,还有其他x86和x64处理器制造商。
历史分支目标预测机制——利用相同指令过去的运行来预测后续执行的目标——几乎肯定会对这个分支预测正确的目标,因为只有一个目标。因此,如果这段代码序列被重新执行(例如在循环中),并且它在指令缓存中停留了一段时间,那么它很可能会被很好地处理。(但是,在某些处理器上,如果其他地方的另一个分支导致哈希冲突,分支目标预测机制可能会被中和类似于缓存行碰撞的影响。)
更大的问题可能是,如果这样的序列在新加载到缓存中的代码中频繁出现,它将如何被处理,这与处理器的非基于历史的目标预测能力有关。这种(非历史)分支目标预测可以轻松确定给定这个代码序列的分支位置,但它完全取决于制造商是否认为它值得在任何给定处理器的芯片上使用。作出这样的决定的因素包括功耗、其他性能改进的权衡(即同一芯片区域可能有更好的用途),以及这种和各种其他代码序列的预期频率。

1
但是Agner记录了Intel的一些CPU特性;分支预测在第11-34页。 - osgx
我从未听说过任何x86-64 CPU将mov r64,imm64 / jmp reg融合为单个直接跳转uop,或者甚至根据此进行预测。ARM CPU对类似于拇指分支的东西做了一些处理,这在技术上是两个指令,一个用于设置分支目标的某些位,另一个用于具有其余部分和跳转。但是这只作为一对使用,并且没有寄存器副作用,并且很常见。对于x86分支,没有一个是真实的:更常见的是内存间接分支(所有调用都进入动态库)。 - Peter Cordes

1

"我知道间接jmp会影响分支预测"

不是的。分支预测和间接跳转预测是不同的。此外,间接跳转在基于表的 switch 语句和解释器中被使用。这些都是非常常见的用例,并出现在基准测试中。因此,英特尔和其他公司花了很多精力和晶体管来提高它们的性能。一篇论文(在问题之后写的!)甚至到了这样的地步:从 Sandy Bridge 开始,你不应该相信民间传说,当涉及到这种间接跳转预测时。英特尔和AMD有动力提高这种性能,他们也确实这样做了。

现在,如果您的 jmp 示例是冷代码,如果这是第一次执行它,那么它是不可能被预测的,事实上 Skylake 的间接跳转预测器将预测跳转后的下一条指令并进行推测。您可以通过使用 UD2(一个非法指令)关闭该推测。无论如何,如果 jmp 仍然在 BTB 中,第二次执行时,分支目标将是正确的。

至于您的第二个问题,缓存效应并不重要。我想较小的版本可能会英勇地节省缓存行溢出,但仅此而已。硬件预取器是为数据而不是指令而设计的。


你提供的论文链接 (https://hal.inria.fr/hal-01100647/document) 表明在解释器中,Haswell 而不是 SnB 真正擅长预测 grand-central-dispatch 分支(据信使用 IT-TAGE)。当然,总是跳转到同一位置的间接分支要容易得多,并且任何形式的间接分支预测都会成功(除非存在破坏性别名),因此即使是 Atom 或 Pentium 2,如果该分支经常运行,也几乎没有问题。 - Peter Cordes
在下一代处理器Sandy Bridge上,错误预测率要低得多。重点是他们已经解决了几代。 - Olsonist
1
顺便提一下,分支预测通常包括间接分支的目标预测。你有点暗示它们是两个不同但类似范围的东西,就像分支方向预测与间接分支目标预测之间的关系。据我所知,“分支预测”没有一个特定的单一含义,排除了间接分支。此外,请注意,在当前块被解码以查看是否包含任何相对直接分支之前,前端需要预测要获取哪个。(Slow jmp-instruction) - Peter Cordes
好的,是的,SnB比NHM有更好的分支预测器。但最大的变革是在Haswell中,它首次使用IT-TAGE来改变预测器的内部工作方式,正如该论文所示,包括它的图表等等。特别是因为您在那段落中谈论译码器,所以是Haswell使得简单调度表现良好。 - Peter Cordes
1
Core i7分支预测器的CAAQA部分描述了有条件分支的2位和锦标赛预测器。但是它接着描述了间接预测器,称“一个单独的单元为间接分支预测目标地址”。我认为这意味着它们不会竞争相同的BTB插槽。至于分支与跳转预测,在CAAQA的ILP极限研究中进行了区分。(但顺便说一句,那本书的定义很糟糕。)至于预取器,我不知道硬件缓存行预取指令是一种什么东西。L1i内存预取还是仅仅是缓存提升? - Olsonist
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接