Extensions
Forms
6 (6 Legacy)
Data
Intel XED v2026.08.23

With a LOCK prefix and a memory destination, CMPXCHG is the compare-and-swap of x86. GCC 14 and Clang 23 at -O2 compile C’s atomic_compare_exchange_strong to it, and atomic read-modify-writes that have no instruction of their own, such as a fetch-and-OR whose old value is used, to this loop:

  1. Load the shared value into the accumulator (EAX or RAX).
  2. Compute the new value from it in another register.
  3. Execute LOCK CMPXCHG with the shared location as the destination and the new value as the source. If the location still holds what step 1 loaded, the new value is stored and ZF is set.
  4. If ZF is clear, another thread changed the value in between. The accumulator now holds that value, so the loop goes back to step 2 without loading it again.

Taking a spinlock is the shortest case: 0 in EAX, 1 in the source register, and the lock is taken when ZF is set.

Points that are easy to miss:

  • Only the LOCK form is atomic with respect to other processors, and LOCK needs a memory destination (#UD otherwise).
  • The destination is written even when the comparison fails: Intel’s and AMD’s manuals both say the processor writes back the value it read. CMPXCHG therefore needs write access to the page either way.
  • With 32-bit operands the outcome decides which register is written. On success EAX is not written, so bits 63:32 of RAX keep their old value; on failure EAX is loaded and bits 63:32 are cleared. A register destination is the other way round: written and zero-extended on success, left whole on failure. Zen 5 and the Intel processor that ran the cases of the Operation section agree.
  • A locked operand that crosses a cache-line boundary makes the processor lock the bus, which system software can turn into #AC with split-lock disable (Intel’s Volume 3A, Section 11.1.2.3). Intel’s manual recommends naturally aligned locked operands, and AMD’s optimization guide for Zen 5 ones that do not cross a 64-byte boundary.

For two registers’ worth of data, such as a pointer with a version counter against the ABA problem, use CMPXCHG8B or CMPXCHG16B. XADD and XCHG do fetch-and-add and swap in one step, without a loop, and CMPccXADD adds only when a condition holds.

In the optimization guide

What the optimization guide says about CMPXCHG, a line per claim. Each links to the claim in the guide, with its sources and where they differ.

Memory

  • Sharing between cores: A contended lock is best taken by spinning on a plain load with PAUSE and trying cmpxchg only when it looks free, with backoff.

Forms

Every encoding of CMPXCHG that Intel XED knows, one row per XED instruction form (iform). How to read the notation.
InstructionEncodingRequires
CMPXCHG m8, r8 CMPXCHG_MEMb_GPR80F B0 /rBase instruction set
CMPXCHG r8, r8 CMPXCHG_GPR8_GPR80F B0 /rBase instruction set
CMPXCHG m16/32/64, r16/32/64 CMPXCHG_MEMv_GPRv0F B1 /rBase instruction set
CMPXCHG r16/32/64, r16/32/64 CMPXCHG_GPRv_GPRv0F B1 /rBase instruction set
LOCK CMPXCHG m8, r8 CMPXCHG_LOCK_MEMb_GPR80F B0 /rBase instruction set
LOCK CMPXCHG m16/32/64, r16/32/64 CMPXCHG_LOCK_MEMv_GPRv0F B1 /rBase instruction set

Latency and throughput

What the scheduling models of LLVM 23.1.2 give for each form, not measurements: latency / reciprocal throughput in cycles, the ports under them. A row is a model, or models that agree; a dash, a form that its processors lack. Memory forms: latency from the address, ports without the load and store units. Which processors each model covers.
Modelm8, r8r8, r8m16, r16
m32, r32
m64, r64
r16, r16
r32, r32
r64, r64
CMPXCHG m8, r8CMPXCHG m16, r16
CMPXCHG m32, r32
CMPXCHG m64, r64
Sandy Bridge8 / 2p0155 / 1.33p0158 / 2p0155 / 1.33p0158 / 2p0158 / 2p015
Haswell9 / 1p01565 / 1.25p01569 / 1p01565 / 1.25p01569 / 1p01569 / 1p0156
Broadwell, Skylake, Skylake-SP, Ice Lake8 / 1p01565 / 1.25p01568 / 1p01565 / 1.25p01568 / 1p01568 / 1p0156
Alder Lake, Sapphire Rapids13 / 1p0 p1 p5 p6 p113 / 1p0 p1 p5 p6 p1112 / 1p0 p1 p5 p6 p113 / 1p0 p1 p5 p6 p1113 / 1p0 p1 p5 p6 p1112 / 1p0 p1 p5 p6 p11
Lunar Lake13 / 0.67p0123453 / 0.83p01234512 / 0.67p0123453 / 0.83p01234513 / 0.67p01234512 / 0.67p012345
Bonnell6 / 3p19 / 4.5p0114 / 7p115 / 7.5p016 / 3p114 / 7p1
Silvermont10 / 3IEC0 IEC1 MEC6 / 3IEC0 IEC110 / 3IEC0 IEC1 MEC6 / 3IEC0 IEC110 / 3IEC0 IEC1 MEC10 / 3IEC0 IEC1 MEC
Piledriver3 / 23EX13 / 3EX13 / 21EX13 / 3EX13 / 23EX13 / 21EX1
Zen8 / 0.5ALU0 ALU1 ALU2 ALU31 / 0.25ALU0 ALU1 ALU2 ALU38 / 0.5ALU0 ALU1 ALU2 ALU31 / 0.25ALU0 ALU1 ALU2 ALU38 / 0.5ALU0 ALU1 ALU2 ALU38 / 0.5ALU0 ALU1 ALU2 ALU3
Zen 28 / 0.33ALU0 ALU1 ALU2 ALU33 / 0.25ALU0 ALU1 ALU2 ALU38 / 0.33ALU0 ALU1 ALU2 ALU33 / 0.25ALU0 ALU1 ALU2 ALU38 / 0.33ALU0 ALU1 ALU2 ALU38 / 0.33ALU0 ALU1 ALU2 ALU3
Zen 3, Zen 47 / 3ALU0 ALU1 ALU2 ALU33 / 3ALU0 ALU1 ALU2 ALU33 / 3ALU0 ALU1 ALU2 ALU33 / 3ALU0 ALU1 ALU2 ALU37 / 3ALU0 ALU1 ALU2 ALU33 / 3ALU0 ALU1 ALU2 ALU3
Jaguar11 / 1.5ALU0 ALU13 / 1.5ALU0 ALU111 / 1.5ALU0 ALU13 / 1.5ALU0 ALU116 / 16ALU0 ALU117 / 17ALU0 ALU1

Operation

What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.

old = dest.read()                # with LOCK: one atomic read-modify-write
flags = sub_flags(rAX, old)      # as CMP rAX, old
if rAX == old:
    dest.write(src)              # a 32-bit register: bits 63:32 cleared
else:
    rAX = old                    # EAX: bits 63:32 cleared
    if dest.is_memory:
        dest.write(old)          # memory is written back all the same
    # a register destination is not written: bits 63:32 of a 32-bit
    # one stay as they were

Run on AMD Zen 5 (EPYC 9645) and an Intel processor under KVM (model hidden): 272 cases.

Operands

What each form reads and writes, as Intel XED records it: the operands of its syntax, in order, and the implicit ones that the syntax does not name. How to read.
OperandKindAction
CMPXCHG r/m8, r8 CMPXCHG r/m16/32/64, r16/32/64 LOCK CMPXCHG m8, r8 LOCK CMPXCHG m16/32/64, r16/32/64
r/m8/16/32/64explicitread, conditional write
r8/16/32/64explicitread
AL, rAXimplicitread, conditional write
RFLAGSimplicitwrite

Flags

M modified; blank: not affected. How to read.
OFSFZFAFPFCF
All forms
MMMMMM

Attributes

What else XED records about the forms. How to read.

Memory forms without LOCK
accepts a LOCK prefix
LOCK forms
locked: atomic read-modify-write; accepts XACQUIRE; accepts XRELEASE

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.

CPUID requirements and processors of the XED ISA sets above. Alternatives are separated by “or”; processors follow XED’s chip model, whose AMD processors end with Zen 2, and the CPU data of this site for Zen 3 to Zen 6.
ISA setCPUIDProcessors
I486REAL

No CPUID bit: part of the base instruction set.

Every x86-64 processor in XED’s model and Zen 3 to Zen 6

More General-purpose instructions

All 109 General-purpose instructions

Sources

  1. Intel XED v2026.08.23 (commit 0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model.
  2. The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s -march feature sets and AMD’s Processor Programming References, which the page of each processor cites.
  3. LLVM 23.1.2's x86 scheduling models (commit 85ac56026243): the latency, reciprocal throughput and ports of each form, as llvm-mca reports them.
  4. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2A, page 3-194 (CMPXCHG)
  5. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3 (325384-093, September 2026)
  6. AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions (24594, rev. 3.39, October 2026)
  7. Software Optimization Guide for the AMD Zen5 Microarchitecture (58455, rev. 1.00, August 2024), Wayback Machine copy of AMD's ZIP

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.