The rules for MIPS call convention

 

Stack allocation:

 

Reading this document:

A is the maximum number of outgoing arguments for which this function needs to allocate space (see non-leaf function section).  It uses P preserved registers, and it has L words of local data.

 

 

When to do things:

 

Rule 1:  The first instruction(s) in the function manipulate $fp and $sp

addi $sp, $sp, -(L+P+A+1+1)*4  (or however much space you need)

 

            Corollary 1:  $sp is not changed at any other point than the first and last instructions in the function.

             

 

Rule 2:  If you want to use any preserved register in any place during the function, you must store it into the stack when you enter the function (not when you use it).  Let’s assume we are storing P registers for examples below.

sw $s0, (A+L)*4 ($sp)

sw $s1, (A+L+1)*4($sp)

sw $s2, (A+L+2)*4($sp) 

sw $fp, (A+L+P+padding)*8 ($sp)

sw $ra, (A+L+P+padding+1)*8 ($sp)

 

Rule 3:  If you make a function call, and want the value in a non-preserved register after the function call, you must have allocated space in the stack (in the “local data” section) at the beginning and store the register now.

 

Rule 4:  You may pass information into a function through only $a0-$a3 and extra stack arguments.  You may not use the value held in any other register (i.e. $v0, $s0).

 

Rule 5:  You may pass information out of a function through only $v0-$v1 – not $a0-$a3.

 

Rule 6:  You may only enter a function at its beginning.  You may not jal into the middle of a function.

 

Rule 7:  You may have only one jr $ra in each function.  It is the last instruction in the function.

 

Extra rules for non-leaf functions:

 

Step 1:  Look at the declarations for all procedures this function might call.  Find the one with the largest number of outgoing arguments, a.  The amount of extra space you need to allocate for outgoing arguments is the larger of (a-4) and 0.  For this section, I will refer to max (a, 4)  as A.

 

Rule 8:  You must allocated space for all extra outgoing arguments.  Remember, $sp may only be changed in the first line of the function.  You must have allocated an extra A *4 bytes upon entry into your function.

 

Rule 9: 

Passing only 4 arguments:  Place the arguments in $a0 - $a3

Passing more than 4 arguments:  Place the first 4 arguments in $a0 - $a3.  Every argument past the 4th is placed on the stack.

 

add $a0, $s0, $zero

add $a1, $s1, $zero

add $a2, $s2, $zero

add $a3, $s3, $zero

sw $s4, 0($sp)                         # store 5th argument in the stack!!!  Always at this location.

sw $s5, 4($sp)                         # store 6th argument in the stack, always at this location.

 

Rule 10:  You must preserve register $ra because jal destroys the value, and it is a preserved register.

sw $ra, A*4 + P*4($sp)

 

Calculating how much stack space you need:

Stack space = (A + L + P + R + padding)*4

A:  See non-leaf  function rules for the calculation of A.

L:  Local data.  Look for all variables declared in the local scope.  In addition, if this is a non-leaf function, you must allocate space for $a0-$a3 and any other temporary registers you wish to store across function calls.  L >= 4 because you must always allocate for $a0-$a3, just in case.

P:  Allocate space for all preserved registers you wish to use.

R:  Allocate space for $ra and $fp if this is a non-leaf function

padding:  If (A+L+P+R)*4 is not divisible by 8 (or A+L+P+R is not even), then you must add one extra word for padding.  This is because $sp must always  be evenly divisible by 8.  Floating-point numbers are 8 bytes, and their addresses must be divisible by 8.

 

Checking to make sure your code follows call convention:

 

First make sure your code runs properly.  Then:

 

1.  Inspect your code to make sure you followed all rules, especially 1, 3, and 6.

 

2.  To help verify that you followed rules 2, 4, and 5, insert the following into your code:

 

If you insert the following code directly after storing all of the preserved registers into the stack:

 

addi $t0, $zero, -5

addi $t1, $zero, -5

addi $t2, $zero, -5

addi $t3, $zero, -5

addi $t4, $zero, -5

addi $t5, $zero, -5

addi $t6, $zero, -5

addi $t7, $zero, -5

addi $t8, $zero, -5

addi $s0, $zero, -5

addi $s1, $zero, -5

addi $s2, $zero, -5

addi $s3, $zero, -5

addi $s4, $zero, -5

addi $s5, $zero, -5

addi $s6, $zero, -5

addi $s7, $zero, -5

addi $v0, $zero, -5

addi $v1, $zero, -5

 

 

Insert the following code directly before restoring the preserved registers from the stack:

addi $t0, $zero, -5

addi $t1, $zero, -5

addi $t2, $zero, -5

addi $t3, $zero, -5

addi $t4, $zero, -5

addi $t5, $zero, -5

addi $t6, $zero, -5

addi $t7, $zero, -5

addi $t8, $zero, -5

addi $s0, $zero, -5

addi $s1, $zero, -5

addi $s2, $zero, -5

addi $s3, $zero, -5

addi $s4, $zero, -5

addi $s5, $zero, -5

addi $s6, $zero, -5

addi $s7, $zero, -5

addi $a0, $zero, -5

addi $a1, $zero, -5

addi $a2, $zero, -5

addi $a3, $zero, -5