Registers, Memory, and Call/Return

Tom Kelliher, CS 220

Announcements

None.

Assignment

Study factorial.spim.

Programmer's Register Use Conventions

Definitions:

  1. Caller/callee.

  2. Caller save vs. callee save.

  3. Frame:
    1. Saved registers.

    2. Local variables.

    3. Scratch pad, on-stack arguments for called functions.

  4. Frame stack.

Example. Suppose main calls factorial, using an on-stack parameter ( n) pass.
factorial uses $s0 and has a local variable, temp:

Example code snippets:

lw $s0, 4($fp)

sw $s0, -12($fp)

sw $s0, 0($sp)
sub $sp, $sp, 4

Convention:

  1. $v[0-1] --- function results.

  2. $a[0-3] --- function arguments.

  3. $t[0-9] --- caller save registers. (Except for two global pointers, ignore these registers.)

  4. $s[0-7] --- callee save registers.

  5. $sp --- top of stack pointer, pointing to first free location on execution stack.

  6. $fp --- frame pointer, pointing to base of current frame.

  7. $ra --- return address.

Memory Use

  1. Upon entry to main, the frame stack is ready to go.

  2. main pushes its frame and gets to work.

  3. Upon exit, main restores $ra (among others) and executes jr $ra.

Call/Return Conventions

Use this sequence. Assume caller is calling callee.

Caller:

  1. Store any register parameters.

  2. Push any on-stack parameters (caller and callee must agree on order).

  3. Execute jal callee

Callee:

  1. Create stack frame by subtracting size of frame from $sp.

    Number of words needed:

    1. Two for $fp and $ra.

    2. One for each $sx register used.

    3. One for each local integer, pointer, etc.

  2. Save registers, using $sp as base register.

  3. Set $fp by adding frame size to $sp and storing.

  4. Body of callee executes. Frame references should use $fp as base register.

  5. Store return value in appropriate $ax registers.

  6. Restore saved registers, using $sp as base register.

  7. Pop frame from stack by adding frame size to $sp.

  8. Execute jr $ra

Caller:

  1. Collect and store return values.

Example Code

Consider the following C++ code which recursively computes the factorial:

#include <iostream.h>

int getnum(void);
int factorial(int n);

int main()
{
  int value;

  cout << "Enter 0 to exit.\n";

  value = getnum();

  while (value != 0)
    {
      cout << "Factorial: " << factorial(value) << endl;

      value = getnum();
    }

  return 0;
}


int getnum(void)
{
  int num;

  cout << "Number: ";
  cin >> num;

  return num;
}


int factorial(int n)
{
  if (n <= 1)
    return 1;

  return n * factorial(n - 1);
}

Here is the corresponding SPIM program:

# factorial.spim --- A recursive SPIM program.  Demonstrates function
#    call and return.


            .data
prompt:     .asciiz "Number: "
nl:         .asciiz "\n"
instr:      .asciiz "Enter 0 to exit.\n"
response:   .asciiz "Factorial: "


######################################################################
# main
######################################################################

            .text
            .globl main
main:
            sub $sp, $sp, 16     # Push frame & save registers.
            sw $fp, 16($sp)
            sw $ra, 12($sp)
            sw $s0,  8($sp)
            add $fp, $sp, 16

            li $v0, 4            # Print instruction.
            la $a0, instr
            syscall

            jal getnum           # Get a number from keyboard.

            sw $v0, -12($fp)     # Store locally.
            move $s0, $v0

while1:
            beqz $s0, endwhile1  # Compute until 0 entered.

            li $v0, 4            # Print response prompt.
            la $a0, response
            syscall

            move $a0, $s0        # Pass argument

            jal factorial        # Call

            move $a0, $v0        # Copy return value to print it
            li $v0, 1
            syscall

            li $v0, 4            # Prepare to read next number.
            la $a0, nl
            syscall

            jal getnum

            sw $v0, -12($fp)     # Store number just read.
            move $s0, $v0

            b while1

endwhile1:
            lw $s0,  8($sp)      # Restore registers and pop frame.
            lw $ra, 12($sp)
            lw $fp, 16($sp)
            add $sp, $sp, 16
            li $v0, 0
            jr $ra               # Exit.


######################################################################
# getnum --- returns integer read from keyboard through $v0.
######################################################################

            .text
getnum:
            sub $sp, $sp, 12     # push frame & save registers.
            sw $fp, 12($sp)
            sw $ra,  8($sp)
            add $fp, $sp, 12

            li $v0, 4
            la $a0, prompt
            syscall

            li $v0, 5
            syscall              # Value read left in $v0.

            sw $v0, -8($fp)

            lw $ra,  8($sp)      # restore registers & pop frame.
            lw $fp, 12($sp)
            add $sp, $sp, 12
            jr $ra


######################################################################
# factorial --- compute factorial of $a0 and return result through
#    $v0
######################################################################

            .text
factorial:
            sub $sp, $sp, 16
            sw $fp, 16($sp)
            sw $ra, 12($sp)
            sw $s0,  8($sp)
            add $fp, $sp, 16

            sw $a0, -12($fp)       # Our value n.
            move $s0, $a0

            bgt $s0, 1, recurse  # Base case.  Return 1
            li $v0, 1
            lw $s0, 8($sp)
            lw $ra, 12($sp)
            lw $fp, 16($sp)
            add $sp, $sp, 16
            jr $ra

recurse:    sub $a0, $a0, 1      # Recursive call.  Compute (n-1)!
            jal factorial
            mul $v0, $v0, $s0    # n * (n-1)!
            lw $s0, 8($sp)
            lw $ra, 12($sp)
            lw $fp, 16($sp)
            add $sp, $sp, 16
            jr $ra



Thomas P. Kelliher
Tue Nov 25 16:50:13 EST 1997
Tom Kelliher