为什么大部分的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, 42
为MOV RAX, 42
编码8个字节值。
对于8位和16位操作系统来说,这种优化并不重要(因为它们更小),改变规则也会破坏旧代码。