How do the setX, jX, and cmovX instruction families relate to one another?
They all read the same condition flags but act on them differently: setX writes a 0/1 byte, jX jumps, and cmovX conditionally copies a register.
* cmp/test set the condition flags; setX, jX and cmovX all consume the same flags using identical condition suffixes. *
After a cmp or test leaves its verdict in the flags, you have three ways to consume it — and they share the same condition suffixes (e, ne, l, ge, a, b, …):
| Family | Example | What it does |
|---|---|---|
setX |
setl %al |
Sets a single byte to 1 if the condition holds, else 0 (other bytes untouched) |
jX |
jl .L2 |
Branches to a label if the condition holds |
cmovX |
cmovl %rcx, %rax |
Copies source→dest only if the condition holds, with no branch |
cmp %rsi, %rdi
setl %al # al = (rdi < rsi) ? 1 : 0 -> implements a boolean result
Why cmov matters: It computes a conditional result without a jump, so there's no branch for the CPU to mispredict. Compilers use it for cheap ?: ternaries and small ifs — turning a branch into straight-line code. That's the assembly-level realization of the C ternary operator.
Go deeper:
SETcc — x86 set-byte-on-condition reference — SETcc — write a 0/1 byte from the flags.
CMOVcc — x86 conditional-move reference — CMOVcc — branchless conditional move.
Predication / branchless execution (Wikipedia) — cmov as branchless predication, and why it dodges misprediction.