L11 [Stack Subroutines] - Skyline-9/CS2110-Notes GitHub Wiki

L11 [Stack Subroutines]

Let's say we want to write a recursive fact function

int fact(int n) {
    int answer;

    if(n <= 0) answer = 1;
    else answer = n * fact(n - 1);

    return answer;
}

Initial Part

Building the stack frame is always the same

FACT    ADD R6, R6, -4      ; Allocate Space
        STR R7, R6, 2       ; Save Ret Addr
        STR R5, R6, 1       ; Save Old FP
        ADD R5, R6, 0       ; Copy SP to FP
        ADD R6, R6, -5      ; Room for 5 registers

        ;; Save the registers
        STR R0, R5, -1
        STR R1, R5, -2
        STR R2, R5, -3
        STR R3, R5, -4
        STR R4, R5, -5

Let's write the teardown first and then go into the middle and write the code for factorial

The Ending

Let's use R0 as the scratch register first. So, where does answer live? R5 + 0.

Where does the return value live? R5 + 3

LDR R0, R5, 0   ; Return value = answer
STR R0, R5, 3   ; Return Addr is R5 + 3
LDR R4, R5, -5  ; restore R4
LDR R3, R5, -4  ; restore R3
LDR R2, R5, -3  ; restore R2
LDR R1, R5, -2  ; restore R1
LDR R0, R5, -1  ; restore R0
ADD R6, R5, 0   ; Restore SP
LDR R5, R6, 1   ; Restore FP
LDR R7, R6, 2   ; Restore Return Address
ADD R6, R6, 3   ; Pop ra, fp, 1v1
RET

The Code In-Between Stack Buildup and Teardown

Where does the first parameter live? R5 + 4

; if (n <= 0) {
LDR R0, R5, 4   ; Load n into R0
BRP IFELSE1     ; Branch on failure

; answer = 1
AND R0, R0, 0
ADD R0, R0, 1
STR R0, R5, 0

; } else {
BR ENDIF1

; answer = n * fact(n - 1);
; rewrite: R0 = fact(n - 1); answer = mult(n, R0)

IFELSE1     LDR R0, R5, 4   ; Push n - 1
            ADD R0, R0, -1

            ;; Starting a new stack frame
            ADD R6, R6, -1
            STR R0, R6, 0

            JSR FACT        ; fact(n - 1)
            LDR R0, R6, 0   ; R0 = return value
            ADD R6, R6, 2   ; Pop return value and arg1
                            ; Note that the stack frame is now gone

            ;; answer = mult(n, R0)
            ADD R6, R6, -1  ; Push R0
            STR R0, R6, 0
            ADD R6, R6, -1  ; Push n
            LDR R0, R5, 4
            STR R0, R6, 0

            JSR MULT        ; mult(n, R0)
            LDR R0, R6, 0   ; answer = return value
            STR R0, R5, 0
            ADD R6, R6, 3   ; Pop return value and arg1-2

To call a subroutine, just push the argument in reverse order

Equality of stack buildup and teardown