条件指令 (CMOV) 和跳转指令之间的区别



我很困惑在哪里使用cmov指令,在哪里使用jump汇编指令?

性能的角度来看:

  • 它们两者有什么区别?
  • 哪一个更好?

如果可能,请举例说明它们的区别。

movcc 是一个所谓的谓词指令。 这是"此指令在条件(谓词(下执行"的花哨说法。

许多处理器(包括 x86(在执行算术运算(尤其是比较指令(后,设置条件代码位以指示运算结果的状态。

条件

跳转指令检查条件代码位的状态,如果为 true,则跳转到指定目标。

由于跳转是有条件的,并且处理器通常具有深层管道,因此当 CPU 遇到 jmp 指令时,条件代码位可能实际上尚未准备好供 jmp 指令处理。 芯片设计人员可以简单地等待流水线耗尽(通常是许多时钟周期(,然后执行jmp,但这会使处理器变慢。

相反,他们中的大多数人选择使用分支预测算法,该算法预测条件跳转将走向何方。 然后,处理器可以获取、解码和执行预测的分支(或不执行(,并继续快速执行,条件是,如果最终到达的条件代码位被证明是错误的条件(分支错误预测(,处理器将撤消它在分支之后所做的所有工作,并沿着另一条路径重新执行程序。

条件跳转对于流水线执行比普通数据依赖关系更难,因为它们可以更改流经流的指令流中的下一个指令。 这称为控件依赖关系,而不是数据依赖关系(如add,其中两个输入都是其他最近指令的输出(。

分支

预测因子结果非常好,因为大多数分支往往对其方向有偏见。 (通常,大多数循环末尾的分支将分支回顶部(。因此,大多数时候处理器不必退出错误预测的工作。

如果分支的方向是高度不可预测的,那么处理器将在大约50%的时间内猜错,因此不得不撤回工作。 太贵了。

好的,现在,人们经常发现这样的代码:

  cmp   ...
  jcc   $
  mov   register1, register2
$: ; continue here
  ...
  ; use register1

如果分支预测器猜对了,则无论分支走哪条路,此代码都很快。 如果它猜错了很多...哎哟。

因此,条件移动指令。 这是根据条件代码位有条件地移动数据的移动。 我们可以重写上面的内容:

  cmp   ...
  movcc  register1, register2
$: ; continue here
  ...
  ; use register1

现在我们没有分支指令,因此没有使处理器撤消所有工作的错误预测。 由于没有控件依赖关系,因此无论movcc的行为是像mov还是nop,都需要获取和解码以下指令。 管道可以保持满状态,而无需预测条件并推测执行使用 register1 的指令。 (你可以用这种方式构建一个CPU,但它会破坏movcc的目的。

movcc将控件依赖项转换为数据依赖项。 CPU将其视为3输入数学指令,输入是EFLAGS及其两个"常规"输入(dest寄存器和源寄存器或存储器(。 在 x86 上,就无序执行跟踪依赖关系的方式而言,adccmovae(如果CF==0为 mov (相同:输入是 CF,并且都是 GP 寄存器。 输出是目标寄存器。

对于 x86,每个条件组合 cc 都有cmovccjccsetcc指令。 ( setcc根据条件将目标设置为 0 或 1。 因此,它对标志具有数据依赖性,并且没有其他输入依赖关系。

最新更新