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