Instruction
ADC
Adds two integers and the carry flag, the step that chains multi-word additions; APX adds a three-operand form.
- Extensions
- Forms
- 48 (24 Legacy, 24 EVEX)
- Data
- Intel XED v2026.08.23
ADC adds its source and CF to its destination, and leaves the carry out of that sum in CF. That makes it the link of a chain: to add numbers wider than a register, ADD the lowest words and ADC each higher pair, every ADC taking the carry of the one before.
Wide additions in C
GCC 14 and Clang 23 at -O2 compile an unsigned __int128 addition to
add on the low halves and adc on the high halves, the result in
RDX:RAX. For longer numbers both offer carry built-ins:
__builtin_addcll(a, b, carry_in, &carry_out), called once per word
with the carry passed along, becomes one ADD and a row of ADCs, with the
loads and stores between them done by MOV, which leaves CF alone.
A loop over the words is harder, because the loop’s own CMP overwrites
CF. With the _addcarry_u64 intrinsic in a loop, both compilers save
the carry in a register with SETC (or SETB) after each ADC and recreate
it at the top with add al, -1, which sets CF exactly when AL is not 0;
Clang also unrolls by four and keeps CF in the flags within each pass.
Hand-written code can keep CF across the whole loop by stepping with LEA
and counting with DEC, neither of which writes CF, as in
Example 3-26 of Intel’s Optimization Reference Manual.
Adding a condition
ADC with 0 adds the carry alone, and CMP puts an unsigned
comparison into CF, so a + (b < c) on unsigned numbers becomes
cmp rsi, rdx and adc rax, 0, without a SETcc.
Related instructions
SBB is the subtracting counterpart. ADCX and ADOX add with a carry in CF or OF only, so that two chains can run side by side; Intel’s manual presents them, with MULX, as a way to speed up arithmetic on large integers (Section 2.8.5.10). APX gives ADC a form with a new destination register but, unlike ADD, none that leaves the flags unchanged.
Intel’s manual notes that ADC and SBB became faster in Sandy Bridge, with a throughput of one per cycle instead of 1.5 to 2 cycles before (Section 3.5.1.3).
In the optimization guide
What the optimization guide says about ADC, a line per claim. Each links to the claim in the guide, with its sources and where they differ.
Haswell and Broadwell
- What Broadwell changed: A micro-op of Haswell’s reads three inputs only for FMA, so ADC, SBB and CMOV, which read two registers and the flags, are two micro-ops each; Broadwell makes them one, though stores and blends stay at two.
Forms
| Instruction | Encoding | Requires |
|---|---|---|
ADC m8, imm8
ADC_MEMb_IMMb_80r2 | 80 /2 ib | Base instruction set |
ADC r8, imm8
ADC_GPR8_IMMb_80r2 | 80 /2 ib | Base instruction set |
ADC m16/32/64, imm16/32
ADC_MEMv_IMMz | 81 /2 iw/id | Base instruction set |
ADC r16/32/64, imm16/32
ADC_GPRv_IMMz | 81 /2 iw/id | Base instruction set |
ADC m8, imm8 not in 64-bit mode
ADC_MEMb_IMMb_82r2 | 82 /2 ib | Base instruction set |
ADC r8, imm8 not in 64-bit mode
ADC_GPR8_IMMb_82r2 | 82 /2 ib | Base instruction set |
ADC m16/32/64, imm8
ADC_MEMv_IMMb | 83 /2 ib | Base instruction set |
ADC r16/32/64, imm8
ADC_GPRv_IMMb | 83 /2 ib | Base instruction set |
ADC m8, r8
ADC_MEMb_GPR8 | 10 /r | Base instruction set |
ADC r8, r8
ADC_GPR8_GPR8_10 | 10 /r | Base instruction set |
ADC m16/32/64, r16/32/64
ADC_MEMv_GPRv | 11 /r | Base instruction set |
ADC r16/32/64, r16/32/64
ADC_GPRv_GPRv_11 | 11 /r | Base instruction set |
ADC r8, m8
ADC_GPR8_MEMb | 12 /r | Base instruction set |
ADC r8, r8
ADC_GPR8_GPR8_12 | 12 /r | Base instruction set |
ADC r16/32/64, m16/32/64
ADC_GPRv_MEMv | 13 /r | Base instruction set |
ADC r16/32/64, r16/32/64
ADC_GPRv_GPRv_13 | 13 /r | Base instruction set |
ADC AL, imm8
ADC_AL_IMMb | 14 ib | Base instruction set |
ADC rAX, imm16/32
ADC_OrAX_IMMz | 15 iw/id | Base instruction set |
LOCK ADC m8, imm8
ADC_LOCK_MEMb_IMMb_80r2 | 80 /2 ib | Base instruction set |
LOCK ADC m16/32/64, imm16/32
ADC_LOCK_MEMv_IMMz | 81 /2 iw/id | Base instruction set |
LOCK ADC m8, imm8 not in 64-bit mode
ADC_LOCK_MEMb_IMMb_82r2 | 82 /2 ib | Base instruction set |
LOCK ADC m16/32/64, imm8
ADC_LOCK_MEMv_IMMb | 83 /2 ib | Base instruction set |
LOCK ADC m8, r8
ADC_LOCK_MEMb_GPR8 | 10 /r | Base instruction set |
LOCK ADC m16/32/64, r16/32/64
ADC_LOCK_MEMv_GPRv | 11 /r | Base instruction set |
ADC r8, r8
ADC_GPR8i8_GPR8i8_APX | EVEX.LLZ.NP.MAP4.WIG 10 /rEVEX.LLZ.NP.MAP4.WIG 12 /r | APX_F |
ADC m8, r8
ADC_MEMi8_GPR8i8_APX | EVEX.LLZ.NP.MAP4.WIG 10 /r | APX_F |
ADC r16/32/64, r16/32/64, imm8 NDD
ADC_GPRv_GPRv_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 83 /2 ib ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, m16/32/64, imm8 NDD
ADC_GPRv_MEMv_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 83 /2 ib ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r8, r8, r8 NDD
ADC_GPR8i8_GPR8i8_GPR8i8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 10 /r ND=1EVEX.LLZ.NP.MAP4.WIG 12 /r ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r8, m8, r8 NDD
ADC_GPR8i8_MEMi8_GPR8i8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 10 /r ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, r16/32/64
ADC_GPRv_GPRv_APX | EVEX.LLZ.NP.MAP4.SCALABLE 11 /rEVEX.LLZ.NP.MAP4.SCALABLE 13 /r | APX_F |
ADC m16/32/64, r16/32/64
ADC_MEMv_GPRv_APX | EVEX.LLZ.NP.MAP4.SCALABLE 11 /r | APX_F |
ADC r16/32/64, r16/32/64, r16/32/64 NDD
ADC_GPRv_GPRv_GPRv_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 11 /r ND=1EVEX.LLZ.NP.MAP4.SCALABLE 13 /r ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, m16/32/64, r16/32/64 NDD
ADC_GPRv_MEMv_GPRv_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 11 /r ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r8, m8
ADC_GPR8i8_MEMi8_APX | EVEX.LLZ.NP.MAP4.WIG 12 /r | APX_F |
ADC r8, r8, m8 NDD
ADC_GPR8i8_GPR8i8_MEMi8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 12 /r ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, m16/32/64
ADC_GPRv_MEMv_APX | EVEX.LLZ.NP.MAP4.SCALABLE 13 /r | APX_F |
ADC r8, r8, imm8 NDD
ADC_GPR8i8_GPR8i8_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 80 /2 ib ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r8, m8, imm8 NDD
ADC_GPR8i8_MEMi8_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 80 /2 ib ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, r16/32/64, m16/32/64 NDD
ADC_GPRv_GPRv_MEMv_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 13 /r ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r8, imm8
ADC_GPR8i8_IMM8_APX | EVEX.LLZ.NP.MAP4.WIG 80 /2 ib | APX_F |
ADC m8, imm8
ADC_MEMi8_IMM8_APX | EVEX.LLZ.NP.MAP4.WIG 80 /2 ib | APX_F |
ADC r16/32/64, imm16/32
ADC_GPRv_IMMz_APX | EVEX.LLZ.NP.MAP4.SCALABLE 81 /2 iw/id | APX_F |
ADC m16/32/64, imm16/32
ADC_MEMv_IMMz_APX | EVEX.LLZ.NP.MAP4.SCALABLE 81 /2 iw/id | APX_F |
ADC r16/32/64, r16/32/64, imm16/32 NDD
ADC_GPRv_GPRv_IMMz_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 81 /2 iw/id ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, m16/32/64, imm16/32 NDD
ADC_GPRv_MEMv_IMMz_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 81 /2 iw/id ND=1 | APX_F + APX_NCI_NDD_NF |
ADC r16/32/64, imm8
ADC_GPRv_IMM8_APX | EVEX.LLZ.NP.MAP4.SCALABLE 83 /2 ib | APX_F |
ADC m16/32/64, imm8
ADC_MEMv_IMM8_APX | EVEX.LLZ.NP.MAP4.SCALABLE 83 /2 ib | APX_F |
Latency and throughput
| Model | m8, imm8ADC m8, imm8 | r8, imm8r16, imm16r32, imm32r16, imm8r32, imm8r64, imm8r8, r8r16, r16r32, r32r64, r64 | m16, imm16m32, imm32m64, imm32m16, imm8m32, imm8m64, imm8ADC m16, imm16ADC m32, imm32ADC m64, imm32ADC m16, imm8ADC m32, imm8ADC m64, imm8 | r64, imm32 | m8, r8ADC m8, r8 | m16, r16m32, r32m64, r64ADC m16, r16ADC m32, r32ADC m64, r64 | r8, m8r16, m16r32, m32r64, m64 | AL, imm8rAX, imm16rAX, imm32 |
|---|---|---|---|---|---|---|---|---|
| Sandy Bridge | 9 / 1p015 | 2 / 0.67p015 | 9 / 1p015 | 2 / 0.67p015 | 9 / 1p015 | 9 / 1p015 | 7 / 0.67p015 | 2 / 0.67p015 |
| Haswell | 9 / 1p0156 | 2 / 0.5p0156 | 9 / 1p0156 | 2 / 0.5p0156 | 9 / 1p0156 | 9 / 1p0156 | 7 / 0.5p0156 | 2 / 0.5p0156 |
| Broadwell, Skylake, Skylake-SP, Ice Lake | 8 / 1p0156 | 1 / 0.5p06 | 8 / 1p0156 | 1 / 0.5p06 | 8 / 1p0156 | 8 / 1p0156 | 6 / 0.5p06 | 2 / 0.5p0156 |
| Alder Lake, Sapphire Rapids | 13 / 0.5p0 p1 p5 p6 p11 | 1 / 0.5p06 | 12 / 0.5p0 p1 p5 p6 p11 | 1 / 0.5p06 | 13 / 0.6p0 p1 p5 p6 p11 | 12 / 0.6p0 p1 p5 p6 p11 | 6 / 0.5p06 | 1 / 0.5p06 |
| Lunar Lake | 12 / 0.5p012345 | 1 / 0.33p024 | 12 / 0.5p012345 | 1 / 0.33p024 | 12 / 0.5p012345 | 12 / 0.5p012345 | 6 / 0.33p024 | 1 / 0.33p024 |
| Bonnell | 1 / 1p0 | 1 / 0.5p01 | 1 / 1p0 | 1 / 0.5p01 | 1 / 1p0 | 1 / 1p0 | 1 / 1p0 | 1 / 0.5p01 |
| Silvermont | 5 / 2IEC0 IEC1 MEC | 1 / 0.5IEC0 IEC1 | 5 / 2IEC0 IEC1 MEC | 1 / 0.5IEC0 IEC1 | 5 / 2IEC0 IEC1 MEC | 5 / 2IEC0 IEC1 MEC | 4 / 1IEC0 IEC1 MEC | 1 / 0.5IEC0 IEC1 |
| Piledriver | 6 / 2EX0 EX1 | 1 / 1EX0 EX1 | 6 / 2EX0 EX1 | 1 / 1.5EX0 EX1 | 6 / 2EX0 EX1 | 6 / 2EX0 EX1 | 5 / 1.5EX0 EX1 | 1 / 1EX0 EX1 |
| Zen | 5 / 0.5ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 5 / 0.5ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 5 / 0.5ALU0 ALU1 ALU2 ALU3 | 5 / 0.5ALU0 ALU1 ALU2 ALU3 | 5 / 0.5ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Zen 2 | 5 / 0.33ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 5 / 0.33ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 | 5 / 0.33ALU0 ALU1 ALU2 ALU3 | 5 / 0.33ALU0 ALU1 ALU2 ALU3 | 5 / 0.33ALU0 ALU1 ALU2 ALU3 | 1 / 0.25ALU0 ALU1 ALU2 ALU3 |
| Zen 3, Zen 4 | 6 / 1ALU0 ALU1 ALU2 ALU3 | 1 / 1ALU0 ALU1 ALU2 ALU3 | 6 / 1ALU0 ALU1 ALU2 ALU3 | 1 / 1ALU0 ALU1 ALU2 ALU3 | 1 / 1.75ALU0 ALU1 ALU2 ALU3 | 6 / 1ALU0 ALU1 ALU2 ALU3 | 5 / 1ALU0 ALU1 ALU2 ALU3 | 1 / 1ALU0 ALU1 ALU2 ALU3 |
| Jaguar | 6 / 1ALU0 ALU1 | 1 / 1ALU0 ALU1 | 6 / 1ALU0 ALU1 | 1 / 1ALU0 ALU1 | 6 / 1ALU0 ALU1 | 6 / 1ALU0 ALU1 | 4 / 1ALU0 ALU1 | 1 / 1ALU0 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 = sext(src) # an immediate is sign-extended to OSIZE
c = cf # the carry in
flags = add_flags(a, b, c)
dest.write(a + b + c) # a 32-bit register: bits 63:32 cleared
Run on AMD Zen 5 (EPYC 9645) and an Intel processor under KVM (model hidden): 1,040 cases. The APX forms were not run: none of these processors has APX. The forms that 64-bit mode lacks were not run: the probe runs in 64-bit mode.
a = src1.read()
b = sext(src2) # an immediate is sign-extended to OSIZE
c = cf # the carry in
flags = add_flags(a, b, c)
dest.write(a + b + c) # the new destination: bits 63:OSIZE
# cleared, even for 8 and 16 bits
Not run on a processor: none of these processors has APX.
Operands
| Operand | Kind | Action |
|---|---|---|
ADC r/m8, imm8 ADC r/m16/32/64, imm16/32 ADC r/m16/32/64, imm8 LOCK ADC m8, imm8 LOCK ADC m16/32/64, imm16/32 LOCK ADC m16/32/64, imm8 | ||
r/m8/16/32/64 | explicit | read, write |
imm8/16/32 | explicit | read |
RFLAGS | implicit | read, write |
ADC r/m8, r8 ADC r/m16/32/64, r16/32/64 LOCK ADC m8, r8 LOCK ADC m16/32/64, r16/32/64 | ||
r/m8/16/32/64 | explicit | read, write |
r8/16/32/64 | explicit | read |
RFLAGS | implicit | read, write |
ADC r8, r/m8 ADC r16/32/64, r/m16/32/64 | ||
r8/16/32/64 | explicit | read, write |
r/m8/16/32/64 | explicit | read |
RFLAGS | implicit | read, write |
ADC AL, imm8 ADC rAX, imm16/32 | ||
AL, rAX | explicit | read, write |
imm8/16/32 | explicit | read |
RFLAGS | implicit | read, write |
ADC r8, r/m8, imm8 NDD ADC r16/32/64, r/m16/32/64, imm8 NDD ADC r16/32/64, r/m16/32/64, imm16/32 NDD | ||
r8/16/32/64 | explicit | write |
r/m8/16/32/64 | explicit | read |
imm8/16/32 | explicit | read |
RFLAGS | implicit | read, write |
ADC r8, r/m8, r8 NDD ADC r16/32/64, r/m16/32/64, r16/32/64 NDD | ||
r8/16/32/64 | explicit | write |
r/m8/16/32/64 | explicit | read |
r8/16/32/64 | explicit | read |
RFLAGS | implicit | read, write |
ADC r8, r8, m8 NDD ADC r16/32/64, r16/32/64, m16/32/64 NDD | ||
r8/16/32/64 | explicit | write |
r8/16/32/64 | explicit | read |
m8/16/32/64 | explicit | read |
RFLAGS | implicit | read, write |
Flags
| OF | SF | ZF | AF | PF | CF |
|---|---|---|---|---|---|
| All forms | |||||
| M | M | M | M | M | TM |
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
Attributes
What else XED records about the forms. How to read.
ADC m8, imm8ADC m8, r8ADC m16/32/64, imm16/32ADC m16/32/64, imm8ADC m16/32/64, r16/32/64- 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 |
|---|---|---|
I86 | 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 | APX_F | Nova Lake, Diamond Rapids |
APX_F_N3 | APX_F + APX_NCI_NDD_NF | Same as APX_F |
More General-purpose instructions
- AAA
- AAD
- AAM
- AAS
- ADD
- AND
- BOUND
- BSF
- BSR
- BSWAP
- BT
- BTC
- BTR
- BTS
- CALL
- CBW
- CDQ
- CDQE
- CLC
- CLD
- CLI
- CMC
- CMP
- CMPS
- CMPXCHG
- CMPXCHG8B
- CPUID
- CQO
- CWD
- CWDE
- DAA
- DAS
- DEC
- DIV
- ENTER
- IDIV
- IMUL
- IN
- INC
- INS
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 2A, page 3-9 (ADC)
- 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.