When should the compiler NOT use conditional moves?
Whenever evaluating both branches would be wasteful, unsafe, or have side effects — because cmov always computes both results before selecting one.
The whole speed trick of cmov is that it skips branching by computing both values. That backfires in three situations:
1. Expensive computations — both run even though only one is kept:
val = Test(x) ? Hard1(x) : Hard2(x); // both Hard1 and Hard2 evaluated
2. Unsafe computations — a path that would normally never execute now does:
val = p ? *p : 0; // *p dereferences even when p is NULL → crash
3. Side effects — both updates happen, corrupting state:
val = x > 0 ? (x *= 7) : (x += 3); // both assignments execute
The rule: cmov is only safe when both candidate computations are cheap, side-effect-free, and cannot fault. The compiler weighs this with heuristics (and sometimes profiling) when deciding between cmov and a real branch — which is why you see both in optimized code.
Go deeper:
Predication (Wikipedia) — predication trade-offs when both paths must execute.
Felix Cloutier — CMOVcc — shows cmov continues unconditionally — both candidates computed.