Introduction

A hazard is a situation in which the next instruction in a pipeline cannot execute in its planned clock cycle without giving a wrong result. The pipeline must then either wait (a stall, also called a bubble) or use extra hardware that removes the conflict. Hazards are the reason a real pipeline has a CPI above 1.

There are three kinds. A structural hazard is a conflict over hardware: two instructions need the same unit in the same cycle. A data hazard is a conflict over a value: an instruction needs a result that an earlier instruction has not yet produced. A control hazard is a conflict over the instruction stream: the pipeline does not yet know which instruction follows a branch. Beyond the ideal formula of Instruction Pipelining, the task is to count the stall cycles these hazards cause, with or without forwarding, and to turn the count into CPI, time or speedup.

Prerequisites

  • Instruction Pipelining: the five stages IF, ID, EX, MEM, WB, the space-time diagram, k+n−1k + n - 1 cycles, CPI and speedup.

Core concepts

Pipeline model used in this note

Pipeline convention used in all Gate CS Mastery notes. Unless a question says otherwise: five stages IF, ID, EX, MEM, WB, one cycle each; source registers are read in ID; an ALU result is computed in EX and a loaded value is available at the end of MEM; results are written in WB. The register file is written in the first half of a cycle and read in the second half (a split-cycle register file), so an instruction in ID can read a value written by WB in the same cycle. Separate instruction and data memories (or caches), so IF and MEM never conflict. A stalled instruction waits in ID and the instructions behind it wait too.

Counting convention. "Stall cycles" are the cycles added to the ideal count k+n−1k + n - 1. Total cycles =k+n−1+= k + n - 1 + stall cycles. CPI over a long program =1+= 1 + stall cycles per instruction.

Data dependences and data hazards

Let instruction ii come before instruction jj in program order.

DependenceConditionNameHazard in the simple 5-stage in-order pipeline?
True dependencejj reads a register that ii writesRAW (read after write)Yes: the only data hazard that stalls this pipeline
Anti-dependencejj writes a register that ii readsWAR (write after read)No: ii reads in ID long before jj writes in WB
Output dependencejj and ii write the same registerWAW (write after write)No: writes happen in order in WB

WAR and WAW are name dependences: no value flows between the instructions, and renaming the register removes them. They become hazards in pipelines where instructions can complete out of order (for example a long floating-point unit beside a short integer path), or where some instruction writes early and another reads late. RAR (read after read) is not a dependence at all.

Operand forwarding (bypassing)

A result exists inside the pipeline long before WB writes it. Forwarding adds paths and multiplexers that take the value from the pipeline registers and feed it straight to the ALU inputs.

PathFromToCovers
EX/MEM to EXALU output of the instruction one aheadALU input of the next instructionDependent instruction right after an ALU instruction
MEM/WB to EXALU result or loaded value two aheadALU inputDistance 2, and a load followed (after one stall) by its user
MEM/WB to MEMLoaded valueData-memory input of a storeLoad followed by a store of the same register (Related material)

Load-use hazard. A load produces its value only at the end of MEM. The next instruction wants it at the start of its EX, which is the same cycle. Forwarding cannot send a value backward in time, so a load followed immediately by an instruction needing its value at the start of EX costs one stall cycle even with full forwarding. Store-data use is exempt when MEM/WB-to-MEM forwarding is present; a store-address dependency still needs the EX-stage value. The hardware that detects this and inserts the bubble is the hazard detection unit; the forwarding multiplexers are controlled by the forwarding unit.

Stalls by dependence distance

Let the distance be j−ij - i: 1 for adjacent instructions, 2 if one instruction sits between them, and so on. The table gives the stall cycles for one RAW dependence on an ALU result or a load result in the pipeline above.

Producer, hardwareDistance 1Distance 2Distance 3Distance 4
ALU, full forwarding0000
Load, full forwarding1000
ALU or load, no forwarding, split-cycle register file2100
ALU or load, no forwarding, no split cycle3210

The table counts stalls for one isolated dependence. In a sequence, an earlier stall pushes later instructions back and can absorb a later dependence. Always trace the sequence instead of adding table entries blindly (Example 1 shows both effects).

Structural hazards

A structural hazard appears when the hardware cannot support every combination of instructions in flight.

  • One memory port shared by instructions and data: a load or store in MEM and a fetch in IF collide. Each load/store blocks a simultaneous instruction fetch; count only actual conflicting fetch cycles, not one unconditional extra cycle per memory instruction. Remedy: separate instruction and data caches.
  • A register file without split-cycle access: WB and ID collide in the same cycle (counted in the "no split cycle" row above).
  • A non-pipelined multicycle unit (for example a divider that takes 4 cycles in EX): a second instruction that needs the unit must wait until it is free. Remedy: pipeline the unit or duplicate it.

Control hazards

A branch decides the next PC only when its condition and target are known. Instructions fetched after the branch in the meantime may be on the wrong path.

  • Branch penalty. If the branch is resolved at the end of stage rr (counting IF as stage 1), the correct next instruction is fetched rr cycles after the branch was fetched instead of 1, so r−1r - 1 cycles are lost when the fetch went wrong. Resolved in ID: penalty 1; in EX: 2; in MEM: 3.
  • Stall on every branch (no prediction): every branch pays the full penalty.
  • Predict not taken: keep fetching sequentially; if the branch is taken, flush the wrong-path instructions (turn them into bubbles). Only taken branches pay.
  • Predict taken: needs the target early (a branch target buffer); only not-taken branches pay once the target is known.
  • Delayed branch: the instruction slots right after the branch (the delay slots, as many as the penalty) always execute. The compiler fills them with useful instructions that are independent of the branch, or with NOPs. A NOP in a slot is a wasted cycle.
  • Dynamic prediction (Related material): a 1-bit history or 2-bit saturating counter predicts from past outcomes. For 2 bits, SN=0, WN=1, WT=2, ST=3; predict taken in states 2/3. Taken increments and not-taken decrements, saturating at 3 and 0. A strong state requires two successive opposite outcomes to reverse prediction, whereas a weak state requires only one.
  • Resolving earlier: comparing registers in ID (with an extra comparator and forwarding into ID) cuts the penalty to 1, at the cost of new data hazards for the branch's own operands.

Filling a delay slot. The compiler can take the slot instruction from three places; each is legal only under its own condition.

Source of the slot instructionLegal whenSaves a cycle
From before the branchThe branch does not test a register it writes, and moving it does not break any other dependenceOn both paths
From the branch target (copied)Its result is harmless on the fall-through path (its destination is not read there before being rewritten)When the branch is taken
From the fall-through pathIts result is harmless on the taken pathWhen the branch is not taken

The first source is the best because the slot does useful work whatever the outcome; the other two help only on one outcome and need the "harmless on the other path" check.

How it works

Figure 1 compares one RAW dependence on an ALU result without and with forwarding, and the load-use case.

Data hazard without forwarding, with forwarding, and the load-use stall
Figure 1. ADD R1, R2, R3 followed by SUB R4, R1, R5: without forwarding SUB waits in ID until cycle 5 and finishes in cycle 8 (2 stalls); with forwarding the EX/MEM value reaches SUB's EX in cycle 4 (no stall); after LW R1, 0(R2) the user's EX moves to cycle 5 (1 stall).

Figure 2 shows a taken branch resolved in EX under predict not taken.

Taken branch resolved in EX with two flushed instructions
Figure 2. A taken branch fetched in cycle 1 is resolved at the end of EX in cycle 3; the two instructions fetched in cycles 2 and 3 are flushed and the target is fetched in cycle 4, a penalty of 2 cycles.

Algorithms and pseudocode

The procedure below counts the cycles of a straight-line sequence in the pipeline above, one instruction at a time. Instructions are numbered from 1; EXstart[j] is the cycle in which instruction jj starts EX.

Text
COUNT-CYCLES(I[1..n], forwarding)
  lastWriter <- empty register map (absent means NIL)
  if n = 0 then return 0
  for j <- 1 to n
    e <- EXstart[j-1] + 1 if j > 1 else 3      // in-order, one EX per cycle
    for each source register r of I[j]
      p <- lastWriter[r] if present, else NIL
      if p exists then
        if forwarding then
          if r is store-data used only in MEM then
            e <- max(e, EXstart[p] + 1)  // MEM/WB-to-MEM bypass; no immediate load-data stall
          else if I[p] is a load then e <- max(e, EXstart[p] + 2) // EX-stage consumer
          else e <- max(e, EXstart[p] + 1)                       // EX-stage consumer
        else
          e <- max(e, EXstart[p] + 3)   // read in ID during p's WB (split cycle)
    EXstart[j] <- e
    for each destination register r of I[j]
      lastWriter[r] <- j
  return EXstart[n] + 2                  // n's MEM and WB

Without split-cycle registers, replace EXstart[p]+3 by EXstart[p]+4. With a word-RAM register map supporting constant-time lookup/update, at most s≥1s\ge1 source operands and a bounded number of destinations per instruction, work is O(ns)O(ns); storage is O(n+R)O(n+R) for EXstart and writers of the RR registers encountered. An absent map entry means no previous writer, avoiding a full register-universe initialization cost. Literal backward searches instead take O(n2s)O(n^2s) worst case. Branches add their penalty to the next correct-path fetch; structural conflicts add a cycle per conflicting use.

Mathematical explanation

CPI with stalls. If a fraction fhf_h of instructions suffers hazard hh with penalty php_h cycles,

CPI=1+∑hfh ph.\text{CPI} = 1 + \sum_h f_h \, p_h.

Branches. With branch frequency bb, taken fraction tt and penalty pp:

SchemeStall cycles per instruction
Stall on every branchb pb\,p
Predict not takenb t pb\,t\,p
Predict taken (target known in time)b (1−t) pb\,(1 - t)\,p
Prediction with accuracy aab (1−a) pb\,(1 - a)\,p
Delayed branch, fraction qq of slots filled usefully, one slotb (1−q)b\,(1 - q)
Delayed branch, uu unfilled slots (NOPs) per branch on averageb ub\,u

Speedup with stalls. For balanced stages (tnp=k tpt_{np} = k\,t_p) and many instructions,

S=k1+stall cycles per instruction.S = \frac{k}{1 + \text{stall cycles per instruction}}.

With unequal stages, use S=tnp/(CPI⋅tp)S = t_{np} / (\text{CPI} \cdot t_p).

Why the table is right. With forwarding, an ALU producer that starts EX in cycle cc has its result in the EX/MEM register at the end of cc, so the consumer can start EX in c+1c + 1: no stall at distance 1. A load's value is in MEM/WB at the end of c+1c+1, so an EX-stage consumer starts EX at c+2c+2: one stall at distance 1. For store data used only in MEM, the listed MEM/WB-to-MEM bypass permits EX at c+1c+1 and MEM at c+2c+2, with no stall. Thus LW R1,0(R2); SW R1,4(R2) has EX cycles 3 and 4 and completes the five-stage timing envelope in 6 cycles (the store's WB slot does no register write). Without forwarding, the producer writes in WB in cycle c+2c + 2; with a split cycle the consumer reads in ID in that cycle and starts EX in c+3c + 3, which is 2 cycles late at distance 1. Without a split cycle it reads one cycle later still.

Worked examples

Example 1: one producer, several consumers

Text
I1: ADD R1, R2, R3
I2: SUB R4, R1, R5
I3: AND R6, R1, R7
I4: OR  R8, R1, R9
I5: XOR R10, R4, R11
  • Full forwarding. No stall. Total 5+5−1=95 + 5 - 1 = 9 cycles.
  • No forwarding, split-cycle register file. I2 needs R1 at distance 1: 2 stalls, so I2 reads R1 in cycle 5 (I1's WB) and starts EX in cycle 6. I3 and I4 now read R1 after it is written: no further stall. I5 needs R4 from I2; I2 writes R4 in cycle 8, I5 reaches ID in cycle 8: no stall. Total 9+2=119 + 2 = 11 cycles.
  • No forwarding, no split cycle. I2 waits 3 cycles (EX in cycle 7, WB in cycle 9). I5 then needs R4 one cycle after I2's WB, at cycle 10, but would have read it in cycle 9: 1 more stall. Total 9+4=139 + 4 = 13 cycles.

The I3 and I4 dependences on R1 cost nothing in every case: the stall in front of them already delayed them.

Example 2: load-use hazards and scheduling

Text
I1: LW  R1, 0(R2)
I2: ADD R3, R1, R4
I3: SW  R3, 4(R2)
I4: LW  R5, 8(R2)
I5: ADD R6, R5, R7
  • With forwarding. I1 to I2 is a load-use pair (1 stall); I2 to I3 is ALU to store (forwarded, 0); I4 to I5 is a load-use pair (1 stall). Total 9+2=119 + 2 = 11 cycles.
  • Without forwarding (split cycle). Three distance-1 RAW pairs (I1 to I2, I2 to I3, I4 to I5), 2 stalls each: total 9+6=159 + 6 = 15 cycles.
  • Reordered by the compiler as I1, I4, I2, I3, I5: R1 is used two instructions after its load, R5 two after its load, so with forwarding there is no stall and the sequence takes 9 cycles. Without forwarding this order still loses 3 cycles (12 in total): I2 is at distance 2 from its load (1 stall) and I3 at distance 1 from I2 (2 stalls), while I5 is far enough from I4.

Example 3: a multicycle execute stage

MUL R1, R2, R3 spends 3 cycles in EX; ADD R4, R1, R5 and SUB R6, R7, R8 spend 1. With forwarding, MUL occupies EX in cycles 3, 4 and 5, so ADD starts EX in cycle 6 (2 stalls) and SUB in cycle 7. The three instructions finish in cycle 9 instead of 7. Even an independent instruction behind ADD is delayed, because EX is busy and the pipeline is in order.

Example 4: branch schemes compared

20% of instructions are branches and 65% of them are taken.

SchemePenaltyCPI
Stall every branch, resolved in EX21+0.20×2=1.401 + 0.20 \times 2 = 1.40
Predict not taken, resolved in EX21+0.20×0.65×2=1.261 + 0.20 \times 0.65 \times 2 = 1.26
Predict not taken, resolved in ID11+0.20×0.65×1=1.131 + 0.20 \times 0.65 \times 1 = 1.13
Delayed branch, resolved in ID, 70% of slots filled1 slot1+0.20×0.30=1.061 + 0.20 \times 0.30 = 1.06

With balanced stages and k=5k = 5, the speedups over the non-pipelined processor are 5/1.40≈3.575/1.40 \approx 3.57, 5/1.26≈3.975/1.26 \approx 3.97, 5/1.13≈4.425/1.13 \approx 4.42 and 5/1.06≈4.725/1.06 \approx 4.72.

Example 5: a single memory port

With one memory shared by IF and MEM, each load/store blocks a simultaneous fetch, if one is actually requested. For LW followed by four independent ALU instructions, LW is in MEM in cycle 4, so the fourth instruction's fetch moves from cycle 4 to cycle 5 and the five instructions take 10 cycles instead of 9. For a long otherwise-unstalled stream, CPI is approximately 1 plus the load/store fraction: 35% gives 1.35. Trace finite sequences and overlapping stalls explicitly.

Example 6: classifying dependences

Text
I1: ADD R1, R2, R3
I2: SUB R4, R1, R5
I3: MUL R1, R4, R6
I4: ADD R5, R1, R4

Take every ordered pair i<ji < j; for a read, the producer is the latest earlier instruction that writes that register.

  • RAW (4): I1 to I2 on R1, I2 to I3 on R4, I2 to I4 on R4, I3 to I4 on R1. I1 to I4 is not a RAW pair: I3 rewrites R1 in between, so I4 reads I3's value.
  • WAR (2): I2 reads R1 and I3 later writes it; I2 reads R5 and I4 later writes it.
  • WAW (1): I1 and I3 both write R1.

Timing in the standard pipeline: with full forwarding all three distance-1 RAW pairs are ALU to ALU, so there is no stall and the sequence takes 5+4−1=85 + 4 - 1 = 8 cycles. Without forwarding (split-cycle register file), I2, I3 and I4 each wait 2 cycles for the instruction just ahead: 6 stalls, 14 cycles. The I2 to I4 pair on R4 costs nothing, because I4 is already behind I3. The WAR and WAW pairs cost nothing in either case.

Example 7: when WAR and WAW become hazards

Suppose a divide unit spends 6 cycles in EX beside a 1-cycle integer ALU, and the pipeline lets a short instruction finish before a long one ahead of it (out-of-order completion).

Text
I1: DIV R1, R2, R3      IF 1, ID 2, EX 3 to 8, MEM 9, WB 10
I2: ADD R1, R4, R5      IF 2, ID 3, EX 4,      MEM 5, WB 6

I2 writes R1 in cycle 6 and I1 overwrites it in cycle 10, so after both have finished R1 holds the DIV result although ADD comes later in program order: a WAW hazard. The hardware must hold I2's write until after I1's (or rename R1). A WAR hazard needs the reverse situation, a later instruction writing a register before an earlier one has read it; that can happen only when operand reads are delayed (for example, an instruction waiting for a busy unit reads its registers when it finally starts). In the standard in-order pipeline neither situation arises, which is why only RAW stalls it.

Important properties and observations

  • Only RAW stalls an in-order five-stage pipeline. WAR and WAW need out-of-order completion or unusual write timing to matter.
  • Forwarding removes ALU-to-ALU stalls, not the load-use stall. One bubble remains when the following instruction needs the loaded value at the start of EX (including a store address, but not store data with MEM/WB-to-MEM forwarding); scheduling an independent instruction between them hides it.
  • A stall delays everything behind it. Later dependences may be absorbed; never add per-pair stall counts without tracing.
  • The split-cycle register file saves one cycle on every non-forwarded dependence.
  • Branch penalty == resolution stage −1- 1 (IF counted as stage 1). Deeper pipelines resolve later and pay more.
  • Predict not taken costs nothing on not-taken branches. Its stall cycles per instruction are b t pb\,t\,p.
  • Delay slots are always executed. An instruction placed there must be correct whether or not the branch is taken.
  • Common misconceptions.
    • "Forwarding eliminates all data hazards." The load-use hazard still costs one cycle.
    • "WAR is a hazard in every pipeline." Not in the simple in-order pipeline, where reads are early and writes late.
    • "Stall cycles equal the number of dependent pairs times the penalty." Overlapping stalls make the real total smaller.

GATE examination perspective

  • STATE THE MODEL FIRST. Forwarding or not, split-cycle register file or not, where branches resolve, which memory organisation. The same sequence gives different counts under each.
  • STALL COUNTING. Trace the sequence cycle by cycle (or use the distance table plus tracing), then total =k+n−1+= k + n - 1 + stalls.
  • LOAD-USE. For EX-stage consumers (including a store address), one stall with forwarding at distance 1, none at distance 2 or more. Store data needed only in MEM has no immediate load-data stall with the listed MEM/WB-to-MEM bypass.
  • WITHOUT FORWARDING. 2 stalls at distance 1 and 1 at distance 2 with a split cycle; 3 and 2 (and 1 at distance 3) without.
  • DEPENDENCE CLASSIFICATION. Questions list pairs and ask which are RAW, WAR, WAW. Check which register is written and which is read in each instruction; the destination is usually the first operand, but read the notation.
  • LATEST WRITER. A read depends only on the latest earlier write of that register; an intervening write cuts the older RAW pair (Example 6).
  • WAR AND WAW TIMING. They never stall the standard in-order pipeline; they matter only when instructions can complete out of order or read operands late (Example 7).
  • BRANCH PENALTY AND CPI. Weight the penalty by branch frequency and, under prediction, by the misprediction fraction.
  • UNEQUAL EX TIMES. A multicycle unit delays the dependent instruction and, in an in-order pipeline, everything behind it.
  • DELAY SLOT FILLING. Choose an instruction that the branch does not depend on and whose result is needed on both paths (or harmless on both).

Summary

Sources

  1. C. Hamacher, Z. Vranesic, S. Zaky, Computer Organization, 5th ed., McGraw-Hill, 2002: Chapter 8, Sections 8.2 (Data Hazards, including 8.2.1 Operand Forwarding and 8.2.2 Handling Data Hazards in Software) and 8.3 (Instruction Hazards, including 8.3.2 Conditional Branches and Branch Prediction).
  2. D. A. Patterson, J. L. Hennessy, Computer Organization and Design: The Hardware/Software Interface, 5th ed. (MIPS edition), Morgan Kaufmann, 2013: Sections 4.5 (An Overview of Pipelining), 4.7 (Data Hazards: Forwarding versus Stalling) and 4.8 (Control Hazards).
  3. W. Stallings, Computer Organization and Architecture, 10th ed., Pearson: Section 14.4 (Instruction Pipelining).

Next steps