Reverse Transfer of Control in Compilers



In code generation, loops and jump instructions play a crucial role in controlling the program flow. Intermediate code generation is a key phase in the compiler that converts high-level constructs into machine-interpretable code. While instructions generally follow a linear sequence, there are many cases where the execution needs to loop back to a previous instruction. This backward flow, known as reverse transfer of control, is essential for implementing loops, recursion, and error recovery.

In this chapter, we will discuss reverse transfer of control, its types, and how compilers generate machine code to handle backward jumps.

What is Reverse Transfer of Control?

Reverse transfer of control occurs when execution jumps backward to re-execute a set of instructions. So, when is it needed?

Reverse transfer of control can be useful in the following scenarios −

  • Loops − Repeating code until a condition is met.
  • Function Recursion − Functions calling themselves until a base case is reached.
  • Error Recovery − Retrying operations after failures.

Unlike the forward transfers, the backward jumps focus on iteration and repetition. Now the compiler generates optimized instructions (for example, J, BGE, JAL) to give efficient backward control flow.

Types of Reverse Transfer of Control

Let us check the different types of reverse transfer of control −

Loops (While, For, Do-While)

Loops rely on backward jumps to repeat code blocks. The compiler places condition checks and jump instructions strategically.

Example: While Loop in C

Take a look at the following example −

while (i < 10) {  
   i = i + 1;  
}  

Intermediate Representation (IR) using Atoms

(LBL, L1)  
(TST, i, 10, <, L2)   # If i >= 10, exit loop  
(ADD, i, 1, i)        # i = i + 1  
(JMP, L1)             # Repeat loop  
(LBL, L2)

Translation to Machine Code (MIPS Example)

L1:  
    lw $t1, i  
    li $t2, 10  
    bge $t1, $t2, L2   # If i >= 10, exit loop  

    addi $t1, $t1, 1   # i = i + 1  
    sw $t1, i  
    j L1               # Repeat loop  

L2:  

Here, we can see the j L1 instruction transfers control backward to keep executing the loop.

Do-While Loops

Let us see the other type of loop. This is exit control loop. Unlike while loops, do-while loops always execute at least once before checking the condition. The compiler places the loop condition check at the end and jumps backward if the condition is still valid.

Example: Do-While Loop in C

Take a look at the following example −

do {  
   i = i + 1;  
} while (i < 10);   

Intermediate Representation (IR) using Atoms −

(LBL, L1)  
(ADD, i, 1, i)        # i = i + 1  
(TST, i, 10, <, L1)   # If i < 10, repeat loop  

Translation to Machine Code (MIPS Example) −

L1:  
    addi $t1, $t1, 1   # i = i + 1  

    lw $t1, i  
    li $t2, 10  
    blt $t1, $t2, L1   # If i < 10, repeat loop  

The blt (branch if less than) instruction will transfers control backward to L1, repeating execution.

For Loops

A for loop is also an entry control loop. But it has initialization, condition check, and increment in a structured form. The compiler generates jumps to handle the condition check and iteration step.

Example: For Loop in C

Take a look at the following example −

for (i = 0; i < 10; i++) {  
   sum = sum + i;  
}   

Intermediate Representation (IR) using Atoms −

(MOV, 0, , i)         # i = 0  
(LBL, L1)  
(TST, i, 10, <, L2)   # If i >= 10, exit loop  
(ADD, sum, i, sum)    # sum = sum + i  
(ADD, i, 1, i)        # i = i + 1  
(JMP, L1)             # Repeat loop  
(LBL, L2)   

Translation to Machine Code (MIPS Example) −

    li $t1, 0          # i = 0  
L1:  
    bge $t1, 10, L2    # If i >= 10, exit loop  

    add $t3, $t3, $t1  # sum = sum + i  
    addi $t1, $t1, 1   # i = i + 1  
    j L1               # Repeat loop  

L2:  

Here, we can see the condition check and increment operations are separate, with j L1  that is transferring control backward.

Function Recursion

For function based approaches like recursions the backward transfer occurs. In recursive function calls, where execution jumps back to the function's starting point until a base condition is met.

Example: Factorial Function in C

Take a look at the following example −

int factorial(int n) {  
   if (n == 0) return 1;  
   return n * factorial(n - 1);  
}   

Intermediate Representation (IR) using Atoms −

(TST, n, 0, ==, L1)   # If n == 0, return 1  
(SUB, n, 1, T1)  
(CALL, factorial, T1, T2)  
(MUL, n, T2, R)       # R = n * factorial(n-1)  
(LBL, L1)  
(MOV, 1, , R)

Translation to Machine Code (MIPS Example) −

factorial:  
    beq $a0, 0, base_case   # If n == 0, return 1  

    addi $sp, $sp, -4  
    sw $ra, 0($sp)          # Save return address  

    addi $a0, $a0, -1  
    jal factorial           # Recursive call  

    lw $ra, 0($sp)  
    addi $sp, $sp, 4  
    mul $v0, $a0, $v0       # Multiply n * factorial(n-1)  
    jr $ra                  # Return  

base_case:  
    li $v0, 1               # Return 1  
    jr $ra 

Each recursive call transfers control backward to factorial, this is executing another function call until reaching the base case.

To help remember the Reverse Transfer of Control easily, you can follow the table given below −

Type Usage Machine Instructions
While Loops Iteration with condition check BGE, BLT, J
Do-While Loops Ensures at least one execution BLT, J
For Loops Structured iteration BGE, ADD, J
Recursion Function calls returning back JAL, JR, BEQ

Conclusion

In this chapter, we explored the concept of reverse transfer of control in compiler design which is fundamental for handling loops and recursion. Compilers translate high-level constructs such as while loops, for loops, and recursive functions into branch and jump instructions to enable efficient backward execution.

We covered how compilers manage backward jumps, how developers can write optimized code, and how iteration and recursion function at a low level. Whether it's a simple loop or a complex recursive algorithm, reverse control transfer ensures that programs execute repetitively and predictably.

Advertisements