为什么我们的微处理器中没有更多的寄存器?


18

从理论上讲,不需要寄存器;所有微处理器在没有寄存器的情况下仍然可以工作。但是,这种看似微不足道的添加帮助使微处理器更加高效。

为什么我们不能拥有更多的寄存器来进一步从中受益呢?它们只是片上存储器,可以想象添加起来不是很困难吗?哪些因素影响了寄存器的数量而不是原来的数量,比如说多了十倍?


8
@ Alper91许多假设的和实际的体系结构都没有寄存器,并且根本没有必要。这只是一个有用的优化。
配管

4
嗯 没有人提到Sparc。最大的实现可能有520个寄存器(32个窗口乘以16个寄存器,再加上8个全局变量。)我肯定记得它们。
2016年

13
我认为指令中需要指定寄存器的位数是个大问题。如果您有1024个寄存器,则每个算术指令至少需要30位-除非添加其他约束,例如“所有3个寄存器必须来自同一组32(在这种情况下,您需要20位)。”
user253751

8
@pipe-实际上,几乎任何实际设计在原理上都需要“寄存器”,因为即使您构建堆栈计算机或类似的东西,您也必须有一个位置来保存ALU的参数,否则输出-大多数记忆没有三个访问端口。堆栈计算机需要一个堆栈指针,该指针是一个寄存器!而且,更不用说管道寄存器了。您可以向程序员隐藏对此类“寄存器”的使用,但是您仍然需要一些寄存器,并且可能与原始寄存器机器的数目差不多。
克里斯·斯特拉顿

4
@ChrisStratton当然可以,但是只要不通过ISA公开它们,这只是一个实现细节。不过有些争论,因为我们不知道op由register表示什么。
管道

Answers:


33

有几个因素:

  • 高性能微体系结构使用寄存器重命名。也就是说,物理寄存器的数量大于体系结构可见的寄存器的数量,并且它们能够跟踪它们的独立使用。

  • 寄存器数量加倍不会使性能提高一倍。ISTR(来自计算机体系结构,一种量化方法)从16个寄存器增加到32个寄存器会带来10%的改善,前提是假定增加不会带来不利影响(这是非常乐观的假设)。

  • 在体系结构上可见的寄存器具有成本。例如:

    • 增加它们的数量会增加指令格式中采用的位数,以指示正在作用于哪个寄存器(将寄存器数量加倍意味着该格式中的每个寄存器都有一个位数,从而防止将这些位数用于其他用途或强制使用较长的指令)。
    • 增加架构寄存器的数量会增加上下文切换成本(因为必须在上下文切换中保存和恢复它们)。

1
我敢保证16到32个寄存器的性能提高完全取决于所考虑的编译器的优化潜力。在汇编程序中,访问两倍数量的寄存器(在x64体系结构中)可以极大地提高性能-但仅适用于特殊角色,并且仅在实际使用它们的情况下。
rdtsc

6
@rdtsc:根据与此答案相关联的论文中的模拟数据,将8个体系结构寄存器增加到16个体系结构寄存器可以大大改善典型代码的溢出/重载数量。它会影响代码大小,指令数量以及低延迟存储转发的重要性。16-> 32的效果要小得多。AFAICT的16个架构寄存器非常适合硬件重命名,以消除WAR和WAW危害。
彼得·科德斯

2
但是,英特尔的AVX512增加了16个矢量寄存器,总共32个。(以及将它们的宽度加倍到64字节,即一个完整的高速缓存行)。隐藏高吞吐量,高延迟FP操作中的延迟可能会占用大量寄存器。例如,Intel Haswell具有5c lat,每0.5c吞吐量FMA中有一个,因此您需要10个矢量累加器来使FMA执行单元饱和以进行缩减(例如,点积或求和数组,其中FMA是循环携带的依赖项的一部分) )。x86-64仅具有16个矢量寄存器。但是请记住,整数运算,尤其是。在GP reg上,很少有超过1c的延迟。
彼得·科德斯

1
整数,FP和向量寄存器的权衡是不同的。例如,整数寄存器的懒惰保存/恢复没有意义,对向量一执行此操作会更好。向量ISA的寄存器通常比整数1多(AltiVec至少具有128个寄存器,ISTR为Sparc读取了大约256个寄存器,但现在找不到引用)。
AProgrammer

1
en.wikipedia.org/wiki/AltiVec具有32个128b矢量reg。我对SPARC感到好奇,并查看了其寄存器窗口内容如何用于上下文切换。它一次具有32个可见的寄存器,但使用一个到较大寄存器文件的滑动窗口。从这个简化的版本听起来操作系统需要知道整个滑动窗口寄存器文件的大小才能保存/恢复,因为即使窗口滑动指令提供了用于保存/恢复注册表的内存,也可以通过捕获来完成到操作系统。
彼得·科德斯

16

尽管寄存器和RAM都是内存,但是它们以不同的方式访问,以反映访问它们的成本(在芯片区域或隐藏时钟周期内)。

寄存器与ALU紧密绑定,可以担当数据源,接收器,修饰符等的许多角色。因此,它们需要大量的宽复用连接。在某些架构中,我们可以写出R1 <= R2 + R3,而这恰恰是在单个时钟周期内发生的。每个寄存器都直接在操作码中寻址,这种寻址是非常有限的资源。

由于寄存器的实现成本很高,因此在大多数体系结构中,寄存器的数量通常限于10/20的数量级。

RAM松散地绑定到CPU,通常通过单个共享连接进行引导。这使得实现大量RAM的成本大大降低。RAM地址通常来自寄存器存储的地址,因此不会占用大量指令宽度。

SPARC是一种有趣的体系结构,具有72至640个64位寄存器,具有32个寄存器上下文,可以通过重叠进行移位,以通过参数传递进行快速子例程调用。您往往不会在成本很重要的PC和服务器中找到它们,例如在99.999%的应用程序中。


4
另一方面是您必须在上下文切换期间保存/恢复寄存器。更多的寄存器,更多的时间。
Michel Billaud '16

我想指出,老TMS9900保存在外部存储器所有的工作寄存器en.wikipedia.org/wiki/Texas_Instruments_TMS9900
彼得·史密斯

1
我已经“总是”使用了(除了一些调整),但是将其简化了。也许我只是将其更改为“一般”。基本上,如果您可以找到并理解例外,则不需要我指出这些例外。如果您有足够的勇气被误导,那就没关系,因为它不会给您带来麻烦。TMS9900,那真是太奇怪了,我早年的罪孽是99/4,是奇怪的野兽!
Neil_UK

Itanium还具有注册窗口。
西蒙·里希特

1
@ChrisStratton:尽管“不能使用寄存器X和Y”被认为是“ ABI”的一部分(例如,在mips上的k0和k1寄存器)是有先例的,但这是不寻常的用法。如果在上下文切换时未保存/恢复这些“禁止ABI的寄存器”,则肯定会在进程之间存在不需要的/不安全的隐式消息通道。也就是说,不应该进行通信的进程可以通过将信息存储在禁止的寄存器中并等待上下文切换来进行通信。
R.,

12

在说明中必须填写寄存器。如果寄存器很多,指令会更长。如果存在大量寄存器,则为中断服务保存和恢复寄存器内容需要更多时间。


5

在大多数情况下,寄存器的数量是成本,复杂性和实用性之间的折衷。

寄存器被实现为多端口静态RAM,这使其比其他存储选项成本更高(芯片面积)。

然后,它们与处理器的指令集耦合,增加寄存器的数量会增加指令集的复杂性。因此,如果您想与指令集保持兼容,就不能仅仅增加下一代处理器中可用寄存器的数量来提高效率,这些程序就不会使用它们。

接下来,您真正需要多少个寄存器?它们的用途是有限的。考虑您编写了一种算法,该算法在1024字节上执行一些数学运算,比方说乘以5。使用当前的寄存器计数,最终会得到以下结果:

load operand1=5
load address
loop: load operand2=byte1@address
multiply Register1 with Register2
store result
increment address
if address = end goto endLoop
jump loop
endLoop:

现在,如果您将具有1024个寄存器并将所有数据存储在其中,则程序将如下所示:

multiply Register1 with Register2
multiply Register1 with Register3
multiply Register1 with Register4
multiply Register1 with Register5
multiply Register1 with Register6
...

由于每个指令都是不同的指令,因此必须将每个指令都写出。因此,您所需的程序存储器正在爆炸。在意识到这一点之后,您可能希望引入一些说明,例如multiply register1 with register(2 to 256)。但是什么时候停止,您是否提供所有组合的说明?

因此,也许我们目前可用的数字是成本,复杂性和实用性之间的良好折衷。


1
我认为该程序multiply Register1 with Register2 multiply Register1 with Register3非常不切实际,因为数据必须直接或间接来自计算机外部,因此需要加载寄存器,并且需要在某个地方直接或间接使用结果,因此需要存储寄存器。实际上,针对高级语言的体面的优化编译器将“展开”第一个程序的循环以创建类似于第二个程序的内容,从而优化寄存器使用,内存延迟,也许是高速缓存占用率和执行速度。
gbulmer

1
不需要许多特殊用途的multiply register1 with register(2 to 256)说明。流水线显着提高了CPU吞吐量,尤其是对于更易于解码和执行指令的情况。因此,可以通过使用几个具有较高执行率的较简单的指令来实现复杂的大量指令的效果。具有更多数量的寄存器有助于编译器生成许多独立的指令(不共享寄存器的指令),这些指令可以独立完成,从而提高了吞吐量。您的示例=更多的寄存器更好。
gbulmer

4

寄存器非常昂贵。非常贵。与其说寄存器本身,不如说是寄存器之间的所有连接。假设您有一条指令reg1 = reg2 + reg3。快速实施,您需要在一个周期内从两个寄存器读取数据,并在第二个周期内写入另一个寄存器。现在,如果您有一个处理器每个周期可以执行多个指令(例如3条指令),则您需要能够每个周期从六个寄存器读取数据,并将数据写入3个寄存器。那是非常可怕的,非常快的连接。

当然,您可以只使用更多的晶体管。问题是:速度下降。您需要更多的硬件来从更多的寄存器中进行选择。寄存器文件的空间变大。所有这些使事情变慢。因此,使用相同的技术,您可能能够拥有16个寄存器并以2,600 MHz运行,或者有32个寄存器并以2,400 MHz运行。现在,额外的寄存器必须弥补时钟速度的显着下降。


2

什么因素影响寄存器的数量

- 内存层次结构

寄存器,缓存,RAM均使用不同的存储技术来实现。

不同的技术在以下方面有所不同

  1. 访问时间
  2. 成本
  3. 密度

一个示例:CPU中的内部寄存器是静态随机存取存储器,而计算机主存储器是动态随机存取存储器

静态RAM二进制单元使用6晶体管电路实现,而动态RAM二进制单元则使用电容器和晶体管实现。比较SRAM和DRAM

  • SRAM存储器比DRAM存储器快得多[与DRAM相比,访问SRAM的周期很少]
  • SRAM电路比DRAM消耗更少的功率
  • 与SRAM不同,DRAM需要定期刷新存储器中的每个位
  • SRAM的成本高于DRAM
  • SRAM比DRAM具有更低的密度

因此,增加快速,昂贵,密度较小的内存的数量并不是一件实际的事情。实际上,我们可能会使用其中的一些,编写良好的程序会将最常用的数据存储在这些快速寄存器中,而较不常用的数据则存储在较慢的内存中。

- 指令长度

寄存器的地址包含在一条指令中,该指令根据可表示该地址的位数限制访问寄存器的数量。例如,在MIPS体系结构中,32位长度的指令仅保留5位来表示可访问寄存器的地址,这将寄存器的数量限制为2 5 = 32寄存器。增加寄存器的数量将需要增加指令长度,以包括足以访问所有寄存器的位。


2

如果您查看处理器的指令集,则有多种将它们分组的方法。例如,所有ADD指令可能和所有XOR指令一起分组。

在同一条指令的每一组中,可能存在在存储器或寄存器上运行的版本。正是这个子分组有效地定义了处理器拥有的寄存器数量。

作为一个8位的假设示例,假设$Ax指令可能是ADD指令,也$Cx可能是XOR指令。通过这种设计,仅剩下四个位来定义操作数!

  • 一个可能只有四个通用寄存器,并且使用两位定义一个,而使用两位定义另一个。
  • 或者,可以使用第一位来区分“特殊”变量,而使用其他3位来定义要使用累加器操作的八个寄存器中的哪一个($x0可以是累加器本身)。
  • 或者,一个寄存器的数量可能超过此数量,但随后限制了哪些指令可访问哪些寄存器。

当然,我们已经过了8位指令集。但是,这种逻辑过去仍然可以帮助定义寄存器集-将来它将继续这样做。

编辑(按要求)

说前四位的指令:ADDSUBXORMOVCMP等这里有16种可能性。然后,对于那些有意义的寄存器间指令(例如ADD Rx,Ry),您需要指定RxRy。说接下来的两个位用于x,最后两个位用于y。从而:

ADD R1, R2  =>  'ADD' + 'R1' + 'R2' => $A0 + $04 + $02

仅用两位来定义这样的寄存器,总共只有四个寄存器的空间!

顺便说一句,您会注意到某些寄存器组合没有任何意义。例如,MOV Rx, Rx(什么都不做)和SUB Rx, Rx(总是产生0)。这些可能成为特殊情况的说明:

  1. SUB Rx, Rx可能成为NOT Rx-单操作数指令。
  2. MOV Rx, Rx可能变成一条MOV以第二个字节为立即值的指令,解释为MOV Rx, #$yy

通过这种方式,您可以“玩弄”指令图,为其他无用或无意义的指令填充空洞,从而为程序员提供更大的指令集。但最终,指令集定义了寄存器集。


我还是很困惑,您能解释一下操作数只剩下4位吗?
达尔山乔德哈里

检查我更新的答案
John Burger

1
恕我直言,通过将“ 假设示例假定为8位指令集 ”移至问题的开头,可以大大改善此答案。我浪费了时间尝试理解它,得出结论只对8位固定长度的指令有意义,然后继续阅读,发现确实如此。恕我直言,这种指令集在问题中并不是很无关紧要。它的整个地址空间可以是紧密耦合的静态RAM。我也认为以“ 某些寄存器组合没有意义…… ” 开头的部分与该问题无关,可以删除。我的$ 0.02
gbulmer

-2

如今,英特尔正在使用数千个寄存器-每个CPU内核数百个。但是,存储在CPU上的最大数据量是在缓存中,这间接地回答了这个问题。缓存是分层组织的,其中较小的快速L1缓存和较慢的L2和L3缓存距离较远。从某种意义上说,寄存器文件是L0,甚至比L1还要快,甚至更小。因此,您可以增加寄存器的数量,但这可能会减慢它们的速度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.