Instruction
SETcc
Writes 1 or 0 to a byte depending on a condition on the flags; APX adds a form that also clears the rest of the destination register.
- Extensions
- Mnemonics
- SETO, SETNO, SETB, SETC, SETNAE, SETNB, SETNC, SETAE, SETZ, SETE, SETNZ, SETNE, SETBE, SETNA, SETNBE, SETA, SETS, SETNS, SETP, SETPE, SETNP, SETPO, SETL, SETNGE, SETNL, SETGE, SETLE, SETNG, SETNLE, SETG
- Forms
- 6 (2 Legacy, 4 EVEX)
- Data
- Intel XED v2026.08.23
SETcc writes 1 to a byte register or a byte of memory when a condition
on the flags holds, and 0 when it does not, which turns a comparison
into a value. GCC 14 and Clang 23 at -O2 compile return a < b; on two
ints to xor eax, eax, cmp edi, esi and setl al. The condition
codes are those of Jcc and CMOVcc, and
the CMP page shows which to use for signed and unsigned
comparisons.
Why the XOR comes first
SETcc writes only its byte and leaves the rest of the register alone,
while the int result needs zeros above it. Clearing EAX beforehand
makes the SETcc complete it, and the old contents no longer matter. The
XOR has to precede the CMP, since it changes the flags itself. Where
no register can be cleared in advance, a MOVZX follows instead: GCC
compiles memcmp(a, b, 16) == 0 to two XORs of quadwords, an OR,
sete al and movzx eax, al. For a function that returns bool,
both compilers leave out the XOR and set only AL.
Other uses
- Overflow.
__builtin_add_overflowon twolongs becomes an ADD, a store of the sum andseto al. - Counting. GCC’s loop that counts the elements equal to k runs
xor ecx, ecx, the CMP,sete cland an ADD to the total each round, with no branch but the loop’s own. - Choosing a constant.
a < b ? 7 : 3becomessetl alandlea eax, [4*rax + 3]. Intel’s optimization manual recommends SETcc and CMOVcc only for branches that are hard to predict (Section 3.4.1.1, Coding Rule 2). - Floating point. UCOMISD sets ZF, PF and CF, all
three when a NaN makes the operands unordered, so
a == bondoubles has to look at PF as well: GCC emitssetnp aland a CMOVNE that clears the result unless ZF is set. Clang uses CMPSD instead.
APX
APX adds SETcc.ZU, an EVEX form that writes 0 or 1 to all 64 bits of its register, so that no XOR has to come first; with a memory operand it still writes one byte. The legacy form stays a byte write.
In the optimization guide
What the optimization guide says about SETcc, a line per claim. Each links to the claim in the guide, with its sources and where they differ.
Out of order
- Partial register and flag writes:
setccwrites a single byte, so making a 32-bit 0 or 1 of a condition takes either amovzxafter it or a zeroing idiom before.
Branches
- CMOV and branchless code: CMOVcc and SETcc replace a branch with a data dependence: nothing can be mispredicted, but the result waits for the condition and for both inputs, and the core can no longer run ahead on a guessed path.
- CMOV and branchless code: Without CMOV a choice between two constants can be made from the flags with arithmetic:
setccgives 0 or 1, subtracting 1 turns it into a mask of all ones or zeros, and anandwith the difference of the constants and anaddof one of them gives the result.
Forms
| Instruction | Encoding | Requires |
|---|---|---|
SETcc m8
SETcc_MEMb | 0F 90+cc /r | Base instruction set |
SETcc r8
SETcc_GPR8 | 0F 90+cc /r | Base instruction set |
SETcc r8
SETcc_GPR8i8_APX_N3 | EVEX.LLZ.F2.MAP4.WIG 40+cc /r | APX_F + APX_NCI_NDD_NF |
SETcc m8
SETcc_MEMi8_APX_N3 | EVEX.LLZ.F2.MAP4.WIG 40+cc /r | APX_F + APX_NCI_NDD_NF |
SETcc r8 ZU
SETcc_GPR8i8_APX_N3_ZU | EVEX.LLZ.F2.MAP4.WIG 40+cc /r ND=1 | APX_F + APX_NCI_NDD_NF |
SETcc m8 ZU
SETcc_MEMi8_APX_N3_ZU | EVEX.LLZ.F2.MAP4.WIG 40+cc /r ND=1 | APX_F + APX_NCI_NDD_NF |
Latency and throughput
| Model | m8 | m8SETBE, SETNBE | r8 | r8SETBE, SETNBE |
|---|---|---|---|---|
| Sandy Bridge | 2 / 1p05 | 3 / 1p05 | 1 / 0.5p05 | 2 / 1p05 |
| Haswell, Broadwell | 2 / 1p06 | 3 / 1p0156 | 1 / 0.5p06 | 2 / 0.5p0156 |
| Skylake, Skylake-SP | 2 / 1p06 | 3 / 1p06 | 1 / 0.5p06 | 2 / 1p06 |
| Ice Lake | 2 / 0.5p06 | 3 / 1p06 | 1 / 0.5p06 | 2 / 1p06 |
| Alder Lake, Sapphire Rapids | 13 / 1p06 | 13 / 1p06 | 2 / 1p06 | 2 / 1p06 |
| Lunar Lake | 13 / 0.67p135 | 13 / 0.67p135 | 2 / 0.67p135 | 2 / 0.67p135 |
| Bonnell | 2 / 1p1 | 2 / 1p1 | 1 / 0.5p01 | 1 / 0.5p01 |
| Silvermont | 1 / 1IEC0 IEC1 MEC | 1 / 1IEC0 IEC1 MEC | 1 / 0.5IEC0 IEC1 | 1 / 0.5IEC0 IEC1 |
| Piledriver | 1 / 1EX0 EX1 | 1 / 1EX0 EX1 | 1 / 0.5EX0 EX1 | 1 / 0.5EX0 EX1 |
| Zen | 1 / 0.5ALU0 ALU1 ALU2 ALU3 | 1 / 0.5ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Zen 2 | 1 / 0.33ALU0 ALU1 ALU2 ALU3 | 1 / 0.33ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Zen 3, Zen 4 | 2 / 1ALU0 ALU3 | 2 / 1ALU0 ALU3 | 1 / 1ALU0 ALU3 | 1 / 1ALU0 ALU3 |
| Jaguar | 1 / 1ALU0 ALU1 | 1 / 1ALU0 ALU1 | 1 / 0.5ALU0 ALU1 | 1 / 0.5ALU0 ALU1 |
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
dest.write(cond(CC)) # 1 or 0, one byte: a register keeps its
# other bits
Run on AMD Zen 5 (EPYC 9645): 48 cases. The APX forms were not run: none of these processors has APX.
dest.write(cond(CC)) # SETcc.zu: a register is written whole,
# bits 63:8 cleared; memory is one byte
# all the same
Not run on a processor: none of these processors has APX.
Operands
| Operand | Kind | Action |
|---|---|---|
SETcc r/m8 | ||
r/m8 | explicit | write |
RFLAGS | implicit | read |
Flags
| When | OF | SF | ZF | PF | CF |
|---|---|---|---|---|---|
| All forms | |||||
| SETO | T | ||||
| SETNO | T | ||||
| SETB | T | ||||
| SETNB | T | ||||
| SETZ | T | ||||
| SETNZ | T | ||||
| SETBE | T | T | |||
| SETNBE | T | T | |||
| SETS | T | ||||
| SETNS | T | ||||
| SETP | T | ||||
| SETNP | T | ||||
| SETL | T | T | |||
| SETNL | T | T | |||
| SETLE | T | T | T | ||
| SETNLE | T | T | T | ||
Exceptions
The exception class is XED's name for the set of exception conditions that a form follows. How to read.
- Legacy forms
- none in XED
- EVEX forms
APX-EVEX-INT
CPUID and processors
Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.
| ISA set | CPUID | Processors |
|---|---|---|
I386 | No CPUID bit: part of the base instruction set. | Every x86-64 processor in XED’s model and Zen 3 to Zen 6 |
APX_F_N3 | APX_F + APX_NCI_NDD_NF | Nova Lake, Diamond Rapids |
More General-purpose instructions
- NEG
- NOP
- NOT
- OR
- OUT
- OUTS
- PAUSE
- POP
- POPA
- POPF
- PUSH
- PUSHA
- PUSHF
- RCL
- RCR
- RET
- ROL
- ROR
- SALC
- SAR
- SBB
- SCAS
- SHL
- SHLD
- SHR
- SHRD
- STC
- STD
- STI
- STOS
- SUB
- TEST
- UD0
- UD1
- UD2
- UDB
- XADD
- XCHG
- XLAT
- XOR
All 109 General-purpose instructions
More APX instructions
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model. - The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s
-marchfeature sets and AMD’s Processor Programming References, which the page of each processor cites. - LLVM 23.1.2's x86 scheduling models (commit
85ac56026243): the latency, reciprocal throughput and ports of each form, as llvm-mca reports them. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2B, page 4-623 (SETcc)
- Intel Advanced Performance Extensions (Intel APX) Architecture Specification, revision 9.0 (355828-009, August 2026)
- AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions (24594, rev. 3.39, October 2026)
- Intel 64 and IA-32 Architectures Optimization Reference Manual, Volume 1 (248966-051, October 2026)
The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The timings come from LLVM's scheduling models, part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.