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