为什么大部分的x64指令会将32位寄存器的上半部分清零?

今天我了解了x64程序集(资料来源: http : //x86asm.net/articles/x86-64-tour-of-intel-manuals/ )

也许最令人惊讶的事实是,诸如MOV EAX,EBX之类的指令自动将RAX寄存器的高32位清零。

英特尔文档(3.4.1.1通用基本体系结构中的64位模式的通用寄存器)在同一来源中引用告诉我们:

  • 64位操作数在目标通用寄存器中生成一个64位结果。
  • 32位操作数产生一个32位结果,在目标通用寄存器中零扩展为一个64位结果。
  • 8位和16位操作数生成8位或16位结果。 目标通用寄存器的高56位或48位(分别)不会被操作修改。 如果8位或16位操作的结果是用于64位地址计算的,则明确地将寄存器扩展为完整的64位。

在x86-32汇编中,16位指令如

mov ax, bx 

不要performance出这种eax的上位字“零”的“奇怪”的行为。

因此:这种行为被引入的原因是什么? 乍一看这似乎不合逻辑(但原因可能是我习惯了x86-32汇编的怪癖)。

我不是AMD或者为他们说话,但是我会以同样的方式来做。 因为调零高半并不会创build一个依赖于以前的值,该CPU将不得不等待。 如果没有这样做,寄存器重命名机制基本上会被击败。 这样,您就可以在64位模式下编写快速的32位代码,而不必一直明确地破坏依赖关系。 如果没有这种行为,64位模式下的每一个32位指令将不得不等待之前发生的事情,即使这个高的部分几乎不会被使用。

16位指令的行为是奇怪的。 依赖性的疯狂是现在回避16bit指令的原因之一。

它只是在指令和指令集中节省空间。 您可以使用现有的(32位)指令将小的立即数值移动到64位寄存器。

MOV EAX, 42可以被重新使用时MOV RAX, 42它也MOV RAX, 42MOV RAX, 42编码8个字节值。

对于8位和16位操作系统来说,这种优化并不重要(因为它们更小),改变规则也会破坏旧代码。