# Non-Leaf Procedures and The Stack --- CS 130 // 2022-09-22 # Review ### Calling Our Leaf Procedure ```python def func(x,y): return x + y def main(): func(1, 2) ``` --- ```mips func: add $v0, $a0, $a1 jr $ra main: li $a0, 1 li $a1, 2 jal func ``` ### Procedure Calls ```python def main(): func(1, func(2, func(3, 4))) ``` --- ```mips main: li $a0, 3 li $a1, 4 jal func li $a0, 2 move $a1, $v0 jal func li $a0, 1 move $a1, $v0 jal func ``` ## Calling a Procedure 1. Put parameters in appropriate registers + `$a0`, `$a1`, `$a2`, `$a3` 2. Transfer control to the procedure: *jump and link* + `jal ProcedureLabel` - puts the current instruction's address into `$ra` 3. Perform task 4. Place result in a location the callee can find + `$v0`, `$v1` 5. Return control to the caller: *jump to addr. in register* + `jr $ra` ## Non-Leaf Procedures - Life would be easy if all procedures were "leaves" - In reality, a procedure might call another procedure which may call another procedure ... - could even be *recursive* - We need a way to preserve the state of each partially completed call so that they all return properly # Stack ## Stack - MIPS provides a register `$sp` that stores a memory address - Addresses **above** `$sp` is memory that is already being used by other parts of the program - Addresses **below** `$sp` is free memory ## Stack - The **called** procedure is responsible for restoring any saved registers `$s0`, ..., `$s7` as well as the stack pointer `$sp` register before returning - Any other register may be used without restoration, so the **calling** procedure is responsible for saving any data before making the call ## Memory Structure  ## Stack Frames  ## Exercise - Convert the following Python code into MIPS ```python def compute(e): return e + e def calc(c): d = compute(7) return c + d def main(): a = 5 b = calc(a) ``` ## Exercise Solution: Compute ```python def compute(e): return e + e ``` ```mips compute: add $v0, $a0, $a0 # returns e + e jr $ra ``` ## Exercise Solution: Calc - Take 1 ```python def calc(c): d = compute(7) return c + d ``` ```mips calc: li $a0, 7 # puts 7 in a0 jal compute # calls compute(7) add $v0, $v0, $a0 # adds argument to result jr $ra ``` - Unfortunately this will fail. Why? + Both `$a0` and `$ra` will be erased! ## Exercise Solution: Calc - Take 2 ```python def calc(c): d = compute(7) return c + d ``` ```mips calc: addi $sp, $sp, -8 # allocates space sw $a0, 0($sp) # stores c on the stack sw $ra, 4($sp) # stores $ra on the stack li $a0, 7 # puts 7 in a0 jal compute # calls compute(7) lw $ra, 4($sp) # restores $ra lw $a0, 0($sp) # restores argument addi $sp, $sp, 8 # deallocates space add $v0, $v0, $a0 # adds argument to result jr $ra ``` ## Exercise: Main ```python def main(): a = 5 b = calc(a) ``` ```mips main: li $s0, 5 # a = 5 move $a0, $s0 # loads a into argument jal calc # calls calc(5) move $s1, $v0 # b = result ``` ## Assignment - [Assignment 4](../../assignments/assignment-4/) - Translate a Python program that has functions and Arrays - 8 points - Part of it has been done - you'll do a "middle" function.