CMOV是如何提高CPU流水线性能的?

30

我明白当一个分支很容易预测时,最好使用IF语句,因为该分支是完全自由的。我已经学到了如果该分支不容易预测,那么CMOV更好。然而,我不太明白这是如何实现的?

显然,问题域仍然是相同的-我们不知道要执行的下一条指令的地址吗?所以我不明白从流水线的最深处开始运行CMOV时,如何帮助指令提取器(在过去10个CPU周期)选择正确的路径并防止流水线停顿?

请问有人能帮我理解CMOV如何改善分支吗?


3
如果我们“不知道要执行的下一条指令的地址”怎么办? 如果指令序列是 I1; CMOV; I3,那么指令I1,然后是CMOV,最后是I3被依次执行,总是按照这个顺序。跟在I1之后的是CMOV。跟在CMOV之后的是I3 - Pascal Cuoq
一个指令长的分支是一个非常特殊的情况;它可以进行一些通用分支无法实现的优化。 - Seva Alekseyev
Pascal,那么这与IF语句有什么不同?我们知道两个分支的起始指令... - user997112
3
您可以将CMOV视为根本不是分支,而是一条指令,效果为Dest = (Dest AND NOT Condition) OR (Source AND Condition),其中Source、Dest和Condition都是位。 - Seva Alekseyev
1
Seva的解释比任何一个答案都好得多。这是一种数据依赖,而不是控制依赖。它有3个输入(dest、src和flags),并产生一个输出(dest)。对于OOO流水线,它可以像adc一样精确追踪(adc也具有相同的三个输入和一个输出)。 - Peter Cordes
2个回答

20

请问有人能帮我理解CMOV如何改善分支吗?

实际上,它并不是改善分支,而是消除分支。CMOV可以被视为两个指令的组合,即MOV和NOP。哪一个指令被执行取决于标志位。因此,在内部它看起来可能像这样:

if (cond) {
    mov dst, src
} else {
    nop
}

问题域仍然相同-我们不知道要执行的下一条指令的地址吗?

嗯,不是这样的。下一条指令总是跟随CMOV的指令,因此指令流水线不会被无效化和重新加载(忽略分支预测和其他优化)。它是一连续的宏操作码流。以下是一个简单的例子

if (ecx==5)
    eax = TRUE
else
    eax = FALSE

在基本汇编中:

cmp ecx,5      ; is ecx==5
jne unequal    ; what is the address of the next instruction? conditional branch
mov eax,TRUE   ; possibility one
jmp fin
unequal:       : possibility two
mov eax,FALSE
fin:
nop

使用CMOV

cmp ecx,5
mov eax, FALSE   ; mov doesn't affect flags
mov ebx, TRUE    ; because CMOV doesn't take immediate src operands, use EBX for alternative
cmove eax, ebx   ; executes as MOV if zero-flag is set, otherwise as NOP
nop              ; always the next instruction, no pipeline stall

在当前的CPU上是否值得使用?明确的答案是肯定的。根据我的经验和(当然)算法的不同,速度提升是显著的,值得付出努力。


2
cmove不允许立即操作数。因此,您需要清除一个寄存器:mov ebx, TRUE然后cmove eax, ebx - Björn Lindqvist
没错。如果你没有多余的寄存器,可以使用变量像ddTRUE。 - zx485
2
或者,在这种特定情况下,使用sete - alecov

20

CMOV指令不直接控制程序流。它们是基于条件码执行的指令,用于计算结果,也就是被谓词化的指令。一些体系结构(如ARM)可以根据条件码谓词许多形式的指令,但x86只能使用"mov",即有条件移动(CMOV)。这些指令需要解码并在执行时延迟以确定指令的结果。

另一方面,分支则是预测和实际导向指令执行的。分支预测器“向前看”,专门查找分支指令,并通过导向控制流来预测路径。类比铁路轨道上的人员会将铁轨向左或向右移动,以告诉列车该往哪里走。如果那个人选择了错误的方向,列车就必须停下来、倒车,然后再朝正确的方向行驶。浪费大量时间。

与此不同,CMOV并未引导流程。它们只是简单的指令,需要额外的时间(并创建附加依赖项),以根据条件码来确定移动的正确结果。类比列车不决定向左还是向右走,而是沿着一条不需要拐弯的直路前进,但速度较慢(显然更为复杂,但这是我现在想到的最好的比喻)。

CMOV曾经效率非常低(延迟很高),但现在已经得到改进,变得相当快,使它们更加实用和高性能。

希望这有所帮助。


9
回答不错,不过我希望cmov的火车示例能够包括一些在铁路公司之间分配车厢的内容,其中一个最终会跌入深渊(显然还必须有一场屋顶格斗场景) - Leeor
从我的测试来看,在某些情况下,短跳(1-4条指令)会更快。 - BitBank

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