【问题标题】:Why does x86 only have 1 form of conditional move, not immediate or 8-bit?为什么 x86 只有一种形式的条件移动,而不是立即数或 8 位?
【发布时间】:2021-01-12 23:53:07
【问题描述】:

我注意到Conditional Move 指令的可扩展性不如普通的mov。例如,它不支持立即数,也不支持寄存器的低字节。

出于好奇,为什么Cmov 命令比一般的mov 命令更严格?例如,为什么两者都不允许:

mov    $2, %rbx    # allowed
cmovcc $1, %rbx    # I suppose setcc %bl could be used for the '1' immediate case

附带说明一下,在使用 Compiler Explorer 时,我注意到 cmovcc 的使用率远低于 jmpccsetcc。通常是这样吗?如果是这样,为什么它的使用频率低于其他条件句?

【问题讨论】:

  • 我最近一直在学习aarch64上的条件选择指令,比较起来很有意思。它们也没有立即数,但它们确实有增加、补充或否定两个值之一的变体。由于它们有一个零寄存器,这实际上为您提供了几乎所有 0、1 和 -1 的组合作为“立即数”,这可能涵盖了 98% 的可能用例。
  • 英特尔说了什么?我不知道最初的创作者还在附近,或者在等待你为什么做这些问题,但你可能会走运。
  • 请注意mov instruction(程序集中没有commands,只有instructions)实际上是关于十几个具有相同名称的不同指令。这就是为什么它看起来如此多才多艺。

标签: assembly x86 cpu-architecture instructions conditional-move


【解决方案1】:

作为条件,它已经需要 16 个不同的操作码,仅用于 cmov r, r/m 形式,每个不同的 cc 条件对应一个,就像 jccsetcc(当然,同义词共享一个操作码)。

因此,即使有另外 16 个0F xx 操作码的“空间”,当英特尔为 Pentium Pro 添加它时,花费所有编码空间可能也不值得。好吧,也许是一个符号扩展的 imm8 表格。这将占用其他新操作码的空间,例如英特尔可能已经开始设计或至少考虑在 P6 的 ISA 扩展完成时为 Pentium-MMX 和 Pentium III 设计的 MMX 和 SSE 指令。

当您需要cmov(通常有条件地将某些东西归零)时,大多数时候imm8 表单会很有用,但它不是必需的。 RISC 哲学(英特尔在 P61 中采用的理念)倾向于只提供一种方式,并在需要时让代码使用 mov-immediate 在另一个寄存器中创建一个常量。

乱序执行通常可以隐藏mov-immediate 的成本,将常量放入另一个寄存器。这样的指令独立于其他所有指令,只要在它被调度到的执行端口上有一个空闲周期就可以执行。 (然而,前端通常是一个真正的瓶颈,静态代码大小确实很重要,所以很遗憾它不是免费的。)

脚注 1:RISC 的想法对于 P6 微架构来说是一件大事,最引人注目的是将 x86 指令解码为 1 或更多微指令的革命性想法,用于其类似 RISC 的后端,允许输出例如,一条内存目标指令(加载/ALU/存储)的不同部分的按顺序执行。

但在较小的决策中也是如此,例如 P6 没有硬件支持来维持一条指令的微指令之间的 TLB 一致性。这就是为什么adc %reg, (mem) 需要比您在英特尔 CPU 上预期的更多的微指令。 Andy Glew(从事 P6 工作的英特尔架构师)解释说,在 Stack Overflow cmets(我在 this answer 中引用)中,包括说“我加入 P6 时是 RISC 支持者,我的态度是“让 SW(微代码)去做”。'

很容易看出这种态度如何扩展到 x86 ISA 设计,并且只提供了cmov 的最低限度的形式。 (几乎不需要 8 位;您始终可以移动整个寄存器,并且您 often want to avoid partial registers in high-performance code 无论如何,因为可能会出现停顿。这在 PPro 上比在后来的 P6(如 Core 2)上更昂贵。Sandybridge 家族进行了部分寄存器合并更便宜。)

但这纯粹是我对可能影响该设计决策的因素的猜测。


必须权衡添加晶体管以解码 cmov 的 imm8imm32 和/或 r/m8 编码的成本(功率和芯片面积以及可实现的时钟速度)期望代码能够使用它而在现实世界中加速。以及未来使用更多操作码编码空间的成本。

除了编码空间的未来成本(让 MMX 和 SSE1 指令只有 2 字节的操作码)之外,英特尔可能会通过省略 cmov $sign_extended_imm8, %reg 来猜错,这实际上经常很有用。


它的使用较少,因为它仅在计算条件两边的结果并选择一个条件的成本较低时才有用,而不仅仅是分支并只做一个。它作为一种优化很有用,尤其是当编译器预计分支预测不佳时。 Purpose of cmove instruction in x86 assembly?

关于控制依赖(分支)与数据依赖(cmov)的更一般的 cpu 架构背景:difference between conditional instructions (cmov) and jump instructions

请参阅Conditional move (cmov) in GCC compiler re: 当 GCC 将 if-conversion 转换为无分支 asm 时。

如果你做错了 (gcc optimization flag -O3 makes code slower than -O2),使用 cmov 甚至会受到伤害,因为分支预测可以非常准确地预测(例如,在排序输入数据的特殊情况下)。

在具有更短/更窄管道和更小的乱序执行资源(因此错误预测的成本更低)的旧 CPU 上,CMOV 在更少的情况下有用。特别是在 Broadwell 之前的 Intel 上,它需要 2 微秒而不是 1 微秒。Linux Torvalds 解释了为什么它在很多常见情况下都很糟糕,早在 2007 年就在 Core 2 CPU 上进行了一些测试:https://yarchive.net/comp/linux/cmov.html

但是,如果您编写的代码根据条件从几个值中进行选择,那么编译器生成它的情况当然并不罕见。 Clang 的启发式倾向于使用比 GCC 更多的 cmov,即更积极的 if 转换到无分支。


请注意,setcc 也不会经常使用,除非您经常查看返回布尔值的非内联版本的函数。

我在我的 Arch Linux 桌面上反汇编了libperl.so(刚刚选择了一个随机的大型二进制文件),由 GCC 10.1.0 编译。在总共 377835 条指令中 (objdump -d | egrep ' +[0-9a-f]+:'| wc -l):

  • setcc出现1783次,经常在setxx a/setxx b/or a,b多条件下做一个分支。

  • cmovcc 出现了 1737 次。 objdump -drwC -Mintel /usr/lib/perl5/5.32/core_perl/CORE/libperl.so | egrep 'cmov[a-z]+ ' | wc

【讨论】:

  • 我不同意它没有用;在我使用 cmov 的 98% 的时间里,我都需要立即使用它。
  • @prl:我实际上同意这一点。如果有一个循环,从循环中提升常量设置是一件麻烦事,否则它纯粹是开销。符号扩展的imm8 表单可能值得编码空间。因此,也许我们应该改为说它不是必要,而英特尔正试图将 RISC 理念与 P6 结合起来,有时会损害设计。
  • 我认为操作码平面中可用空间不足可能是主要问题。请注意,如果您想要立即形式(8 位立即数,16/32 位立即数),您实际上需要 2x16 操作码。我的意思是他们本可以将一些位移动到第二个操作数中,而您不需要立即移动的变体,但我想它最终被拒绝了。
  • @fuz:我的意思是只提供一个imm8 表单,使用mov 到一个tmp reg 的更大立即数。许多用例涉及少量数字。实际上,您可以使用 modrm 中的 /r 字段来编码 3 个操作码位,就像许多立即指令一样,将其减少到 2 个总操作码,但请注意 setcc 也不会这样做。解码器已经知道如何从操作码本身的低位(对于 JCC)解码 4 位条件,并且 JCC 和 SETCC 都以这种方式工作,将条件码位保持在同一个位置是有意义的.即使它确实会消耗更多的编码空间
  • @fuz:我想如果r/m32 对内存目标进行编码,英特尔会将其设计为#UD,或者只使用任何常见的uop生成句柄来生成加载和存储,让用户如果他们愿意,就在自己的脚下开枪。解码器已经知道如何解码来自/r 的操作码位,否则您将使用/r 作为目标,并且在 Mode 和 r/m 字段之间总共有 5 个操作码位。 IIRC,至少还有一条其他指令只允许寄存器作为 r/m,但我忘记了。 (它可能比 P6 更新,并且可能有特权?)有些只允许 mem...
猜你喜欢
  • 2013-12-03
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-24
  • 2019-11-01
  • 1970-01-01
  • 2021-11-26
相关资源
最近更新 更多