diff --git a/section_1/recursion/README.md b/section_1/recursion/README.md new file mode 100644 index 0000000..6d0391d --- /dev/null +++ b/section_1/recursion/README.md @@ -0,0 +1,38 @@ +# Section 1 - recursion + +Let it be said right from the start: + +*Recursion in assembly language is not the ball of joy that it is in +higher level languages*. + +## Fibonacci Sequence + +The Fibonacci Sequence is one primary example of recursion. Consider +this example: + +```c++ +unsigned int FibonacciInC(unsigned int nthNumber) { + if (nthNumber <= 1) { + return nthNumber; + } + return FibonacciInC(nthNumber - 1) + FibonacciInC(nthNumber - 2); +} +``` + +The terminal condition is `nthNumber` less than or equal to 1. If the +parameter is less than or equal to 1, the very same value is returned. + +If the parameter is greater than 1, the result is the sum or the +results of the Fibonacci value of one less than the parameter plus the +results of two less than the parameter. + +## Recursion Leverages the Stack + +Notice that recursion is accomplished by simply calling a function +inside itself. All of the work of implementing recursion is hidden +behind the scenes by the compiler. + +Specifically, `nthNumber` and the results of +`FibonacciInC(nthNumber - 1)` is pushed onto (and popped off of) the +stack. The value of `FibonacciInC(nthNumber - 2)` doesn't go on the +stack because its results are used right away. diff --git a/section_1/recursion/fib.c b/section_1/recursion/fib.c index b73e7d5..972a4bb 100644 --- a/section_1/recursion/fib.c +++ b/section_1/recursion/fib.c @@ -11,11 +11,11 @@ unsigned int FibonacciInC(unsigned int nthNumber) { int main() { printf("In C:\n"); - for (unsigned int n = 0; n < 10; n++) { + for (unsigned int n = 0; n < 14; n++) { printf("Fibonacci number %2d is: %d\n", n, FibonacciInC(n)); } printf("In assembly language:\n"); - for (unsigned int n = 0; n < 10; n++) { + for (unsigned int n = 0; n < 14; n++) { printf("Fibonacci number %2d is: %d\n", n, Fib(n)); } return 0; diff --git a/section_1/recursion/fib.s b/section_1/recursion/fib.s deleted file mode 100644 index b30710e..0000000 --- a/section_1/recursion/fib.s +++ /dev/null @@ -1,115 +0,0 @@ - .arch armv8-a - .file "fib.c" - .text - .align 2 - .global FibonacciInC - .type FibonacciInC, %function -FibonacciInC: -.LFB0: - .cfi_startproc - stp x29, x30, [sp, -48]! - .cfi_def_cfa_offset 48 - .cfi_offset 29, -48 - .cfi_offset 30, -40 - mov x29, sp - str x19, [sp, 16] - .cfi_offset 19, -32 - str w0, [sp, 44] - ldr w0, [sp, 44] - cmp w0, 1 - bhi .L2 - ldr w0, [sp, 44] - b .L3 -.L2: - ldr w0, [sp, 44] - sub w0, w0, #1 - bl FibonacciInC - mov w19, w0 - ldr w0, [sp, 44] - sub w0, w0, #2 - bl FibonacciInC - add w0, w19, w0 -.L3: - ldr x19, [sp, 16] - ldp x29, x30, [sp], 48 - .cfi_restore 30 - .cfi_restore 29 - .cfi_restore 19 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE0: - .size FibonacciInC, .-FibonacciInC - .section .rodata - .align 3 -.LC0: - .string "In C:" - .align 3 -.LC1: - .string "Fibonacci number %2d is: %d\n" - .align 3 -.LC2: - .string "In assembly language:" - .text - .align 2 - .global main - .type main, %function -main: -.LFB1: - .cfi_startproc - stp x29, x30, [sp, -32]! - .cfi_def_cfa_offset 32 - .cfi_offset 29, -32 - .cfi_offset 30, -24 - mov x29, sp - adrp x0, .LC0 - add x0, x0, :lo12:.LC0 - bl puts - str wzr, [sp, 24] - b .L5 -.L6: - ldr w0, [sp, 24] - bl FibonacciInC - mov w2, w0 - ldr w1, [sp, 24] - adrp x0, .LC1 - add x0, x0, :lo12:.LC1 - bl printf - ldr w0, [sp, 24] - add w0, w0, 1 - str w0, [sp, 24] -.L5: - ldr w0, [sp, 24] - cmp w0, 9 - bls .L6 - adrp x0, .LC2 - add x0, x0, :lo12:.LC2 - bl puts - str wzr, [sp, 28] - b .L7 -.L8: - ldr w0, [sp, 28] - bl Fib - mov w2, w0 - ldr w1, [sp, 28] - adrp x0, .LC1 - add x0, x0, :lo12:.LC1 - bl printf - ldr w0, [sp, 28] - add w0, w0, 1 - str w0, [sp, 28] -.L7: - ldr w0, [sp, 28] - cmp w0, 9 - bls .L8 - mov w0, 0 - ldp x29, x30, [sp], 32 - .cfi_restore 30 - .cfi_restore 29 - .cfi_def_cfa_offset 0 - ret - .cfi_endproc -.LFE1: - .size main, .-main - .ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0" - .section .note.GNU-stack,"",@progbits diff --git a/section_1/recursion/fibo.s b/section_1/recursion/fibo.s index cff5772..30415ae 100644 --- a/section_1/recursion/fibo.s +++ b/section_1/recursion/fibo.s @@ -3,19 +3,38 @@ .align 4 Fib: str x30, [sp, -16]! - cmp w0, 1 + // If w0 is 0 or 1, take the branch to return w0. + cmp w0, 1 bls 99f // If we get here, we need to do the recursion. // Save the parameter on the stack so we can // get it back between recursions. - str w0, [sp, -16]! + // nthNumber to be stored at 16 off sp + str w0, [sp, -16]! // +1 + + // Execute Fib(nthNumber - 1) sub w0, w0, 1 bl Fib - ldr w0, [sp], 16 // temporary + + // Fib(n-1) stored at 32 of sp + str w0, [sp, -16]! // +2 + // Execute Fib(nthNumber - 2) + ldr w0, [sp, 16] + sub w0, w0, 2 + bl Fib + + // Restore the results of Fib(nthNumber - 1) and also + // undo the stack change associated with preserving it. + ldr w1, [sp], 16 // +1 + add w0, w0, w1 + + // Undo the stack change due to storing nthNumber + ldr w1, [sp], 16 // 0 + 99: ldr x30, [sp], 16 ret