MIPS assembly language - temporary register vs saved registers
Categories:
MIPS Registers: Understanding Temporary vs. Saved Registers
Explore the critical distinction between temporary (t-registers) and saved (s-registers) in MIPS assembly, and learn how to manage them effectively for robust function calls.
In MIPS assembly language, registers are fundamental for storing data and intermediate results during program execution. A crucial concept for writing correct and efficient MIPS code, especially when dealing with functions and subroutines, is understanding the difference between temporary registers (t-registers) and saved registers (s-registers). This distinction dictates how registers should be managed across function calls to maintain data integrity and prevent unexpected behavior.
The Role of Registers in MIPS
MIPS architecture provides a set of general-purpose registers, each with a specific convention for its use. These conventions are not enforced by the hardware but are a programming standard that all MIPS compilers and assembly programmers are expected to follow. Adhering to these conventions ensures that different parts of a program, especially functions, can interact predictably without corrupting each other's data. The primary distinction lies in their 'caller-save' or 'callee-save' nature.
flowchart TD A[MIPS Registers] --> B{Register Type} B --> C[Temporary Registers (t-registers)] B --> D[Saved Registers (s-registers)] C --> C1["Caller-saved: Caller must save if needed after call"] D --> D1["Callee-saved: Callee must save if it modifies"] C1 --> E[Volatile across function calls] D1 --> F[Preserved across function calls]
MIPS Register Classification and Preservation Convention
Temporary Registers (t-registers): Caller-Saved
Temporary registers, typically denoted as $t0
through $t9
, are considered 'caller-saved'. This means that if a calling function (the caller) has important data in a t-register that it needs to preserve across a function call, it is the caller's responsibility to save that data to the stack before making the call. The called function (the callee) is free to use any t-register without needing to save its original value, as it assumes the caller has already preserved anything important. After the callee returns, the caller can then restore its data from the stack if necessary.
# Caller's perspective for t-registers
# Assume $t0 holds a value needed after 'myFunction'
addi $sp, $sp, -4 # Make space on stack
sw $t0, 0($sp) # Save $t0 to stack
jal myFunction # Call the function
lw $t0, 0($sp) # Restore $t0 from stack
addi $sp, $sp, 4 # Restore stack pointer
Example of caller saving a temporary register
Saved Registers (s-registers): Callee-Saved
Saved registers, typically $s0
through $s7
, are 'callee-saved'. This convention dictates that if a called function (the callee) intends to use an s-register, it must first save the original value of that s-register to the stack. After the callee has completed its operations and before it returns control to the caller, it must restore the original value of the s-register from the stack. This ensures that the caller's data in s-registers remains untouched across the function call, preserving the program's state.
# Callee's perspective for s-registers
myFunction:
addi $sp, $sp, -4 # Make space on stack
sw $s0, 0($sp) # Save $s0 to stack (if myFunction uses $s0)
# ... myFunction's operations, potentially modifying $s0 ...
lw $s0, 0($sp) # Restore $s0 from stack
addi $sp, $sp, 4 # Restore stack pointer
jr $ra # Return to caller
Example of callee saving a saved register
Practical Implications and Best Practices
Understanding and correctly applying the temporary vs. saved register convention is paramount for writing robust MIPS assembly code. It's a contract between functions that allows modular programming. When designing your functions:
- For temporary values within a function: Use t-registers. If you call another function and need the t-register's value after the call, you (the caller) must save it.
- For values that need to persist across function calls: Use s-registers. If your function modifies an s-register, you (the callee) must save and restore its original value.
This convention helps optimize register usage, as not all registers need to be saved on every function call, reducing stack overhead.
sequenceDiagram participant Caller participant Callee Caller->>Caller: Store important data in $t0 Caller->>Caller: Store important data in $s0 Note over Caller: Caller needs $t0 after Callee returns Caller->>Caller: Push $t0 to stack Caller->>Callee: Call Callee Note over Callee: Callee needs to use $s0 Callee->>Callee: Push $s0 to stack Callee->>Callee: Perform operations (uses $t0, $s0) Callee->>Callee: Pop $s0 from stack Callee->>Caller: Return Caller->>Caller: Pop $t0 from stack Caller->>Caller: Continue with original $t0 and $s0
Sequence of register saving and restoring during a function call