Data Hazards in Pipelines: Forwarding Versus Stalling

Overlapping instruction execution creates a serious problem when one instruction needs a result that a previous instruction has not finished computing yet. This article explains what data hazards are, how forwarding solves most of them without losing any performance, and why some situations still require the pipeline to stall.

Data HazardsForwardingPipeline Stalling

~3 دقیقه مطالعه · آخرین به‌روزرسانی ۱۵ شهریور ۱۴۰۵

What a Data Hazard Is

In a pipelined processor, several instructions are in progress simultaneously. A Data Hazard occurs when an instruction needs to use a value that a preceding instruction, still moving through the pipeline, has not yet finished computing and written back to the register file.

Consider this sequence of instructions:

add a, b, c
sub d, a, e

The second instruction needs the value of a, but the first instruction has not yet reached its write-back stage by the time the second instruction reaches decode. Without any correction, the second instruction would read a stale, outdated value of a from the register file.

The First Solution: Forwarding

Forwarding (also called Bypassing) solves this without losing any clock cycles, by adding extra wiring that routes a result directly from where it is computed to where it is needed, skipping the normal path through the register file entirely.

Without forwarding:
add computes result → written to register file (cycle 5)
sub needs result → read from register file (cycle 3) — too early, wrong value

With forwarding:
add computes result in EX stage (cycle 3)
result is forwarded directly into sub's EX stage (cycle 4)

Because the result the second instruction needs is available right after the first instruction's execute stage, extra hardware paths can feed that value forward in time to reach the second instruction exactly when it needs it, avoiding any wasted cycles.

When Forwarding Alone Is Not Enough

Forwarding solves most data hazards, but not all of them. A Load-Use Hazard occurs specifically when an instruction immediately following a load needs the value that load is retrieving:

ld a, 0(b)
add d, a, e

The loaded value is not available until the end of the memory access stage, which happens later than the point where the following instruction's execute stage needs it, even with forwarding wiring in place. In this specific case, forwarding cannot deliver the value in time.

The Second Solution: Stalling

When forwarding cannot resolve a hazard in time, the pipeline must insert a Stall (also called a Bubble): the dependent instruction, and everything behind it, is held in place for one clock cycle while the needed value becomes available, at the cost of one cycle of lost throughput.

ld a, 0(b)      : IF ID EX MEM WB
[bubble inserted]
add d, a, e     : IF ID  --  EX MEM WB

This deliberately wastes one cycle rather than producing an incorrect result, which is always the correct tradeoff, since accuracy cannot be sacrificed for speed.

Why This Distinction Matters for Compiler Design

Because load-use stalls specifically cost a cycle, compilers that understand this hazard can sometimes reorder independent instructions to be placed immediately after a load, filling what would otherwise be a wasted stall cycle with useful work instead — a technique called Instruction Scheduling, which relies directly on understanding this hazard's exact cause.

نوشته و پژوهش‌شده توسط دکتر شاهین صیامی

مقالات مرتبط

Common Misconceptions About Parallel Computing and the Book's Final Lessons

After covering everything from thread-level parallelism to warehouse-scale computing, it is worth correcting persistent misconceptions about parallel systems that even experienced engineers sometimes hold. This article addresses common fallacies about scaling and parallel hardware, then closes out the parallel processing chapter by tying together the full journey from a single instruction to a building full of cooperating machines.

ادامه

Real Stuff: Benchmarking CPUs Against GPUs and Multiprocessor Matrix Multiply

Comparing a CPU and a GPU fairly requires a model that accounts for both computational throughput and memory bandwidth limits together. This article introduces the roofline model used to compare real hardware like the Intel Core i7 and NVIDIA Tesla GPU, then shows how matrix multiplication is accelerated across multiple processors as the final practical application of this chapter's parallel concepts.

ادامه

Benchmarking Multiprocessors and Modeling Parallel Performance

Measuring the performance of a parallel system requires different tools and metrics than measuring a single-core processor. This article covers the specialized benchmarks used to evaluate multiprocessor systems, explains how to model scaling behavior as more processors are added, and revisits Amdahl's Law in the context of real-world performance measurement.

ادامه

Cluster Networking: Connecting to the World Outside

A cluster of machines is only useful if it can communicate efficiently both internally and with the outside world. This article covers the networking layers involved in cluster communication, the tradeoffs between latency and bandwidth at scale, and how clusters connect to external networks and users.

ادامه

Clusters, Warehouse-Scale Computers, and Network Topologies

Beyond a single chip, parallelism extends to entire buildings full of independent computers working together. This article explains the shift from shared memory multiprocessing to clusters of separate machines, introduces the concept of warehouse-scale computing, and covers the network topologies that connect these independent machines efficiently.

ادامه

An Introduction to GPUs: Massive Parallelism for Data-Heavy Workloads

A GPU takes the SIMD idea covered earlier in this series to an extreme scale, running thousands of lightweight threads simultaneously to process massive amounts of independent data. This article explains why GPUs are architecturally so different from CPUs, how their thread execution model works, and what kinds of workloads benefit most from this design.

ادامه