Funciones
en MIPS
Ciencias de la Computación III
Diego José Figueroa
¿Cómo llamo a una función?
¿Cómo le envío argumentos?
¿Cómo obtengo su resultado?
¿Cómo administro los registros?
Primero, un recordatorio...
Stack
- El stack siempre crece hacia abajo.
- $sp apunta al tope del stack.
- Siempre mantengan $sp en el tope del stack.
- Todo lo que esté arriba (>= $sp) es espacio ocupado.
- Todo lo que esté abajo (< $sp) es espacio libre.
-
$sp siempre debe estar alineado en múltiplos de 4.
Stack
¿Cómo obtengo espacio libre en el stack?
addi $sp $sp -4 # reservo 1 word
Stack
addi $sp $sp -8 # reservo 2 words

Stack
¿Cómo uso ese espacio?
sw $s0 0($sp) # *($sp + 0) <- $s0
sw $s1 4($sp) # *($sp + 4) <- $s1
Utilizamos cualquier instrucción para escribir a memoria, según sea apropiado (sb, sw, etc.), y usamos $sp como la base de la dirección.
Stack
¿Cómo libero ese espacio?
addi $sp $sp 8 # sumo 8
Regresamos $sp a su lugar inicial.
Stack
¿Para qué nos puede servir?
- Valores temporales
- Variables locales
- Copias de registros
- Paso de parámetros
Llamadas a funciones
- Cargar los argumentos a $a0 - $a3
- Hacer jal a la función (etiqueta)
- La función, antes de terminar hace jr $ra.
- Al regresar de la función, buscamos el valor de retorno en $v0 (y $v1).
Llamadas a funciones
-
Según el convenio de MIPS, dentro de la función:
- $s0 - $s7, $sp, $fp, no deben cambiar.
- $t0 - $t9, $a0 - $a3, pueden cambiar.
- $ra no debe cambiar.
- Cualquier valor arriba de $sp no debe cambiar.
Llamadas a funciones
- El convenio de MIPS no presenta mayor complicación para funciones simples.
- Pero, ¿qué implica si dentro de una función queremos llamar a otra función?
- ¿Qué pasa con $ra?
- ¿$a0 - $a3?
- ¿$t0 - $t9?
- ¿$s0 - $s7?
Procedimiento general
al entrar a una función
- Reservar espacio necesario en el stack
- 1 word para cada registro que no deba cambiar
- $ra
- argumentos
- Guardar los registros necesarios
- Copiar $aX a un lugar seguro ($sX o al stack)
- Guardar $ra
Procedimiento general
al salir de una función
- Poner valor de retorno en $v0 (y $v1).
- Restaurar registros que no deben cambiar.
- Restaurar $ra,
- Liberar el stack (regresar $sp a su estado inicial).
- jr $ra.
Ejemplo
fibn:
addi $sp $sp -12 # reservar
sw $s0 0($sp) # guardar $s0
sw $s1 4($sp) # guardar $s1
sw $ra 8($sp) # guardar $ra
...
Ejemplo
li $v0 0 # caso base,
beq $a0 $v0 fibn_done # devolver 0
li $v0 1 # caso base
beq $a0 $v0 fibn_done # devolver 1
move $s0 $a0 # mover $a0 a $s0
addi $a0 $s0 -1
jal fibn # call fibn n-1
mov $s1 $v0 # almacena el result
addi $a0 $s0 -2
jal fibn # call fibn n-2
add $v0 $v0 $s1 # resultado final
Ejemplo
fibn_done:
lw $s0 0($sp) # restaurar los
lw $s1 4($sp) # registros
lw $ra 8($sp)
addi $sp $sp 12 # restaurar $sp
jr $ra # regresar