Instruction
CMPXCHG16B
Compares RDX:RAX with 16 aligned bytes of memory: if equal, stores RCX:RBX there and sets ZF, else loads them into RDX:RAX; atomic with LOCK.
- Extensions
- Forms
- 2 (2 Legacy)
- Data
- Intel XED v2026.08.23
CMPXCHG16B is CMPXCHG8B with REX.W: it compares RDX:RAX with 16 bytes of memory and, if they match, stores RCX:RBX there, reporting the outcome in ZF. It is the double-width compare-and-swap of 64-bit code, for two words that must change together: a pointer and a version counter against the ABA problem in a lock-free stack, or the head and tail of a queue. Like CMPXCHG, it writes the memory back when the values differ, so the page must be writable either way.
The alignment rule
The operand must be aligned to 16 bytes, or the instruction raises
#GP(0), with or without LOCK; Zen 5 recorded both. CMPXCHG8B has no
such rule. A structure of two pointers is aligned to only 8 bytes
unless declared otherwise, for example with alignas(16).
Not in the baseline
AMD’s manual calls support for it implementation dependent. It has
its own CPUID bit, leaf 1, ECX bit 13 (cx16 in Linux), and belongs
to x86-64-v2 rather than the baseline. Without the
bit, AMD’s manual raises #UD, while Intel’s lists #GP(0) for 64-bit
mode.
From C
GCC 14 and Clang 23 at -O2 emit it only with -mcx16 or a -march
that includes it; otherwise both call libatomic’s
__atomic_compare_exchange_16. With -mcx16:
- Clang inlines LOCK CMPXCHG16B for
__atomic_compare_exchange_nand C11’satomic_compare_exchange_strongon 16-byte types, and pushes RBX, which is callee-saved, around it. - GCC inlines it only for the old
__sync_val_compare_and_swap; its__atomicand C11 forms still call libatomic. - Clang even makes a 16-byte atomic load out of it: zeros in all four
registers, then LOCK CMPXCHG16B, which either stores 0 over 0 or
fails and returns the value. That load is a write, so it faults on
read-only memory. With AVX (
-march=x86-64-v3), Clang loads with VMOVDQA instead: Intel’s and AMD’s manuals both make aligned 16-byte loads and stores atomic on processors that report AVX (Intel’s Volume 3A, Section 11.1.1; AMD’s Volume 2, Section 7.3.2).
Forms
| Instruction | Encoding | Requires |
|---|---|---|
CMPXCHG16B m128 64-bit mode only
CMPXCHG16B_MEMdq | REX.W 0F C7 /1 | CMPXCHG16B |
LOCK CMPXCHG16B m128 64-bit mode only
CMPXCHG16B_LOCK_MEMdq | REX.W 0F C7 /1 | CMPXCHG16B |
Latency and throughput
| Model | m128 | CMPXCHG16B m128 |
|---|---|---|
| Sandy Bridge | 6 / 1p015 | 6 / 1p015 |
| Haswell | 22 / 4p0156 | 22 / 4p0156 |
| Broadwell | 21 / 4p0156 | 21 / 4p0156 |
| Skylake, Skylake-SP, Ice Lake | 23 / 4p0156 | 23 / 4p0156 |
| Alder Lake, Sapphire Rapids | 32 / 4p0 p1 p5 p6 p11 | 32 / 4p0 p1 p5 p6 p11 |
| Lunar Lake | 32 / 2.83V2 V3 p0 p1 p2 p3 p4 p5 | 32 / 2.83V2 V3 p0 p1 p2 p3 p4 p5 |
| Bonnell | 22 / 11p1 | 22 / 11p1 |
| Silvermont | 10 / 3IEC0 IEC1 MEC | 10 / 3IEC0 IEC1 MEC |
| Piledriver | 3 / 69EX1 | 3 / 69EX1 |
| Zen, Zen 2 | 100 / 0.25 | 100 / 0.25 |
| Zen 3 | 4 / 14.75ALU0 ALU1 ALU2 ALU3 | 4 / 14.75ALU0 ALU1 ALU2 ALU3 |
| Zen 4 | 2 / 10ALU0 ALU1 ALU2 ALU3 | 2 / 10ALU0 ALU1 ALU2 ALU3 |
| Jaguar | 32 / 3ALU0 ALU1 | 38 / 38ALU0 ALU1 |
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
if dest.address % 16 != 0:
fault(GP, 0) # m128 must be 16-byte aligned, with or
# without LOCK
old = dest.read() # with LOCK: one atomic read-modify-write
if old == rdx << 64 | rax:
zf = 1
dest.write(rcx << 64 | rbx)
else:
zf = 0
rdx = old >> 64
rax = old
dest.write(old) # memory is written back all the same
# the other flags stay as they wereRun on AMD Zen 5 (EPYC 9645): 16 cases.
Operands
| Operand | Kind | Action |
|---|---|---|
CMPXCHG16B m128 64-bit mode only LOCK CMPXCHG16B m128 64-bit mode only | ||
m128 | explicit | read, conditional write |
RDX | implicit | read, conditional write |
RAX | implicit | read, conditional write |
RCX | implicit | read |
RBX | implicit | read |
RFLAGS | implicit | write |
Flags
| ZF |
|---|
| All forms |
| M |
Attributes
What else XED records about the forms. How to read.
- All forms
- aligned memory operand
- Memory forms without LOCK
- accepts a LOCK prefix
- LOCK forms
- locked: atomic read-modify-write
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 |
|---|---|---|
CMPXCHG16B | CMPXCHG16B | Every x86-64 processor in XED’s model and Zen 3 to Zen 6 |
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 2A, page 3-196 (CMPXCHG8B/
CMPXCHG16B) - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3 (325384-093, September 2026)
- AMD64 Architecture Programmer's Manual, Volume 2: System Programming (24593, rev. 3.46, October 2026)
- AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions (24594, rev. 3.39, 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.