5 lessons

Branches & Speculation

A CPU cannot afford to wait to find out where a branch goes, so it guesses. What that buys, what a misprediction costs, and why unpredictable data hurts more than extra work.

SourceCompilerInstructionsFront EndExecutionRegistersCachesMemoryI/OBehavior
Control Hazards: The CPU Does Not Know Where You Are Going

A pipelined CPU must fetch an instruction every cycle, but at a conditional branch it does not yet know which instruction comes next. Waiting for the answer is unaffordable on a deep pipeline, which is why every high-performance CPU guesses instead.

Q · Why is a conditional branch a problem for a pipelined CPU, and why can it not simply wait for the condition?
Branch Prediction: Guessing Well Enough to Matter
▶ lab

The CPU has to supply a fetch address before it knows the branch outcome, so it predicts one from history. Modern predictors are accurate enough that well-behaved code pays essentially nothing for its branches — which is exactly why the badly-behaved cases stand out so sharply.

Q · How does a CPU guess which way a branch will go, and what makes some branches predictable and others not?
Misprediction: What a Wrong Guess Costs

When the predictor is wrong, everything fetched and executed down the wrong path is discarded and the pipeline refills from the correct address. The cost is not the discarded work — it is the emptiness afterwards, and it scales with how deep the pipeline is.

Q · What exactly happens when a branch prediction turns out to be wrong, and why does it cost what it costs?
Speculative Execution: Doing Work Before You Know You Need It

Modern CPUs execute instructions they may have to discard, on the bet that the guess was right. It works because the guess usually is, and because discarded results never become architecturally visible. What they do leave behind — microarchitectural traces — turned out to matter enormously.

Q · Why does a CPU execute instructions it might have to throw away, and what does that work leave behind when it is discarded?
Branchless Code: A Trade, Not an Upgrade

Replacing an unpredictable branch with arithmetic converts a variable cost into a fixed one. That is a win when the branch mispredicts often and the work it guards is trivial — and a loss in every other case, which is most of them.

Q · When is it actually worth replacing a branch with arithmetic, and when does doing so make things worse?