“cqo”、“cdq”和“cwd”x86_64 指令。为什么不只使用 cqo?

Hus*_*sky 6 assembly x86-64

我不是最有经验的汇编程序员,我遇到了“cqo”、“cdq”和“cwd”指令,它们都是有效的 x86_64 汇编。

我想知道在操作较小的值时使用 cdq 或 cwd 是否有任何优势。性能上有什么区别吗?

编辑:最初在计算一位数的绝对值时开始研究这一点。

例如,如果我们在 al 中有 -9 值:

cwd
xor al,dl
sub al,dl
Run Code Online (Sandbox Code Playgroud)

与将其作为 32 位值并计算

cdq
xor eax,edx
sub eax,edx
Run Code Online (Sandbox Code Playgroud)

或者如果我们有 -9 的 64 位值

cqo
xor rax,rdx
sub rax,rdx
Run Code Online (Sandbox Code Playgroud)

如果原始值是 64 位并且由一个值 -9 到 9 组成,那么实际上它们看起来都是一样的。

Pet*_*des 4

仅当您的值已进行符号扩展以填充超过 16 位的 rax 时,您才可以选择。

如果 ax 中有一个有符号的 16 位 int,但 eax 的上位 16 未知或为零,则必须继续使用 16 位指令。 cdq会根据 eax 顶部的垃圾位设置 edx,而不是 ax 中值的符号位。

类似地,如果您使用 32 位操作在 eax 中生成带符号的 32 位 int,则 upper32 将被清零,而不是符号扩展。

如果可以的话,请使用cdq. cqo如果您需要在 rdx 中设置所有 64 位,则可能需要。


请参阅http://agner.org/optimize/了解如何制作在 x86 上快速运行的 asm。64 位模式下默认为 32 位操作数大小,因此 16 或 64 位操作数需要额外的前缀。这意味着更大的代码大小,这意味着更差的 I-cache 效率(并且在 Sandybridge 之前的 CPU 上通常会出现更多解码瓶颈;SnB 的 uop 缓存通常意味着解码不是问题。)

16 位还对寄存器先前的内容有错误的依赖,因为写入 ax 不会清除 rax 的其余部分。幸运的是,AMD64 在设计时就考虑到了乱序 CPU,因此它通过在写入 GP reg 的低 32 位时清除 upper32 来避免重复对高性能带来不便的设计选择。(x86 CPU 在设计 AMD64 时就已经使用了 OOO,这与 ax 扩展为 eax 时不同)。

  • [为什么大多数 x64 指令将 32 位寄存器的上部清零](http://stackoverflow.com/q/11177137/995714) (2认同)