forwarding
Suppose a clerk computes a subtotal and is supposed to file it in a binder, and a moment later a second clerk needs that subtotal. The slow way: clerk one files it, clerk two walks to the binder and reads it back out. The fast way: clerk one simply hands the number straight across the desk the instant it is written. Forwarding is that hand-across-the-desk for a pipeline — routing a freshly computed result directly to the instruction that needs it, instead of making it take the long road through the register file.
Recall the data hazard: add x1, x2, x3 then sub x4, x1, x5. The add's result x1 is born at the end of its EX stage, sitting in the EX/MEM pipeline register, but it does not reach the register file until WB, two cycles later — too late for sub, which needs x1 in its own EX next cycle. Forwarding adds short wires (with multiplexers to select them) that carry the value straight from the EX/MEM register back to the ALU inputs. A small forwarding unit watches for the match — does an earlier instruction's destination register equal a later instruction's source register? — and if so, it steers the fresh value over the bypass path. The result arrives exactly when sub needs it, and not one cycle is lost.
Forwarding is the single most important trick for keeping a pipeline full, because it turns nearly every data hazard into a non-event. Producers can forward from several points — the EX/MEM register and the MEM/WB register both feed bypass paths — covering dependences one or two instructions apart. The crucial honest limit: forwarding can only deliver a value that already exists. For a load, the data is not available until after the MEM stage, so a use in the very next instruction still cannot be forwarded in time — that load-use case forces exactly one stall, the one hazard forwarding alone cannot erase.
add x1, x2, x3 (computes x1 in cycle 3's EX) then sub x4, x1, x5 (needs x1 in cycle 4's EX). Without forwarding, sub would stall until WB in cycle 5. With a wire from the EX/MEM register to the ALU input, x1 is delivered in cycle 4 exactly on time — zero stalls.
Forwarding routes a result from a pipeline register straight back to the ALU, dissolving most data hazards with no lost cycles.
Forwarding cannot conjure a value that has not been computed yet. A load's result is ready only after MEM, so a dependent instruction immediately after a load still needs one stall — the load-use hazard. Forwarding shrinks that delay but cannot fully remove it.