int fib(int n)
{
if (n <= 1) return 1;
else return fib(n-1)+fib(n-2);
}
Oplossing
fib: addi $sp,$sp,-12
sw $ra,8($sp) # push $ra on stack
sw $a0,4($sp) # push n ($a0) on stack
sw $s0,0($sp) # push $s0 on stack!
slti $t0,$a0,2 # $t0 = (n <= 1)
beq $t0,$zero,fib_else # if (!$t0) goto fib_else
addi $v0,$zero,1 # return 1 (in $v0)
addi $sp,$sp,8 # no need to restore $ra,$a0,$s0
jr $ra # return
fib_else:
addi $a0,$a0,-1 # n = n-1
jal fib # $v0 = fib(n-1)
lw $a0,0($sp) # restore $a0
addi $a0,$a0,-2 # n = n-2
add $s0,$v0,$zero # $s0 = fib(n-1)
jal fib # $v0 = fib(n-2)
add $v0,$v0,$s0 # return fib(n) = fib(n-1)+fib(n-2)
lw $s0,0($sp) # restore $s0
lw $ra,8($sp) # restore $ra; need not restore $a0
addi $sp,$sp,12 # restore $sp
jr $ra # return
Opmerkingen:
- Op het eerste gezicht lijkt het alsof n ($a0) niet gesaved hoeft te
worden, want hij is na de recursieve aanroep niet nodig. Echter, hij
is nog nodig voor de tweede recursieve aanroep en moet derhalve wel
gesaved worden. Het volstaat niet om er 1 i.p.v. 2 vanaf te trekken voor
de twee recursieve aanroep, want de eerste recursieve aanroep verandert
de waarde van $a0.
- Het resultaat van fib(n-1) wordt gecopieerd naar $s0, omdat fib(n-2)
ook $v0 als resultaat-register gebruikt. De oude inhoud zou dus
verloren gaan. $s0 hoeft niet gesaved te worden voor de
tweede recursieve aanroep, want het is een saved register.
Het is de verantwoordelijkheid van de callee deze te saven.
Dat gebeurt ook, in de 4e regel en de op 3 na laatste.