The rules for MIPS call convention
Stack allocation:
$sp
before call
L*4 bytes for
local data
4+ 32-bit words
arg1-arg4
(incoming args)
local data
padding
$ra
P*4 bytes for
preserved regs
($s0-$s7)
A*4 bytes for
outgoing args
$sp
during call
preserved registers
4+ 32-bit words
arg1-arg4
(outgoing args)
Reading this document:
A is the maximum number of outgoing arguments that this function needs (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 in your function is to decrement the stack pointer
add $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*4 ($sp)
sw $s1, A*4+4($sp)
sw $s2, A*4+8($sp) …
sw $ra, A*4+P*4 ($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 and the beginning and store
the register now.
Exception: $a0-$a3. You need to store these, but you need not allocate space for
them. The calling function already allocated space for you. B is the total number of
bytes by which $sp was decremented at the beginning of the function call. Note that this
is placing $a0 in the caller’s stack, not this function’s stack.
sw $a0, B ($sp)
sw $a1, B+4 ($sp)
Rule 4: You may pass information into a function through only $a0-$a3. You may not
use the value held in any other register (i.e. $v0).
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 and 4 (You always allocate at least
4). For this section, I will refer to max (a, 4) as A.
Rule 8: You must allocated space for all 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. In Rule
7, you allocated space for all outgoing arguments, so every argument past the 4th is
placed in its location on the stack. Note: Space is still allocated for the first 4. We just
do not use them to pass the arguments.
add $a0, $s0, $zero
add $a1, $s1, $zero
add $a2, $s2, $zero
add $a3, $s3, $zero
sw $s4, 16($sp)
sw $s5, 20($sp)
# store 5th argument in the stack!!! Always at this location.
# 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($sp)
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 rules 1, 3, and 6.
2. To make sure 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
Download

MIPSCallingConvention