# Conditional move (cmov / csel)

A conditional move writes one of two source values into a destination depending
on a condition flag, without branching. x86 calls it `cmov`; AArch64 calls it
`csel` (conditional select). Instead of jumping over a store, the CPU computes
both candidate inputs, then the instruction commits the one the flag selects.
Control flow stays straight — there is exactly one path through the loop.

## The tradeoff

A conditional move is not free speed. It trades a possible pipeline flush for
guaranteed work. A predicted-correct branch is nearly free: the CPU speculates
past it and the speculation holds. A conditional move always does the same work
regardless of the flag, so it never mispredicts, but it also never gets the
"skip the other side" discount a well-predicted branch gives.

So the rule is about predictability:

- If the branch is easy to predict (nearly always taken, or nearly always not),
  a branch is faster — the predictor is right almost every time and the branch
  costs almost nothing.
- If the branch is a coin flip, a conditional move is faster — a real branch
  would mispredict roughly half the time, and each miss flushes the pipeline and
  re-fetches instructions.

Quicksort partitioning on random data is close to the worst case for a branch
predictor: about half the elements fall each side of the pivot with no pattern.
That is exactly where the branchless form pays off. See
[[compiler-codegen-luck]] for a case where the same partition loop ran 6x faster
once Clang emitted `csel` instead of a branch.

## Who decides

The compiler picks between a branch and a conditional move at compile time,
before it knows the data distribution, so it is guessing. The choice is also
brittle: on LLVM it comes out of the `SimplifyCFG` pass matching a specific IR
shape, and small, semantically irrelevant differences in how the source is
written can flip the decision. GCC and Clang often disagree on the same code.

Where you know the branch is genuinely unpredictable, you can nudge the
compiler. Clang has `__builtin_unpredictable()` to mark a condition as a coin
flip. A ternary (`p = cond ? a : b`) frequently lowers to a conditional move but
is not guaranteed to. When it matters, the reliable check is to read the
generated assembly rather than trust the source shape. The deeper reason this is
hard: whether a conditional move helps depends on runtime data the source cannot
express, so no amount of source-level cleverness settles it on its own.

Conditional select is one entry in a much larger catalog of branchless integer
tricks — saturating arithmetic, sign extraction, min/max without a compare-jump,
division by a constant. Warren's [[hackers-delight]] is where those live, and
reading it is the fastest way to recognize the shapes a compiler is reaching for
when it emits something unexpected.
