the delayed branch
Suppose you announce 'I'm leaving the room — but first, whoever is next to me, finish your sentence.' You have turned the awkward pause of leaving into a chance to get one more useful thing done. The delayed branch is that bargain applied to control hazards: the instruction immediately after a branch always executes, taken or not, so the cycle that would otherwise be wasted waiting for the branch outcome does real work instead.
Here is the mechanism. A branch causes a control hazard because its outcome is not known in time to fetch the right next instruction. An old fix, prominent in early RISC designs like MIPS, was to redefine the instruction set so that the slot right after a branch — the branch delay slot — is always executed regardless of whether the branch is taken. The compiler (or assembly programmer) then tries to fill that slot with a genuinely useful instruction that should run either way: often an instruction from before the branch that does not affect the condition, moved down into the slot. If no useful instruction can be found, the slot is filled with a nop, and the cycle is simply wasted — no worse than a plain stall.
The delayed branch was a clever, cheap trick when pipelines were short and shallow, exposing the pipeline's timing directly to software. But it has fallen out of favour, and honesty demands saying why: it is a leaky abstraction that bakes a specific pipeline depth into the architecture, so a single delay slot is the wrong number once pipelines grow deeper. Modern processors abandoned it in favour of branch prediction, which hides control hazards entirely in hardware without burdening the instruction set. The delayed branch survives mostly as a historical lesson and as legacy baggage in old ISAs.
In MIPS, beq x1, x2, L; add x3, x4, x5 — the add in the delay slot runs whether or not the branch to L is taken. A compiler fills the slot with an instruction that was going to run anyway, turning the branch's would-be stall cycle into useful work.
The delayed branch always runs the instruction in its delay slot, reclaiming a wasted cycle — a short-pipeline trick now superseded by prediction.
The delayed branch is a textbook example of a leaky abstraction: it exposes microarchitectural timing to the ISA, which then ages badly as pipelines deepen. RISC-V deliberately omits delay slots, leaving control hazards to hardware prediction.