You're doing this as homework, and the purpose is not to eliminate or optimize the recursion but to translate the function in the recursive spirit intended by the assignment, so you can learn about stack frames, return addresses, variables live across a call, etc..
The link provided for the compiler example in comments above, have optimized the code so severely that none of the lessons you're supposed to learn remain in the resulting code. (We all know that recursion is overkill for summing consecutive value of an array, but that's the assignment.)
You're code needs to do something after jal
, since at some point (when working properly) it will return to the instruction after the recursive jal
.
Something needs to go into $v0
on each return path — there's a difference between the return address (register $ra; sometimes referred to as linkage in older terminology) and the return value (register $v0). Both are necessary, but they are separate concepts, so don't use/confuse one for the other. The return address is a pointer to a machine code instruction used to return control of the processor's instruction stream to the caller; whereas the return value here is just an integer value like 0 or the sum, used to return the function answer aka return value to the caller.
Recursion is one function calling another (that turns out to be the same function). When dealing with calling a function (modulo advanced optimization), we need to preserve values that are defined before and used after a call.
For one, the return address is a parameter value that is needed at the very end of the function and used to return to the caller (jr $ra
).
For another, let's look more closely at this expression:
*array + arraySum(&array[1], arraySize-1)
Obviously, we cannot add (+
) until the call to arraySum
has return an operand. Therefore, depending on how you code this up, either array
or *array
is needed after the call. (It doesn't matter that it is recursive: any call of anything in the same manner will require similar analysis.)
By the C language standard, a C compiler (implementation) is free to dereference array
(as in *array
) before the call to arraySum
or after. Either way, one more value needs to survive the function call: if the dereference is done beforehand then the value of the dereferenced element needs to be preserved for use by add after the function call, or if the dereference is delayed then the array
parameter itself must be preserved in order to do the dereference (and next the addition) after the call.
So, this function requires two items to survive the function call. One is the return address and the other is either the array
parameter or the *array
element value.
Let's arbitrarily choose to dereference the array
parameter after the function returns.
Preserving these items is done using stack space — by allocating a stack frame. Allocating a stack frame implies deallocating it at the end before returning to the caller. Since this code is expressed without loops, there's no need or advantage to using $s
registers here, so the function prologue should simply allocate 2 words of stack space and store the return address there ($ra
), and array
($a0
). In order to do the addition after the function call, the value of the array
parameter should be reloaded from the stack, dereferenced, and added to the return value ($v0
) of the function call.
Function epilogue should reload the return address ($ra
) and deallocate the stack space. (There is no need to restore ($a0
) for the caller.)
The other approach is to dereference array
before the function call, which means one word of stack space will be used to save the value of the dereference, so it can be recreated after the function call.
Similarly, allocate 2 words of stack space and store the return address in one of the words. The other word is used in evaluation of the above addition expression, so the dereference happens before the call, and its value is stored in the other stack allocated word. After the function call, that dereferenced value is restored to a register so that both operands of the add are now in registers and can be summed to $v0
.
Epilogue needs to restore the return address, otherwise deallocate stack space, and return to the caller.