Register allocation is the process where the compiler decides which local variables of a C function should be kept in CPU registers (for fast access), and which should be kept in RAM (on the stack, which is slower).
Why is it Important
- Accessing registers is super-fast (takes 1 cycle).
- Accessing memory (spilled variables) is slower (takes multiple cycles).
- Therefore, efficient use of registers = faster code and better optimization.
Available ARM Registers for C Programs
Register | Usage |
---|---|
r0–r3 | Used for function arguments and return values |
r4–r11 | Available for local variables (callee-saved) |
r12 | Scratch register (in many compilers, used internally only) |
r13 | Stack Pointer (SP) |
r14 | Link Register (LR) |
r15 | Program Counter (PC) |
In practice, around 12 registers (r0–r11) are available for local variable allocation by the compiler.
1. Register Preference
The compiler always tries to keep the most-used variables in registers.
- If your variable is inside a loop, the compiler gives it high priority.
- If your variable is used only once, it’s more likely to be spilled to memory.
2. Spilled Variables
When there are more variables than registers, some variables are:
- Moved to the stack (RAM)
- Accessed using load/store instructions, which slows performance
- Known as spilled variables
3. Reuse of Registers
If variables are not used at the same time, the same register can be reused:
void demo() {
int a = 10; // assigned to r4
int b = 20; // assigned to r5
// a is not used after this point
int c = 30; // compiler can reuse r4 here
}
How to Optimize Register Allocation in Your Code
1: Keep your function logic simple
- Use less than 12 variables inside functions, especially loops.
- Avoid deeply nested logic.
2: Use loops wisely
- Frequently used loop variables (like counters or accumulators) are prioritized for register allocation.
for (int i = 0; i < 100; i++) {
sum += array[i]; // sum and i likely kept in registers
}
3: Avoid the register
keyword
- Modern compilers ignore or limit its usage.
- Let the compiler decide the best allocation using its optimization flags.
Example: Register Allocation in Practice
C Code:
int sum_array(int* arr, int len) {
int sum = 0;
for (int i = 0; i < len; i++) {
sum += arr[i];
}
return sum;
}
What the Compiler Might Do:
Variable | Register Allocated |
---|---|
arr | r0 (argument) |
len | r1 (argument) |
sum | r4 |
i | r5 |
No variables are spilled. Entire function runs from registers, making it fast and optimized