Lecture 11
Andreas Moshovos
Fall 2007
A complete function example: The Ackerman recursive subroutine.
The following C code computes the Ackerman function:
int
Ackerman(unsigned
int x, unsigned int y)
{
if
(x == 0) return y+1;
if
(y == 0) return Ackerman (x-1, 1);
return
Ackerman (x-1, Ackerman(x, y-1));
}
This is an interesting to implement function because it’s recursive and also shows how to use a function call as an argument to call another function.
An equivalent implementation of Ackerman that illustrates what is supposed to happen in the last line is as follows:
int
Ackerman(unsigned
int x, unsigned int y)
{
int tmp;
if
(x == 0) return y+1;
if
(y == 0) return Ackerman (x-1, 1);
tmp = Ackerman(x, y-1);
return
Ackerman (x-1, tmp);
}
Let’s first figure out what needs
to be saved on the stack. We definitely need to save the return address since
Ackerman calls functions. We also need to preserve the value of parameter x
across the call to function Ackerman(x, y-1). We do not need to preserve y since we never needed after a
call. So, in total we need space for two words. Here’s what the stack frame
will look like after Ackerman’s prologue:
sp à |
+0 |
Saved r4 /
argument x |
|
+4 |
Saved ra / return address |
Here’s an implementation in NIOS II assembly:
.text
Ackerman:
# Prologue
addi
sp, sp, -8
stw ra, 4(sp)
# if
(x == 0) return y +1
# we
write this as:
# if
(x != 0) skip over the code that returns y + 1
bne r4, r0, Xnot0
Xis0:
# return
value is y + 1
addi
r2, r5, 1
# done, return from
the function
br epilogue
Xnot0:
# test if y is 0 and
return Ackerman (x – 1, 1)
bne r5, r0, Ynot0
Yis0:
# pre-call
# pass
arguments
# first
argument is x-1
addi
r4, r4, -1
# second is 1
addi r5, r0, 1
call Ackerman
# the return value is
already in r2, exit the function
br
epilogue
Ynot0:
# first call Ackerman
(x, y-1)
# pre-call
# preserve
the value of x on the stack
stw r4,
0(sp)
# pass
arguments
# x
is in the right place
# decrement
y by 1
addi r5, r5, -1
call Ackerman
# post-call
# restore x
ldw r4,
0(sp)
# call
Ackerman (x-1, tmp) where tmp
is the value returned from Ackerman (x, y-1)
# pre-call
# decrement
x by 1 and pass as first argument
addi r4, r4, -1
add r5, r2, r0
call Ackerman
# return
value is already in r2
epilogue:
# Epilogue
# restore
ra and de-allocate stack space
ldw ra, 4(sp)
addi sp, sp, 8
ret # return to caller