在任何x86 CPU中,短分支距离都没有特殊情况。甚至是无条件的 jmp 到下一条指令(架构上是一个nop)需要有效处理正确的分支预测;如果你连续放入足够的BTB条目并且性能下降了悬崖。 缓慢的jmp指令
jmp
的 获取/解码只是一个小问题 强> ;是的,在同一个缓存行中的一个非常短的分支仍将在L1i和可能的uop缓存中命中。但是,解码器不太可能特殊情况下预测的前向跳转并利用包含分支和目标的一个块的预解码指令边界发现。
当指令被解码为uop并被送入前端时,寄存器值不可用;这些仅适用于乱序执行后端。
主要问题是当指示之后 .LBB1_67: 执行时,架构状态根据是否采用分支而不同。 微架构状态(RAT = Register Allocation Table)也是如此。
.LBB1_67:
或者:
r9
sbb
setl
mov r9d, r8d
setb
条件分支在计算机体系结构术语中称为“控制依赖性”。分支预测+推测执行避免将控制依赖性转换为数据依赖性。如果 je 预计不会被采取, setl 结果(旧的价值 r9 )被覆盖 mov 并且在任何地方都不再可用。
je
mov
在发现错误预测之后,没有办法从中恢复 je (实际应该已经采取),特别是在一般情况下。当前的x86 CPU不会尝试查找重新加入路径的直通路径,也不会查找有关它的功能的任何内容。
如果 cl 很长一段时间都没有准备好,所以很长一段时间都没有发现错误的预测,很多指示都在发布之后 or dl, r9b 本可以使用错误的输入执行。在一般情况下,可靠+有效恢复的唯一方法是放弃从“错误”路径完成的所有指令工作。检测到这一点 vpcmpeqb xmm0, [rbx - 16] 例如仍然运行任何一种方式很难,而不是寻找。 (现代英特尔,自Sandybridge以来,有一个分支顺序缓冲区(BOB),它在分支上快照RAT,允许在执行检测到它时立即高效回滚到分支未命中,同时仍允许无序执行 前 在回滚期间继续的说明。在那之前,一个分支小姐不得不回到退休状态。)
cl
or dl, r9b
vpcmpeqb xmm0, [rbx - 16]
一些非x86 ISA的CPU(例如我认为的PowerPC)已经尝试过将正好跳过1条指令的分支转换为预测(数据依赖性)而不是推测它们。例如 动态吊床预测 用于非谓词指令集架构 讨论了这个想法,甚至决定是否在每个分支的基础上进行谓词。如果你的分支预测历史表明这个分支预测不好,那么预测它可能是好的。 (一个Hammock分支是向前跳过一个或几个指令的分支。在具有固定宽度指令字的ISA上检测正好1个指令的情况是微不足道的,如RISC,但在x86上很难。)
在这种情况下,x86有一个 cmovcc 指令,ALU选择操作,根据标志条件产生两个输入之一。 的 cmove r9d, r8d 代替 cmp / je 这将使分支错误预测免疫,但代价是引入数据依赖 cl 和 r8d 使用说明 r9d 。英特尔CPU不会尝试为您执行此操作。 强>
cmovcc
cmove r9d, r8d
cmp
r8d
r9d
(在Broadwell和后来的Intel上,cmov只有1 uop,低于2. cmp / jcc是1 uop,而且 mov 本身也是1 uop,所以在未采取的情况下 cmov 前端的uops也更少了。在所采用的情况下,即使预测正确,也可以在管道中引入气泡,具体取决于代码的吞吐量有多高:阶段之间的队列是否可以吸收它。)
cmov
看到 gcc优化标志-O3使代码比-O2慢 对于CMOV比分支慢的情况,因为引入数据依赖性是不好的。