COA Notes
General purpose register file design, register allocation, and register-based computation models.
Introduction
General purpose registers (GPRs) are the workhorses of the CPU. They're the small set of ultra-fast storage locations that hold the data actively being processed. When a compiler translates your high-level code into machine instructions, one of its most critical jobs is deciding which variables to keep in registers (fast) versus memory (slow). The design of the register file — how many registers, how wide, how many read/write ports — fundamentally shapes processor performance.
What Makes Registers "General Purpose"?
Unlike special-purpose registers (PC, IR, MAR), general purpose registers can hold any type of data:
- Integer values being computed
- Memory addresses for load/store operations
- Loop counters
- Function parameters and return values
- Temporary intermediate results
The term "general purpose" means the instruction set allows these registers to be used interchangeably in most operations. ADD R1, R2, R3 works regardless of which registers you choose.
Register File Architecture
Structure
The register file is essentially a small RAM with very specific properties:
Key Properties
- Multi-ported: Can read 2 registers AND write 1 register simultaneously
- Single-cycle access: Read and write complete within one clock cycle
- Small: 8 to 32 registers (rarely more for general-purpose)
- Static: Built from SRAM flip-flops (not DRAM — no refresh needed)
How Many Registers?
This is one of the most debated design decisions in computer architecture:
Fewer Registers (8-16)
- Pros: Smaller instructions (fewer bits for register specifiers), cheaper hardware, faster register file
- Cons: More memory accesses needed (register "spilling")
- Example: x86-32 had only 8 GPRs — compiler struggled to keep values in registers
More Registers (32-64)
- Pros: Fewer memory accesses, more variables kept in registers, better for compilers
- Cons: Larger instructions, more complex and potentially slower register file
- Example: MIPS, RISC-V, ARM all use 32 GPRs — considered the sweet spot
The Trade-off
The optimal number depends on workload characteristics. Studies show diminishing returns beyond ~32 registers for most programs.
Register Conventions
While registers are "general purpose" in hardware, software conventions assign roles:
RISC-V Register Convention (typical example)
| Register | Name | Convention |
|---|---|---|
| x0 | zero | Hardwired to 0 (reads always return 0) |
| x1 | ra | Return address |
| x2 | sp | Stack pointer |
| x3 | gp | Global pointer |
| x4 | tp | Thread pointer |
| x5-x7 | t0-t2 | Temporary (caller-saved) |
| x8-x9 | s0-s1 | Saved (callee-saved) |
| x10-x17 | a0-a7 | Arguments / return values |
| x18-x27 | s2-s11 | Saved (callee-saved) |
| x28-x31 | t3-t6 | Temporary (caller-saved) |
Caller-Saved vs Callee-Saved
- Caller-saved (temporary): The calling function must save these before calling another function (they may be overwritten)
- Callee-saved (saved): The called function must preserve these (restore before returning)
This convention reduces unnecessary register saves/restores — only registers that are actually needed get saved.
Register Allocation by Compilers
Compilers perform register allocation — deciding which variables live in registers vs memory:
Simple Example
int a = 5, b = 3, c;
c = a + b; // Compiler: R1=a, R2=b, R3=c
// ADD R3, R1, R2Spilling
When there are more live variables than registers, the compiler must "spill" some to memory:
// If we need 35 variables but only have 32 registers:
// Least-used variables get stored to stack memory
// Loaded back into registers when neededGraph Coloring
The classic register allocation algorithm uses graph coloring:
- Each variable is a node
- Edges connect variables that are "live" at the same time
- Assign registers (colors) so no two connected nodes share a color
- If the graph needs more colors than registers → spill
Zero Register
Many RISC architectures include a hardwired zero register:
- Always reads as 0, writes are discarded
- MIPS: $zero (register 0)
- RISC-V: x0
- ARM: XZR
Why? It simplifies many common operations:
| MOV R1, R2 | ADD R1, R2, x0 (add zero = copy) |
| NOP | ADD x0, x0, x0 (result discarded) |
| NEG R1, R2 | SUB R1, x0, R2 (0 - R2 = negate) |
| Compare to 0 | SUB x0, R1, x0 (sets flags, discards result) |
Register File Timing
In a pipelined processor:
- First half of cycle: Write (from previous instruction's write-back)
- Second half of cycle: Read (for current instruction's decode)
This allows read-after-write in the same cycle, solving certain pipeline hazards.
Key Takeaways
- GPRs are the fastest, most frequently accessed storage in the processor
- The register file is multi-ported SRAM — typically 2 read + 1 write port
- Register count (8-64) is a critical design trade-off between instruction size and memory traffic
- 32 registers is the established sweet spot for most RISC architectures
- Software conventions assign roles (arguments, saved, temporaries) to specific registers
- Compilers use register allocation algorithms to minimize slow memory accesses
- A hardwired zero register simplifies many common operations without extra hardware
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for General Purpose Registers.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Computer Organization & Architecture topic.
Search Terms
computer-organization, computer organization & architecture, computer, organization, cpu, general, purpose, registers
Related Computer Organization & Architecture Topics