Assembly CMOV提高CPU管道性能的原因是什么?

Assembly CMOV提高CPU管道性能的原因是什么?,assembly,x86,branch,cpu-architecture,Assembly,X86,Branch,Cpu Architecture,我理解当一个分支很容易预测时,最好使用IF语句,因为该分支是完全自由的。我了解到,如果分支不容易预测,那么CMOV更好。然而,我不太明白如何才能做到这一点 当然问题域仍然是相同的-我们不知道下一条要执行的指令的地址?因此,我不明白在执行CMOV的过程中,如何帮助指令获取程序(过去10个CPU周期)选择正确的路径并防止管道暂停 有人能帮我理解CMOV是如何改进分支的吗 CMOV指令不引导控制流的路径。它们是根据条件代码计算结果而执行的指令,即谓词指令。一些体系结构(如ARM)可以基于条件代码断言多

我理解当一个分支很容易预测时,最好使用IF语句,因为该分支是完全自由的。我了解到,如果分支不容易预测,那么CMOV更好。然而,我不太明白如何才能做到这一点

当然问题域仍然是相同的-我们不知道下一条要执行的指令的地址?因此,我不明白在执行CMOV的过程中,如何帮助指令获取程序(过去10个CPU周期)选择正确的路径并防止管道暂停


有人能帮我理解CMOV是如何改进分支的吗

CMOV指令不引导控制流的路径。它们是根据条件代码计算结果而执行的指令,即谓词指令。一些体系结构(如ARM)可以基于条件代码断言多种形式的指令,但x86只能执行“mov”,即条件移动(CMOV)。为了确定指令的结果,这些指令被解码并延迟执行

另一方面,分支是预测的,并实际指导指令的执行。分支预测器“向前看”指令“fetcher”,专门寻找分支指令,并通过控制流来预测路径。想象一下一条铁路轨道,前面的一个人将轨道向左或向右移动,告诉火车去哪里。如果那家伙选错了方向,火车必须停下来,后退,然后再朝正确的方向移动。浪费了很多时间

另一方面,CMOV不会控制流量。它们只是指令,需要花费额外的时间(并创建额外的依赖项)根据条件代码找出移动的正确结果。想想火车,它不是决定向左或向右行驶,而是走一条直线,不需要转弯,但速度稍慢(显然要复杂一些,但这是我现在能想到的最好的方法)

CMOV过去非常糟糕(延迟非常高),但后来改进得非常快,使其更具可用性和性能价值

希望这有帮助

有人能帮我理解CMOV是如何改进分支的吗

嗯,它并没有改善分支,而是消除了分支。CMOV可以看作是一个MOV和NOP中的两条指令。执行哪一个取决于标志。因此,在内部,它可能看起来像

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

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

嗯,不是。下一条指令总是在CMOV之后的指令,因此指令管道不会失效和重新加载(分支预测和其他优化放在一边)。这是一个连续的宏操作码流。下面是一个简单的例子

if (ecx==5)
    eax = TRUE
else
    eax = FALSE
在基本asm中:

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上值得吗?一个明确的答案是肯定的。根据我的经验和(当然)取决于算法,速度增益是显著的,值得付出努力。

如果指令序列是
I1,我们如何“不知道要执行的下一条指令的地址”的可能重复;CMOV;I3
,指令
I1
,然后
CMOV
,然后
I3
始终按此顺序执行。在
I1
之后的是
CMOV
。在
CMOV
之后的是
I3
;它有助于实现通用分支不承认的优化。或者,您可以将CMOV视为根本不是分支,而是一个命令,其效果是
Dest=(Dest和not条件)或(Source和Condition)
,其中Source、Dest和Condition是位。Seva的解释比这两个答案都好。它是数据依赖项,而不是控件依赖项。它有3个输入(dest、src和标志),并产生一个输出(dest)。对于OOO管道,它可以像adc(具有相同的三个输入和一个输出)一样进行跟踪。答案很好,尽管我希望cmov的火车示例可以包括以某种方式在铁路之间拆分手推车,其中一个最终坠入深渊(显然也会有屋顶打架的场景)根据我的测试,短跑(1-4个指令)在某些情况下速度会更快。
cmove
不允许立即操作数。因此您需要对寄存器进行加密:
mov ebx,TRUE
然后
cmove eax,ebx
。没错。如果没有备用寄存器,可以使用ddTRUE之类的变量。或者,在这种特殊情况下,
sete