22
\$\begingroup\$

Registers are theoretically not required; all microprocessors would still work without registers. But this seemingly trivial addition has helped make microprocessors more efficient.

Why can't we have more registers to further extract benefit from them? They are just memory on chip and one can imagine not very difficult to add? What factor influenced the number of registers to be what they are now and not, say 10x more?

\$\endgroup\$
12
  • 8
    \$\begingroup\$ @Alper91 Many architectures, hypothetical and real, do not have registers, and it's not at all necessary. It's simply a useful optimization. \$\endgroup\$
    – pipe
    Commented Sep 9, 2016 at 6:50
  • 4
    \$\begingroup\$ Hmm. No one has mentioned the Sparc. The largest implementation could have 520 registers in it (32 windows times 16 registers, + 8 globals.) I sure remember them. \$\endgroup\$
    – jonk
    Commented Sep 9, 2016 at 7:09
  • 13
    \$\begingroup\$ I think the number of bits in the instruction that you need to specify the register is a big problem. If you have 1024 registers, then you need at least 30 bits for every arithmetic instruction - unless you add other constraints like "all 3 registers must be from the same group of 32 (in which case you need 20 bits). \$\endgroup\$
    – user20574
    Commented Sep 9, 2016 at 7:18
  • 8
    \$\begingroup\$ @pipe - actually pretty much any practical design does require "registers" in the schematic sense, as even if you build a stack machine or something like that, you have to have a place to hold the arguments to the ALU, or else the outputs - most memories don't have three access ports. And a stack machine needs a stack pointer which is... a register! And lets not mention pipeline registers. You can hide the use of such "registers" from the programmer, but you still need some, and probably nearly as many as a primitive register machine has. \$\endgroup\$ Commented Sep 9, 2016 at 13:09
  • 4
    \$\begingroup\$ @ChrisStratton Sure, but as long as they are not exposed through the ISA, it's simply an implementation detail. Somewhat pointless argument though, since we don't know what OP means by register. \$\endgroup\$
    – pipe
    Commented Sep 9, 2016 at 13:19

8 Answers 8

38
\$\begingroup\$

There are several factors:

  • high performance micro-architectures use register renaming. That is, the number of physical registers is higher than the number of architecturally visible registers and they are able to track independent uses of them.

  • doubling the number of registers does not double the performance. ISTR (from Computer architecture, A Quantitative Approach) that going from 16 to 32 registers brings something like a 10% improvement assuming that the increase has no adverse effect (which is a very optimistic assumption).

  • architecturally visible registers have costs. For instance:

    • Increasing their number increases the number of bits taken in the instruction format to indicate which register is being acted on (doubling the number of register implies to have one more bit per register in the format, thus preventing to use those bits for other usages or forcing a longer instruction size).
    • Increasing the number of architectural registers increases the context switching cost (as they must be saved and restored on context switch).
\$\endgroup\$
8
  • 2
    \$\begingroup\$ I'd wager that the performance improvement of 16 to 32 registers depends totally on the optimization potential of the compiler in question. In assembler, having access to double the number of registers (in x64 architecture) can vastly improve performance - but only for niche roles, and only if they are actually used. \$\endgroup\$
    – rdtsc
    Commented Sep 9, 2016 at 15:14
  • 7
    \$\begingroup\$ @rdtsc: going from 8 to 16 architectural registers gives big improvements in the amount of spills/reloads for typical code, according to data from simulations in a paper linked from this answer. It affects code size, instruction count, and how important low-latency store-forwarding is. 16->32 is a much smaller effect. AFAICT, 16 architectural registers is a good choice for hardware with register renaming to remove WAR and WAW hazards. \$\endgroup\$ Commented Sep 9, 2016 at 18:39
  • 2
    \$\begingroup\$ However, Intel's AVX512 adds 16 more vector regs, for a total of 32. (As well as doubling their width to 64 bytes, a full cache line). Hiding the latency from high throughput high latency FP operations can take a lot of registers. e.g. Intel Haswell has 5c lat, one per 0.5c throughput FMA, so you need 10 vector accumulators to saturate the FMA execution units for a reduction (e.g. dot product, or summing an array, where the FMA is part of a loop-carried dependency). x86-64 only has 16 vector regs. But remember, integer ops, esp. on GP regs, rarely have more than 1c latency. \$\endgroup\$ Commented Sep 9, 2016 at 18:44
  • 1
    \$\begingroup\$ The trade-off is different for integer, FP and vector registers. For instance lazy save/restore of integer registers does not make sense, doing it for vector one is a far better bet. And vector ISA have often more registers than integer one (AltiVec has at least up to 128, ISTR having read about a 256 one for Sparc but can't find a reference now). \$\endgroup\$ Commented Sep 9, 2016 at 19:34
  • 1
    \$\begingroup\$ en.wikipedia.org/wiki/AltiVec has thirty-two 128b vector regs. I got curious about SPARC and looked up how its register-window stuff worked for context switches. It has 32 registers visible at once, but uses a sliding window onto a larger register file. It sounds from this simplified version like the OS needs to know the size of the whole sliding-window register file to save/restore it, because even though the window-slide instructions provide memory for saving/restore regs if needed, it's done by trapping to the OS. \$\endgroup\$ Commented Sep 11, 2016 at 0:45
16
\$\begingroup\$

While registers and RAM are both memory, they are accessed in different ways, to reflect the cost (in chip area, or of hidden clock cycles) of accesssing them.

Registers are tightly bound to the ALU, and can take many roles of data sources, sinks, modifiers etc. They therefore need a wealth of wide multiplexed connections. In some architectures we can write R1 <= R2 + R3, and that is exactly what happens in a single clock cycle. Each register is directly addressed in the op code, this addressing is a very limited resource.

As registers are expensive to implement, the number is usually limited to the order of 10/20 in most architectures.

RAM is loosely bound to the CPU, usually being channelled through a single shared connection. This makes it much much cheaper to implement a large amount of RAM. RAM addresses generally come from a register-stored address, so don't consume significant instruction width.

SPARC is an interesting architecture, with 72 to 640 64 bit registers, with a 32 register context that can be shifted with overlaps for fast subroutine calls with parameter passing. You tend not to find them in PCs and servers where cost matters, like in 99.999% of applications.

\$\endgroup\$
14
  • 4
    \$\begingroup\$ Another aspect is you have to save/restore registers during a context switch. More registers, more time. \$\endgroup\$ Commented Sep 9, 2016 at 7:54
  • \$\begingroup\$ I would note that the old TMS9900 kept all its working registers in external memory en.wikipedia.org/wiki/Texas_Instruments_TMS9900 \$\endgroup\$ Commented Sep 9, 2016 at 7:58
  • 1
    \$\begingroup\$ I had qualified 'invariably' with (excepting a few tweaks) but took it out to simplify it. Perhaps I'll just change it to 'generally'. Basically if you can find and understand the exceptions, you don't need me to point them out. If you're niave enough to be misled, then it doesn't matter, because it won't get you into trouble. TMS9900, that was wierd, I had a 99/4 for my sins in an earlier life, strange beast! \$\endgroup\$
    – Neil_UK
    Commented Sep 9, 2016 at 8:12
  • \$\begingroup\$ Itanium also has register windows. \$\endgroup\$ Commented Sep 9, 2016 at 12:18
  • 1
    \$\begingroup\$ @ChrisStratton: While there is some precedent for "you can't use registers X and Y" being considered part of an "ABI" (e.g. k0 and k1 registers on mips), it's unusual usage. Certainly there are unwanted/unsafe covert messaging channels between processes if save/restore of these "ABI-forbidden registers" is not performed at context switch. That is, processes which should not be able to communicate may be able to do so by storing information in the forbidden registers and waiting for context switches. \$\endgroup\$ Commented Sep 11, 2016 at 5:08
13
\$\begingroup\$

Registers must be adressed within the instruction. If there are a lot of registers, the instruction is longer. Saving and restoring register content for an interrupt service needs more time if there are a lot of registers.

\$\endgroup\$
5
\$\begingroup\$

As most things, the number of registers is a compromise between cost, complexity and usefulness.

Registers are implemented as multi-port static RAM, which makes them more costly (chip area) than other storage options.

Then they are coupled with the instruction set of the processor, increasing the number of registers increases the complexity of the instruction set. So if you want to stay compatible with the instruction set, you can't just increase the number of registers available in the next generation of processors to increase efficiency, the programs wouldn't use them.

Next is how much registers do you really need? There is a limit to their usefulness. Consider you write an algorithm which performs some mathematical operation on 1024 bytes, let's say multiply by 5. With current register counts, you end up with something like:

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:

Now if you would have 1024 registers and all the data stored there, your program would look like:

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

Because each of them is a different instruction, every single one of them has to be written out. So your needed program memory is exploding. After realizing this, you might want to introduce some instructions like, multiply register1 with register(2 to 256). But when would you stop, do you provide an instruction for all combinations?

So maybe the numbers we currently have available is a fine trade-off between cost, complexity and usefulness.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think the program multiply Register1 with Register2 multiply Register1 with Register3 is very unrealistic as the data must have come directly or indirectly from outside the computer, so the registers need to be loaded, and the results need to be used somewhere, directly or indirectly, so the registers need to stored. In reality, a decent optimising compiler for a high-level language will 'unroll' the loop of the first program to create something like the second program, optimising register use, memory latency, maybe cache occupancy and execution speed. \$\endgroup\$
    – gbulmer
    Commented Sep 9, 2016 at 16:56
  • 1
    \$\begingroup\$ There is no need for many special purpose multiply register1 with register(2 to 256) instructions. Pipelining improves CPU throughput significantly especially for simpler to decode and execute instructions. So the effect of complex, massive variety instructions can be achieved by using several simpler instructions with a higher execution rate. Having larger numbers of registers helps by allowing the compiler to generate many independent instructions (ones that do not share a register), which can be completed independently, improving throughput. Your example = more registers are better. \$\endgroup\$
    – gbulmer
    Commented Sep 9, 2016 at 17:06
5
\$\begingroup\$

Registers are very expensive. VERY expensive. It's not so much the registers themselves, it's all the connections from and to registers. Say you have an instruction reg1 = reg2 + reg3. To implement this fast, you need to read data from two registers in one cycle, and write to another register in the second cycle. Now if you have a processor that can execute multiple instructions per cycle, say three instructions, you'd need to be able to read data from six registers each cycle, and write data to 3 registers. That's an awful, awful lot of very fast connections.

Of course you can just use more transistors. The problem is: The speed goes down. You need more hardware to choose from more registers. The space for the register file gets bigger. All that makes things slower. So with the same technology, you might be able to have 16 registers and run at 2,600 MHz or have 32 registers and run at 2,400 MHz. Now the additional registers must make up for a significant drop in clock speed.

\$\endgroup\$
3
\$\begingroup\$

What factor influenced the number of registers

- Memory Hierarchy

Registers, Cache, RAM are all implemented with different storage technologies.

Different technologies differ in

  1. Access times
  2. Cost
  3. Density

An example : The internal registers found in a CPU are Static Random Access Memory, while the computer main memory is Dynamic Random Access Memory

A Static RAM binary cell is implemented using a 6-transistor circuit while a Dynamic RAM binary cell is implemented using a capacitor and a transistor. Comparing SRAM and DRAM

  • SRAM memory is much faster than DRAM memory [Few cycles to access SRAM compared to DRAM]
  • SRAM circuit consumes less power than DRAM
  • DRAM require refreshing every bit in the memory periodically unlike SRAM
  • SRAM costs more than DRAM
  • SRAM has a lower density compared to the DRAM

So its not a practical thing to increase the number of the fast, expensive, less density memory. In fact we might use a few of them and a well written program will store the most frequent used data inside these fast registers while the less frequent used data are stored in the slower memory.

- Instruction length

The address of the registers is included within an instruction, which limits the number of the accessible registers based on the numbers of bit that can represent the address. For example in the MIPS architecture the 32-bit length instruction holds only 5-bits to represent the address of the accessible registers which limits the number of the registers to 25 = 32 register. Increasing the number of the registers would require increasing the instruction length in order to include sufficient bits that could access all the registers.

\$\endgroup\$
2
\$\begingroup\$

If you have a look at a processor's instruction set, there are a number of ways of grouping them. For example, all the ADD instructions might be grouped together, and all the XOR instructions.

Within each group of the same instruction, there may be versions that operate on memory, or on registers. It's this sub-grouping that effectively defines the number of registers that the processor has.

As an 8-bit hypothetical example, let's say the $Ax instructions might be the ADD instructions, and $Cx might be the XOR instructions. With this design, there are only four bits left to define the operands!

  • One might have only four general-purpose registers, and use two bits to define one, and two bits to define the other.
  • Or, one might use the first bit to distinguish "special" variants, and the other 3 bits to define which of eight registers to operate with the accumulator ($x0 could be the accumulator itself).
  • Or, one could have more than this number of registers - but then limit which registers are accessible to which instructions.

Of course, we're past 8-bit instruction sets. But still, this logic helped define register sets in the past - it will continue to do so into the future.

EDIT (as requested)

Say the top four bits are for the instruction: ADD, SUB, XOR, MOV, CMP etc. There are 16 possibilities here. Then, for those instructions where register-to-register makes sense (e.g. ADD Rx,Ry), you need to specify Rx and Ry. Say the next two bits are for x, and the last two are for y. Thus:

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

With only two bits to define a register like this, you only have room for a total of four registers!

As an aside, you'll note that some register combinations don't make sense. For example, MOV Rx, Rx (does nothing) and SUB Rx, Rx (always produces 0). These could become special-case instructions:

  1. SUB Rx, Rx could become NOT Rx - a single-operand instruction.
  2. MOV Rx, Rx could become a MOV instruction that takes a second byte as an immediate value, interpreted as MOV Rx, #$yy.

In this way you can "play" with the instruction map, filling in the holes for otherwise-useless or -nonsensical instructions to provide a larger instruction set for the programmer. But ultimately, the instruction set defines the register set.

\$\endgroup\$
3
  • \$\begingroup\$ I am still confused, can you explain how only 4bits left for operands? \$\endgroup\$ Commented Sep 9, 2016 at 6:46
  • \$\begingroup\$ Check my updated answer \$\endgroup\$ Commented Sep 9, 2016 at 12:55
  • 1
    \$\begingroup\$ IMHO this answer would be significantly improved by moving the "hypothetical example assumed an 8-bit instruction set" to the start of the question. I wasted time trying to make sense of it, concluded it only made sense for an 8-bit, fixed length instruction, then read on to find that is the case. IMHO, that sort of instruction set is not very irrelevant in the context of the question; its whole address space could be tightly coupled static RAM. I also think the part beginning "Some register combinations don't make sense ..." is not relevant to the question, and could be deleted. My $0.02 \$\endgroup\$
    – gbulmer
    Commented Sep 9, 2016 at 16:40
-2
\$\begingroup\$

Intel is using thousands of registers nowadays - hundreds per CPU core. But the largest amount of data stored on a CPU is in cache, which indirectly answers the question. Cache is organized in layers, with a small fast L1 cache and slower L2 and L3 caches further away. The register file in a sense is L0, even faster than L1 but also even smaller. So, you could increase the number of registers, but that would likely slow them down.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.