MIPS assembly language - temporary register vs saved registers

Learn mips assembly language - temporary register vs saved registers with practical examples, diagrams, and best practices. Covers assembly, mips development techniques with visual explanations.

MIPS Registers: Understanding Temporary vs. Saved Registers

Diagram illustrating MIPS register types and their roles in function calls

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