为什么英特尔没有提供其CPU寄存器的高阶部分?

Bla*_*ear 6 x86 assembly cpu-registers

当我在汇编中进行编程并进行某种字符串操作时,我会使用al,ah有时候其他人也会使用字符,因为这样可以让我在寄存器中保留更多数据.我认为这是一个非常方便的功能,但英特尔的工程师似乎不同意我,因为他们没有使寄存器的两个高位字节可访问(或者我错了?).我不明白为什么.我想了一会儿,我的猜测是:

  1. 它们会使CPU太复杂
  2. 他们没用
  3. 也许两者都是上面的

我想到了第二,因为我从未见过使用过的编译程序(al或使用gcc)bh或者其中任何一个.

Jer*_*fin 9

虽然它有点笨拙,但您可以将寄存器的两半交换rol reg,16(或者ror reg,16,如果您愿意).在Netbust CPU(Pentium IV)上效率非常低,但在大多数较新(或较旧)的CPU上,你通常会有一个桶形移位器在一个时钟内完成.

至于为什么他们没有这样做,这很简单:他们需要彻底重新设计指令编码,如果他们真的想这样做的话.在原始设计中,他们使用了所有符合其用于指定寄存器的字段大小的代码.实际上,他们已经使用了一些hack,其中编码的含义取决于模式,如果需要使用不同的大小,则有地址大小和操作数大小前缀.例如,要在32位模式下运行时使用AX,该指令将在指令本身之前具有操作数覆盖前缀.如果他们真的想要足够严重,他们可以扩展这个概念来指定诸如"寄存器X的16-23位中的字节"之类的东西,但它会使解码变得更复杂,并且解码x86指令已经相对痛苦了.


dwi*_*del 6

简短的回答是因为它是如何从16位进化而来的.

为什么没有包含更高字节EAX的寄存器?


Ste*_*non 5

除了Jerry正确提到的指令编码问题之外,还有其他一些工作要做.

大多数非平凡的CPU都是流水线的:这意味着在普通操作中,指令在前一条指令完成执行之前开始执行.这意味着处理器必须检测先前指令上的指令的任何依赖性,并防止指令执行,直到它所依赖的数据(或条件标志)可用[1].

为寄存器的不同部分设置名称会使这种依赖性跟踪变得复杂.如果我写:

mov  ax,  dx
add  eax, ecx
Run Code Online (Sandbox Code Playgroud)

然后核心需要知道它ax是其中的一部分eax,并且添加应该等到移动的结果可用.这称为部分寄存器更新 ; 虽然看起来非常简单,但硬件设计人员通常不喜欢它们,并尽量避免需要尽可能地跟踪它们(特别是在现代无序处理器中).

具有寄存器高半部分的名称会增加一组必须跟踪的部分寄存器名称,这会增加芯片面积和功耗,但几乎没有什么好处.在一天结束时,这就是CPU设计决策的方式:芯片面积(和功率)与效益的权衡.

通过为寄存器的高位部分命名,部分寄存器更新不是唯一复杂的事情,但它是最简单的解释之一; 还有许多其他小东西需要在现代x86 CPU中变得更加复杂以支持它; 综合考虑,额外的复杂性将是巨大的.

[1]还有其他方法可以解决依赖关系,但为简单起见,我们在此忽略它们; 他们引入类似的问题.