零寄存器如何提高性能?

8
在MIPS ISA中,有一个零寄存器($r0),它始终给出零值。这使处理器能够:
  1. 任何产生要丢弃结果的指令都可以将其目标指向此寄存器
  2. 成为0的来源。
据称在这个来源中提到,这提高了CPU的速度。它是如何提高性能的?为什么不是所有ISA都采用这个零寄存器呢?

$r0 不是通用寄存器。它被硬连线接到 0 上。无论你对这个寄存器做什么,它始终具有0的值。您可能会想知道为什么 MIPs 需要这样一个寄存器。

MIPS 的设计人员使用基准测试(用于确定 CPU 性能的程序)使他们相信,将寄存器硬连线接到0会改善 CPU 的性能(速度)而不是没有它。并非每个人都同意硬连线接到0的寄存器是必需的,因此并不是所有的ISA都有零寄存器。


也许零寄存器可以使CPU更快,因为它允许用更少的指令编写许多程序。 - Konrad Lindenbach
4个回答

15

这可能有几种方式可以提高性能,不清楚哪些适用于特定的处理器,但我大致按照从最可能到最不可能的顺序列出了它们。

  1. 它避免了流水线暂停。没有显式的零寄存器,需要使用一个寄存器将其清零并使用其值。这意味着使用零的操作依赖于清零操作,并且(根据流水线转发系统的强度)可能依赖于已清零寄存器的先前值。像x86这样具有相当小的寄存器文件并基本虚拟化其寄存器以防止造成问题的架构具有极强的危险分析工具。这对于RISC处理器通常不是如此。
  2. 如果可以避免寄存器读取,则某些操作可能更易于流水线化。如果使用显式的零寄存器,则在指令解码阶段即可知道操作数为零的事实,而不是在寄存器获取阶段之后。因此,可以跳过寄存器读取阶段。
  3. 同样,明确丢弃结果的能力可以避免需要寄存器写入阶段。
  4. 某些操作在其中一个操作数已知为零或结果已知被丢弃时可以生成更简单的微代码。
  5. 显式的零寄存器减轻了编译器优化器的压力,因为它不需要太过谨慎地进行寄存器分配(不需要识别不会在读取或写入时引起停顿的寄存器)。

1
在较简单的CPU上,如果ISA需要更少的操作码,则解码会有好处。拥有零寄存器意味着mov-immediate到寄存器可以是“ori dst,$zero,1234”的别名,而不需要它自己的操作码。在具有FLAGS的ISA(不像MIPS),cmp可以是目标为$zerosub - Peter Cordes

6
对于每个项,这里有一个答案。
  1. 考虑强制要求注册输出的指令,而您想要丢弃此输出。通常,您必须确保有一个可用的空闲寄存器,如果没有,则将当前某些寄存器推送到堆栈上,这是一项昂贵的操作。显然,操作的输出经常被丢弃,处理此问题的最简单方法是有一个“未使用”的寄存器可用。
  2. 既然我们有了这样一个未使用的寄存器,为什么不使用它呢?经常出现这样的情况,即您想要将某些内容归零或将其与零进行比较。长路是先写入零寄存器(需要额外的指令和机器码中零的字面值,可能采用0x00000000这样的形式,这很长),然后使用它。因此,可以节省一条指令,并减小程序大小。
这些优化可能看起来有点琐碎,并引发问题“那实际上会改善多少?”答案是,在您的MIPS处理器上明显频繁使用上述操作。

2
在x86上丢弃指令的输出非常有用,因为指令具有设置条件码等副作用。由于MIPS指令只有一个输出,因为这是一种RISC体系结构,很少需要丢弃指令的输出。 - markgz

3
零寄存器的概念并非新鲜事物。我最早在上世纪60年代中后期的CDC 6600大型机上遇见过它。从某些方面来看,它是最早的RISC处理器之一,并且曾经连续五年成为世界上最快的计算机。在该架构中,“B0”寄存器被硬连接到始终为零。这个链接提供了更多信息:http://en.wikipedia.org/wiki/CDC_6600 这种寄存器的好处主要在于简化了指令集。当可以实现简单和规则指令集的解码和编排而不需要微码时,它会增加性能。此外,对于像6600这样的大多数LSI芯片,信号传输所用的时间成为执行速度的关键因素之一,保持指令集的简单性(并避免使用微码)可以减少晶体管数量,并缩短电路路径。

1

零寄存器允许在设计新的指令集架构(ISA)时节省一些操作码。

例如,主RISC-V规范有32个伪指令依赖于零寄存器(参见表26.2和26.3)。伪指令是由汇编器映射到另一个实际指令的指令(例如,等于零时分支被映射为等于分支)。相比之下:主要的RISV-V规范列出了164个真实指令操作码(即计算RV(32|64)[IMAFD]基础/扩展,也称为RV64G)。这意味着如果没有零寄存器,RISC-V RV64G将占用32个操作码来处理这些指令(即增加20%)。对于具体的RISC-V CPU实现,这种真实到伪指令的比率可能会根据选择的扩展而向任一方向移动。

较少的操作码简化了指令解码器。

更复杂的解码器需要更多时间来解码指令或占用更多门(不能用于更有用的CPU单元),或者两者都需要。

现有的、逐步开发的指令集架构必须处理向后兼容性。因此,如果您最初的ISA设计不包括零寄存器,您不能在以后的修订中添加它而不破坏兼容性。此外,如果您现有的ISA已经需要一个非常复杂的译码器,那么添加一个零寄存器也得不偿失。

除了现代RISC-V ISA(自2010年以来开发,2019年首次批准)外,ARMv8 AArch64(一种于2011年发布的64位ISA)与以前的ARM 32位ISA相比,也具有零寄存器。由于这个和其他变化,AArch64 ISA与以前的ARM 32位ISA相比,共同点要少得多,比如x86和x86-64 ISA。

与AArch64相比,x86-64没有零寄存器。虽然x86-64比以前的32位x86 ISA更现代,但其ISA只是逐步改变。因此,它包含所有现有的x86操作码和64位变体,因此译码器已经非常复杂。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接