Visual walkthrough — Load-use hazard and stalls
This page rebuilds the central result of the parent topic from absolute zero. If a word looks unfamiliar, it gets a picture before it gets used.
Step 1 — What a pipeline stage even is
WHAT. A modern processor does not finish one instruction before starting the next. It splits the work into five little workshops and lets an instruction move through them one per clock beat, like a car down an assembly line. The five workshops (the Five-stage MIPS pipeline) are:
- IF — Instruction Fetch: grab the instruction from memory.
- ID — Instruction Decode: read the register values it needs.
- EX — Execute: the ALU does the arithmetic.
- MEM — Memory: talk to data memory (only loads/stores use this).
- WB — Write Back: write the result into a register.
WHY these five and not one big blob? Because if each workshop is busy every beat, you finish (almost) one instruction per beat instead of one every five beats. That is the entire point of pipelining — throughput.
PICTURE. Below, one instruction is a horizontal strip sliding rightward, one box per drumbeat of the machine. That drumbeat is what we now name.

Step 2 — Stacking two instructions: the diagonal
WHAT. Put two instructions in the pipeline back-to-back. The second one starts one cycle later than the first. Draw both and they form a staircase — each instruction's strip is shifted one box to the right of the one above.
WHY a diagonal? Because the pipeline can only fetch one new instruction per cycle. So instruction #2 cannot enter IF until #1 has left IF. That forced one-cycle offset is the source of every timing story on this page — remember it.
PICTURE. Two strips, offset by one. Follow the yellow "offset" arrow: the second row is shoved right by exactly one cycle.

Now let us pin down the exact cycles each stage lands in. If instruction #1 starts IF in cycle 1:
Instruction #1
Instruction #2 (one cycle later)
Hold onto those two numbers: #1's MEM is cycle 4, and #2's EX is cycle 4. They collide. Step 4 is where that collision bites.
Step 3 — When is a value produced, and when is it needed?
WHAT. Every instruction has a moment it produces its result and a moment a follower needs it. We must locate both on the clock.
- A normal ALU instruction (like
add) produces its answer during EX. - A load (
lw) does not compute — it reads memory, so it produces its value during MEM. - Any instruction that reads registers to feed the ALU needs those values at the start of EX.
WHY does the moment matter? Because we are about to ask: can we hand the value over in time? A hand-off in time only works if produced ≤ needed. If the value is born after it is needed, no clever wiring saves us.
PICTURE. Two vertical event-markers: a green "PRODUCED" flag and a red "NEEDED" flag, placed on the stages where each event happens for a load and its follower.

Step 3b — The actual forwarding wires (so nothing is hand-waved)
WHAT. "Forwarding" is not one magic wire; it is a small, fixed set of named bypass paths. Each path starts at a pipeline register (a latch named for the two stages it sits between, e.g. EX/MEM holds a result after EX and before MEM) and ends at a consumer input:
- EX/MEM → EX: last instruction's EX result, one cycle old, into this instruction's ALU. (Fixes
add→addback-to-back.) - MEM/WB → EX: a result two cycles old (from EX/MEM, or a load's memory value) into the ALU. (Fixes
add→gap→add, and — after a stall — load→add.) - MEM/WB → MEM: a value delivered into the store-data port of a later store. (Fixes load→store, Step 6.)
- MEM/WB → ID: a value routed into the register-compare inputs of an early-resolving branch sitting in ID. (Needed only for the branch case in Step 7; drawn there.)
WHY name them all? Because the entire load-use argument is "which of these wires can reach in time, and which cannot." The impossible path in Step 4 is precisely a MEM/WB → EX in the same cycle the memory read is happening — that path physically does not exist because the value is not in the MEM/WB latch yet.
PICTURE. A stage strip IF·ID·EX·MEM·WB with the bypass arrows drawn and labelled by source latch and destination input.

Step 4 — The collision: load's value is born one cycle too late
WHAT. Take the classic pair and overlay the produce/need flags on the real cycle numbers:
lw $2, 20($1) # value of dest reg produced in MEM
add $4, $2, $3 # value of that reg needed at start of EXFrom Step 2: the load's MEM is cycle 4; the add's EX is cycle 4.
- The load's
$2is not ready until the end of cycle 4 (memory read finishes then). - The
addwants$2at the start of cycle 4 (its ALU fires then).
WHY forwarding cannot rescue this. A forwarding wire is spatial: it moves a value sideways between stages, always forward in clock time (into this cycle or a later one). Here the need happens at the start of cycle 4 and the value appears at the end of cycle 4 — later within the very same cycle. To satisfy it you would need a MEM/WB → EX wire firing before the MEM/WB latch has been loaded, i.e. a value flowing backward in time inside one cycle — physically impossible. Contrast the ALU-ALU case, where the producer's EX finishes at end of cycle 3 and the follower's EX needs it at start of cycle 4: there, EX/MEM → EX moves forward in time and works. Loads are special only because their birth stage (MEM) sits one stage later.
PICTURE. Red "impossible" arrow trying to point leftward (backward) in time from the end-of-cycle-4 value to the start-of-cycle-4 need. The arrow is crossed out.

Step 5 — The cure: insert exactly one bubble
WHAT. We delay the add (and everything behind it) by one cycle. Its EX slides from cycle 4 to cycle 5. Now:
- Load's
$2ready: end of cycle 4 (). addneeds$2: start of cycle 5 (). Since , ✅ the inequality holds.
The value now lives in the load's MEM/WB register and the MEM/WB → EX wire from Step 3b delivers it in cycle 5.
WHY only one bubble, and how do we implement the delay? The failure was by one instant inside one cycle, so pushing the need into the next cycle closes it exactly. The Hazard detection unit performs the delay with three simultaneous moves (see Pipeline control signals):
- Freeze the PC — don't fetch anything new (the same next instruction is re-read).
- Freeze the IF/ID register — the
addre-decodes next cycle as if for the first time. - Zero the ID/EX control signals — the instruction currently leaving ID becomes a NOP: no register write, no memory touch, no real op. That zeroed slot travelling down the pipe is the bubble we just defined.
PICTURE. The staircase from Step 2, now with a grey NOP box wedged into the add's row, pushing its EX to cycle 5. A green forwarding arrow runs from the load's MEM/WB into the add's EX.

Step 6 — The forgiving case: load → store needs no bubble
WHAT. Not every use of a loaded value collides. A store consumes its store-data register late, in MEM, not in EX:
lw $2, 0($1) # dest reg produced in MEM (cycle 4)
sw $2, 4($1) # same reg needed in MEM (cycle 5)Cycles: lw MEM = 4. sw (one cycle behind) MEM = 5.
- Produced: end of cycle 4 (). Needed: cycle 5 (, its MEM). Since , the inequality holds — the MEM/WB → MEM wire from Step 3b carries
$2across with no stall.
WHY this matters. It proves the hazard is about which stage needs the value, not about "loads are slow." Change the consumer's need-stage from EX to MEM and the whole problem evaporates.
PICTURE. Same staircase, but now the need-flag for the store sits on MEM (cycle 5), safely after the load's produced-flag (end of cycle 4). Green forwarding arrow, no bubble.

Step 6b — The scheduling escape: slip an independent instruction in
WHAT. Put any instruction that does not use $2 between the load and the use:
lw $2, 20($1) # dest reg produced in MEM (cycle 4)
and $7, $8, $9 # independent filler, does not touch $2
add $4, $2, $3 # needs $2 in EXCycles (each row starts IF one cycle after the row above): lw IF=1, so MEM=4. and IF=2. add IF=3, therefore its EX = 3 + 2 = cycle 5.
- Produced: end of cycle 4 (). Needed: start of cycle 5 (). Since , the inequality holds — MEM/WB → EX delivers the value, no bubble.
WHY it works. The filler instruction pushes the dependent add one cycle later without wasting a slot on a NOP — the real work of and fills the gap that a bubble would otherwise fill. This is exactly what Compiler instruction scheduling and out-of-order hardware do: reorder real work into the delay slot.
PICTURE. Three-row staircase; the independent and sits in the row between load and use, and the add's EX (cycle 5) is safely after the load's produced-flag (end of cycle 4).

Step 7 — The nastier edge case: load feeding a branch (two bubbles)
WHAT. A branch (like beq) compares two registers to decide where to jump. In the classic five-stage MIPS the comparison is resolved early, in ID, to keep the branch penalty small (see Branch hazards and prediction). So a branch needs its source registers at the start of ID, not EX. Now feed one of them from a load:
lw $2, 0($1) # dest reg produced in MEM (cycle 4)
beq $2, $3, L # compares $2, needs it in ID (naively cycle 3)Cycles: lw MEM = 4. beq (one cycle behind) ID = 3.
- Produced: end of cycle 4 (). Needed: start of cycle 3 (). Since the inequality fails by a wide margin — the need comes a whole cycle plus an instant earlier.
WHY two bubbles here, not one. We must slide the branch's ID from cycle 3 to a cycle whose start is after . Cycle 4's start () is still before , so that is not enough — we need cycle 5, whose start . Moving ID from cycle 3 to cycle 5 is a two-cycle delay. Only then does the MEM/WB → ID wire (the fourth path added to Step 3b) deliver $2 into the branch's comparator in time. Loads feeding an early-compare branch are the worst load-use case.
HOW the hardware inserts two bubbles. The Hazard detection unit repeats its Step-5 recipe for two consecutive cycles instead of one (see Pipeline control signals):
- Cycle A: freeze PC, freeze IF/ID, zero the ID/EX control signals → first bubble enters the pipe,
beqstays in ID. - Cycle B: detect the hazard again (the load has only reached WB, value still not committed to the register file), freeze PC and IF/ID once more, zero ID/EX again → second bubble enters,
beqstill held in ID. - Cycle C (= cycle 5): the load's value now sits in the MEM/WB latch; the MEM/WB → ID forward feeds the comparator, the branch resolves, and normal fetching resumes.
PICTURE. Load row and branch row; the branch's ID-need flag sits at cycle 3, far before the load's cycle-4 produced flag; two grey bubbles push ID to cycle 5, and a green MEM/WB → ID arrow delivers the value there.
Step 8 — Counting the cost: from one snippet to average CPI
WHAT. Turn the single bubble into a performance number. Take the three-instruction snippet lw; add; sub.
- Ideal (no hazard): instructions in a 5-stage pipe finish in cycles. Here cycles.
- With one required bubble: cycles.
WHY the ? The first instruction needs all 5 stages ( cycles), and each later instruction adds just more cycle (the diagonal from Step 2). So .
Now the average over a program. Define CPI = cycles per instruction. Each unavoidable bubble adds one stall cycle, weighted by how often it happens:
With loads = of instructions and half of them immediately used:
PICTURE. A bar chart: ideal 7 cycles vs stalled 8 cycles for the snippet, and a second bar pair for CPI 1.00 vs 1.10 — the red sliver on top is the tax the load-use hazard levies.
The one-picture summary
The final figure stacks the whole story: the load's row with its value born at the end of MEM (cycle 4, green flag); the naive add colliding at cycle-4 EX (red, impossible backward arrow); the bubble wedged in; and the fixed add at cycle-5 EX receiving the value via a legal forward-in-time green wire. One cycle lost — the price of a load-use hazard.
Recall Feynman retelling — say it to a friend
Imagine an assembly line with five stations, and a new part enters one beat after the previous one, so parts run on a staircase. A load part goes to the memory station (station 4) to pick up a value, and that value only lands in its hands at the very end of station 4. The part right behind it reaches the arithmetic station (also at beat 4) and, at the very start of that beat, holds out its hand for that value. But the value doesn't exist yet — it appears at the end of the beat, not the start. There is no wire that sends a value back in time within one beat, so the follower must wait. We freeze the front of the line for exactly one beat and slip an empty "do-nothing" slot — a bubble — into the pipe. Now the follower reaches the arithmetic station one beat later, at which point the value is already sitting in a holding latch and a normal forward wire hands it over. One wasted beat, no more, no less — unless the follower is a branch that needs the value even earlier (at decode), in which case it waits two beats; and if the follower merely stores the value (needs it late, at the memory station), it catches it with no wait at all. Multiply "how often this happens" by "cycles lost" and you get the little tax on CPI: becomes about .
Recall Quick self-test
Why can't forwarding fix a load-use hazard? ::: The value is produced at the end of the load's MEM stage (), but the dependent ALU needs it at the start of its EX stage () — the same cycle, an earlier instant. Forwarding moves data between stages but never backward in time within a cycle.
How many bubbles does a load feeding an immediate add need? ::: Exactly one — the need-instant must be pushed to , one cycle.
A load feeding another load that uses it as an address — stall or not? ::: One bubble — the second load computes its address in EX, so it needs the value at , exactly the ALU case.
How many bubbles does a load feeding an early-compare beq need? ::: Two — the branch needs its register in ID (cycle 3), so ID must be pushed to cycle 5.
Why does lw; sw $same need no stall? ::: The store consumes its data in MEM (cycle 5), which is after the load produces it (end of cycle 4), so holds.
Give the CPI formula for load-use stalls. ::: , where = fraction of instructions incurring a load-use stall.
See also: Hazard detection unit · Data hazards and forwarding · Pipeline control signals · Compiler instruction scheduling · Branch hazards and prediction · Memory hierarchy and cache