Instruction
XADD
Exchanges a register with the destination and stores their sum in the destination; with LOCK it is the atomic fetch-and-add.
- Extensions
- Forms
- 6 (6 Legacy)
- Data
- Intel XED v2026.08.23
LOCK XADD is the atomic fetch-and-add: it adds a register to memory and
hands back the value the memory held before, in one indivisible step.
GCC 14 and Clang 23 at -O2 compile C’s atomic_fetch_add to it when
the old value is used, and atomic_fetch_sub to a NEG of the operand
followed by LOCK XADD. When the old value is not needed, both emit a
plain LOCK ADD instead, and when only “did it reach zero” matters, as
in dropping a reference count, they subtract with LOCK SUB (GCC) or
LOCK DEC (Clang) and test ZF.
Typical uses:
- counters and statistics that several threads update;
- handing out slots, such as the next free index of a shared buffer: each thread gets a different old value;
- ticket locks: a thread takes a ticket with LOCK XADD on the next ticket number and spins, with PAUSE, until the number being served equals it.
Things to know:
- The flags are those of the addition, so they describe the new value, not the old one that the register receives.
- Only the LOCK form is atomic with respect to other processors, and LOCK needs a memory destination (#UD otherwise).
- A locked instruction is also a full barrier. By both vendors' manuals, loads and stores are not reordered with it, so a sequentially consistent fetch-and-add needs no extra fence.
- With both operands the same register, the register ends up with the sum, twice its old value, as Zen 5 and the Intel processor recorded.
- As with CMPXCHG, an operand that crosses a cache-line boundary makes the processor lock the bus; keep it naturally aligned.
CMPXCHG covers the atomic updates that have no instruction of their own, XCHG swaps without adding, and CMPccXADD adds only when a comparison holds. AADD adds to memory atomically without returning the old value and without ordering other memory accesses.
Forms
| Instruction | Encoding | Requires |
|---|---|---|
XADD m8, r8
XADD_MEMb_GPR8 | 0F C0 /r | Base instruction set |
XADD r8, r8
XADD_GPR8_GPR8 | 0F C0 /r | Base instruction set |
XADD m16/32/64, r16/32/64
XADD_MEMv_GPRv | 0F C1 /r | Base instruction set |
XADD r16/32/64, r16/32/64
XADD_GPRv_GPRv | 0F C1 /r | Base instruction set |
LOCK XADD m8, r8
XADD_LOCK_MEMb_GPR8 | 0F C0 /r | Base instruction set |
LOCK XADD m16/32/64, r16/32/64
XADD_LOCK_MEMv_GPRv | 0F C1 /r | Base instruction set |
Latency and throughput
| Model | m8, r8 | r8, r8r16, r16r32, r32r64, r64 | m16, r16m32, r32m64, r64 | XADD m8, r8 | XADD m16, r16XADD m32, r32XADD m64, r64 |
|---|---|---|---|---|---|
| Sandy Bridge | 8 / 1p015 | 2 / 1p015 | 8 / 1p015 | 8 / 1p015 | 8 / 1p015 |
| Haswell | 8 / 1p0156 | 2 / 0.75p0156 | 8 / 1p0156 | 8 / 1p0156 | 8 / 1p0156 |
| Broadwell, Skylake, Skylake-SP | 7 / 1p0156 | 2 / 0.75p0156 | 7 / 1p0156 | 7 / 1p0156 | 7 / 1p0156 |
| Ice Lake | 7 / 0.5p0156 | 2 / 0.75p0156 | 7 / 0.5p0156 | 7 / 0.5p0156 | 7 / 0.5p0156 |
| Alder Lake, Sapphire Rapids | 13 / 0.5p0 p1 p5 p6 p11 | 2 / 0.6p0 p1 p5 p6 p11 | 12 / 0.5p0 p1 p5 p6 p11 | 13 / 0.5p0 p1 p5 p6 p11 | 12 / 0.5p0 p1 p5 p6 p11 |
| Lunar Lake | 13 / 0.5p012345 | 2 / 0.5p012345 | 12 / 0.5p012345 | 13 / 0.5p012345 | 12 / 0.5p012345 |
| Bonnell | 3 / 1.5p1 | 2 / 1p01 | 3 / 1.5p1 | 3 / 1.5p1 | 3 / 1.5p1 |
| Silvermont | 4 / 2IEC0 IEC1 MEC | 3 / 1.5IEC0 IEC1 | 4 / 2IEC0 IEC1 MEC | 4 / 2IEC0 IEC1 MEC | 4 / 2IEC0 IEC1 MEC |
| Piledriver | 6 / 20EX1 | 1 / 1EX1 | 6 / 20EX1 | 6 / 20EX1 | 6 / 20EX1 |
| Zen, Zen 2 | 100 / 0.25 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 100 / 0.25 | 100 / 0.25 | 100 / 0.25 |
| Zen 3, Zen 4 | 5 / 0.67ALU0 ALU1 ALU2 ALU3 | 0 / 21ALU0 ALU1 ALU2 ALU3 | 5 / 0.67ALU0 ALU1 ALU2 ALU3 | 5 / 0.67ALU0 ALU1 ALU2 ALU3 | 5 / 0.67ALU0 ALU1 ALU2 ALU3 |
| Jaguar | 11 / 1.5ALU0 ALU1 | 2 / 1.5ALU0 ALU1 | 11 / 1.5ALU0 ALU1 | 16 / 16ALU0 ALU1 | 16 / 16ALU0 ALU1 |
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
a = dest.read() # with LOCK: one atomic read-modify-write
b = src.read()
flags = add_flags(a, b)
src.write(a) # when dest and src are one register,
dest.write(a + b) # the sum, written last, is what stays
Run on AMD Zen 5 (EPYC 9645) and an Intel processor under KVM (model hidden): 288 cases.
Operands
| Operand | Kind | Action |
|---|---|---|
XADD r/m8, r8 XADD r/m16/32/64, r16/32/64 LOCK XADD m8, r8 LOCK XADD m16/32/64, r16/32/64 | ||
r/m8/16/32/64 | explicit | read, write |
r8/16/32/64 | explicit | read, write |
RFLAGS | implicit | write |
Flags
| OF | SF | ZF | AF | PF | CF |
|---|---|---|---|---|---|
| All forms | |||||
| M | M | M | M | M | M |
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.
| ISA set | CPUID | Processors |
|---|---|---|
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
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 2D, page 6-27 (XADD)
- 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.