Nested subroutine calls in ARM Architecture - Time & Space Complexity
When subroutines call other subroutines inside them, the total work can grow quickly.
We want to know how the number of calls grows as input size increases.
Analyze the time complexity of the following code snippet.
main:
mov r0, #n // input size
bl subroutine1
b end
subroutine1:
cmp r0, #0
beq return1
sub r0, r0, #1
bl subroutine2
return1:
bx lr
subroutine2:
cmp r0, #0
beq return2
sub r0, r0, #1
bl subroutine1
return2:
bx lr
This code shows two subroutines calling each other recursively, decreasing the input each time.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls between subroutine1 and subroutine2.
- How many times: Each call reduces input by 1, so calls happen about 2n times in total.
Each call leads to another call, alternating between the two subroutines, until input reaches zero.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 calls |
| 100 | About 200 calls |
| 1000 | About 2000 calls |
Pattern observation: The number of calls grows roughly in a straight line with input size.
Time Complexity: O(n)
This means the total work grows directly in proportion to the input size.
[X] Wrong: "Because the subroutines call each other, the time grows exponentially."
[OK] Correct: Each call reduces the input by one, so calls happen in a chain, not branching out exponentially.
Understanding how nested calls affect performance helps you explain recursive code clearly and reason about efficiency in real projects.
"What if each subroutine called itself twice instead of calling the other subroutine? How would the time complexity change?"
Practice
Solution
Step 1: Understand subroutine calls
A subroutine is a small program block that can be called to perform a task.Step 2: Define nested calls
Nested calls happen when one subroutine calls another subroutine inside its code.Final Answer:
One subroutine calls another subroutine inside it -> Option CQuick Check:
Nested call = one subroutine calls another [OK]
- Confusing nested call with recursion
- Thinking subroutine runs alone without calls
- Mixing up call and return instructions
Solution
Step 1: Identify call instruction
In ARM, the instruction to call a subroutine is 'BL' which means Branch with Link.Step 2: Differentiate from return instruction
'BX LR' is used to return from a subroutine, not to call it.Final Answer:
BL -> Option BQuick Check:
Call subroutine = BL instruction [OK]
- Confusing BX LR as call instead of return
- Using MOV or ADD as call instructions
- Mixing up branch instructions without link
main: MOV R0, #1 BL sub1 BX LR sub1: ADD R0, R0, #2 BL sub2 BX LR sub2: ADD R0, R0, #3 BX LR
Solution
Step 1: Trace main and sub1 execution
Start with R0=1 in main. Then BL sub1 calls sub1. In sub1, R0 = 1 + 2 = 3.Step 2: Trace sub1 calling sub2
sub1 calls sub2. In sub2, R0 = 3 + 3 = 6. Then sub2 returns, sub1 returns, main returns.Final Answer:
6 -> Option DQuick Check:
1 + 2 + 3 = 6 [OK]
- Ignoring sub2 addition
- Not updating R0 after each call
- Confusing return with call instructions
main: BL sub1 BX LR sub1: ADD R0, R0, #1 BL sub2 BX LR sub2: ADD R0, R0, #2 BX R0
Solution
Step 1: Check return instructions
Subroutines should return using 'BX LR' to jump back to caller address stored in LR.Step 2: Identify incorrect return
In sub2, 'BX R0' tries to jump to address in R0, which is incorrect and causes error.Final Answer:
Using BX R0 instead of BX LR to return in sub2 -> Option AQuick Check:
Return must use BX LR, not BX R0 [OK]
- Using BX R0 instead of BX LR
- Confusing BL and BX instructions
- Assuming R0 holds return address
Solution
Step 1: Understand call and return instructions
BL saves return address in LR and branches to subroutine; BX LR returns to caller.Step 2: Handle nested calls safely
If a subroutine calls another, it must save LR (e.g., on stack) before calling to avoid losing return address.Final Answer:
Always use BL to call and BX LR to return, saving LR if calling another subroutine -> Option AQuick Check:
BL call + BX LR return + save LR for nested calls [OK]
- Using BX LR to call instead of BL
- Not saving LR before nested calls
- Jumping with MOV ignoring LR
Ready to prove it?
Pass the test and this pattern moves unknown
