In this lesson, you will learn how to optimize your processor's efficiency by hiding the "cost" of branching through the use of delay slots.
The Problem with Branches
When a processor executes a branch instruction, it often doesn't know the next instruction address until the end of the pipeline stage where the condition is evaluated. In a standard pipeline, if the processor simply waited for this calculation, it would have to "flush" or stall the pipeline, wasting precious clock cycles. This is known as a control hazard.
Enter Delayed Branching
Delayed branching is a clever hardware-software collaboration. Instead of stalling the pipeline, the architecture is designed so that the instruction immediately following the branch is always executed, regardless of whether the branch is taken or not. This position is called the branch delay slot.
Your goal as a programmer or compiler is to fill that slot with a useful instruction that needs to happen anyway. If you can find an instruction that doesn't depend on the outcome of the branch, you effectively make the branch "free" in terms of performance.
A Concrete Example
Imagine we are adding two numbers and then jumping to a new routine:
ADD R1, R2, R3 ; Instruction A
BEQ R4, R5, Label ; Branch Instruction
SUB R6, R7, R8 ; Instruction B (in the delay slot)
In a system with delayed branching, the processor will execute the ADD, then execute the BEQ, and then—while it is busy calculating the branch target—it will execute the SUB instruction. By the time the SUB finishes, the hardware has resolved where to go next.
If we couldn't find a useful instruction to put in that slot, we would have to fill it with a NOP (No Operation), which would perform no work and result in a wasted cycle. By intelligently scheduling instructions, we keep the pipeline functional and maintain a high throughput.
Key Takeaway: Delayed branching optimizes performance by executing a useful, independent instruction during the branch calculation cycle, effectively hiding the pipeline delay.