How Do Read-After-Write Data Hazards Arise in Computing?

Read-after-write data hazards occur in pipelined processors when a subsequent instruction attempts to read a register or memory location before a preceding instruction has finished writing its result. Because modern CPUs overlap the execution of multiple sequential instructions to improve throughput, an instruction that depends on an earlier calculation can reach its read stage while the required value is still in flight. Without hardware or compiler intervention, the dependent instruction would read stale data and produce an incorrect result.

Instruction Pipelining and Overlapping Execution

In a non-pipelined processor, each instruction completes all of its steps—fetching, decoding, executing, accessing memory, and writing back—before the next instruction begins. While simple, this sequential approach leaves most of the processor's functional units idle during any given clock cycle.

Pipelining divides instruction execution into discrete stages, such as the classic five-stage RISC pipeline:

  1. IF (Instruction Fetch): Retrieve the instruction from memory.
  2. ID (Instruction Decode): Decode the opcode and read source registers.
  3. EX (Execute): Perform the arithmetic or logic operation.
  4. MEM (Memory Access): Read from or write to data memory.
  5. WB (Write Back): Write the final result back to the register file.

When pipelined, a new instruction enters the IF stage on every clock cycle. Consequently, up to five instructions can be in different stages of execution simultaneously.

How a Read-After-Write Hazard Occurs

A read-after-write (RAW) hazard, also known as a true data dependency, happens when instruction \(I_2\) needs a value produced by an earlier instruction \(I_1\). Consider the following two sequential assembly instructions:

ADD R1, R2, R3   ; I1: R1 = R2 + R3
SUB R4, R1, R5   ; I2: R4 = R1 - R5

In this sequence, \(I_1\) writes to register R1, and \(I_2\) reads from R1. In a five-stage pipeline:

  • At cycle 1, \(I_1\) is in IF.
  • At cycle 2, \(I_1\) is in ID, and \(I_2\) enters IF.
  • At cycle 3, \(I_1\) is in EX (computing \(R2 + R3\)), while \(I_2\) is in ID (reading R1 and R5).
  • At cycle 4, \(I_1\) is in MEM, and \(I_2\) is in EX.
  • At cycle 5, \(I_1\) finally reaches WB and writes the new value into R1.

Because \(I_2\) reads R1 during cycle 3—two cycles before \(I_1\) writes the updated value in cycle 5—\(I_2\) receives the old, stale value of R1.

Calculating the Hazard Window

If \(t_{\text{write}}(I_1)\) is the clock cycle in which \(I_1\) updates the architectural state and \(t_{\text{read}}(I_2)\) is the cycle in which \(I_2\) reads its operands, a RAW hazard arises whenever:

\[t_{\text{read}}(I_2) < t_{\text{write}}(I_1)\]

The severity of the hazard depends on the distance between the two instructions and the depth of the pipeline. Deeper pipelines, which split execution into more stages to achieve higher clock frequencies, widen the gap between the decode/read stage and the write-back stage, increasing the likelihood of RAW hazards.

Hardware and Software Mitigations

Processors and compilers use several techniques to resolve RAW hazards without sacrificing correctness:

  • Data Forwarding (Bypassing): Dedicated hardware paths route the result directly from the output of the EX or MEM stage of \(I_1\) to the input of the EX stage of \(I_2\), eliminating the need to wait for the WB stage.
  • Pipeline Stalling (Bubbles): When forwarding cannot resolve the dependency—such as when \(I_1\) is a memory load instruction whose data is only available after the MEM stage—the control unit inserts no-operation (NOP) cycles to delay \(I_2\) until the data is ready.
  • Instruction Scheduling: Compilers reorder independent instructions between \(I_1\) and \(I_2\) so that the dependent instruction arrives at its read stage only after \(I_1\) has completed its write.
  • Out-of-Order Execution: Advanced superscalar processors dynamically track dependencies using reservation stations and register renaming, allowing independent instructions to execute ahead of stalled dependent ones.