Instruction
SBB
Subtracts an integer and the carry flag, the step that chains multi-word subtractions; APX adds a three-operand form.
- Extensions
- Forms
- 48 (24 Legacy, 24 EVEX)
- Data
- Intel XED v2026.08.23
SBB subtracts its source and CF from its destination, and leaves the
borrow out of that subtraction in CF. It is the subtracting counterpart
of ADC: to subtract numbers wider than a register, SUB the
lowest words and SBB each higher pair. GCC 14 and Clang 23 at -O2
compile an unsigned __int128 subtraction to sub and sbb, and an
__int128 negation to xor edx, edx, NEG of the low half
and sbb rdx, rsi, where NEG’s CF is the borrow.
A mask from the carry
SBB of a register from itself computes 0 - CF: all zeros when CF is clear, all ones when it is set, whatever the register held. Code uses it to turn a condition into a mask without a branch:
-(a < b)on unsigned numbers becomescmp rdi, rsiandsbb rax, rax, since CMP’s borrow is the comparison.x ? -1 : 0becomesneg ediandsbb eax, eax, since NEG sets CF for every operand but 0.a - (b < c)becomescmp rsi, rdxandsbb rax, 0.
The result of sbb reg, reg does not depend on the register, but the
instruction still names it as a source, and here the manuals differ.
AMD’s guide for Zen 5 lists sbb reg, reg among its dependency-removal
idioms, executed without waiting for the old value (Section 2.9.2);
Intel’s Optimization Reference Manual lists only XOR and SUB of a
general-purpose register with itself (Section 3.5.1.7). Clang clears the
register with xor eax, eax before such an SBB, GCC does not.
AF
The flags table follows XED, which records AF as undefined after SBB although it records AF as set by the result for SUB and ADC. Both vendors’ manuals define it: revision 093 of Intel’s, in the SBB entry and in Volume 1’s EFLAGS table, and AMD’s, whose SBB entry marks AF as modified. Zen 5 sets AF as SUB does, and the Operation section computes it so; the note under the flags table gives Intel’s references.
In the optimization guide
What the optimization guide says about SBB, a line per claim. Each links to the claim in the guide, with its sources and where they differ.
Out of order
- Zeroing and dependency-breaking idioms: AMD’s cores recognize two more:
cmp eax, eax, which takes no cycle, andsbb eax, eax, which turns the carry flag into 0 or all ones in one cycle without waiting for EAX.
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.
Zen and Zen+
- Integer execution: Register-to-register moves of 32-bit and 64-bit general registers and of XMM registers, and
xchgof general registers, take no execution cycle, while a YMM move renames only its lower half and moves the upper one in a pipe. sources differ
Zen 2
- Integer execution: Register-to-register moves of general registers of 32 and 64 bits,
xchgof them and moves of whole XMM and YMM registers take no execution cycle, where Zen 1 moves the upper half of a YMM register in a pipe. sources differ
Zen 3
- Integer execution: Register-to-register moves of general registers of 32 and 64 bits,
xchgof them and moves of whole XMM and YMM registers take no execution cycle, nor do the zeroing idioms such asxor eax, eaxandvpxor, which also break the dependency on the old value;sbb eax, eaxdepends only on the carry flag, andpcmpeqd xmm0, xmm0sets all ones without waiting. sources differ
Zen 4
- Integer execution: Register-to-register moves of general registers of 32 and 64 bits,
xchgof them and moves of whole vector registers take no execution cycle, nor do the zeroing idioms such asxor eax, eaxandvpxor, which also break the dependency on the old value;sbb eax, eaxdepends only on the carry flag. sources differ
Forms
| Instruction | Encoding | Requires |
|---|---|---|
SBB m8, imm8
SBB_MEMb_IMMb_80r3 | 80 /3 ib | Base instruction set |
SBB r8, imm8
SBB_GPR8_IMMb_80r3 | 80 /3 ib | Base instruction set |
SBB m16/32/64, imm16/32
SBB_MEMv_IMMz | 81 /3 iw/id | Base instruction set |
SBB r16/32/64, imm16/32
SBB_GPRv_IMMz | 81 /3 iw/id | Base instruction set |
SBB m8, imm8 not in 64-bit mode
SBB_MEMb_IMMb_82r3 | 82 /3 ib | Base instruction set |
SBB r8, imm8 not in 64-bit mode
SBB_GPR8_IMMb_82r3 | 82 /3 ib | Base instruction set |
SBB m16/32/64, imm8
SBB_MEMv_IMMb | 83 /3 ib | Base instruction set |
SBB r16/32/64, imm8
SBB_GPRv_IMMb | 83 /3 ib | Base instruction set |
SBB m8, r8
SBB_MEMb_GPR8 | 18 /r | Base instruction set |
SBB r8, r8
SBB_GPR8_GPR8_18 | 18 /r | Base instruction set |
SBB m16/32/64, r16/32/64
SBB_MEMv_GPRv | 19 /r | Base instruction set |
SBB r16/32/64, r16/32/64
SBB_GPRv_GPRv_19 | 19 /r | Base instruction set |
SBB r8, r8
SBB_GPR8_GPR8_1A | 1A /r | Base instruction set |
SBB r8, m8
SBB_GPR8_MEMb | 1A /r | Base instruction set |
SBB r16/32/64, r16/32/64
SBB_GPRv_GPRv_1B | 1B /r | Base instruction set |
SBB r16/32/64, m16/32/64
SBB_GPRv_MEMv | 1B /r | Base instruction set |
SBB AL, imm8
SBB_AL_IMMb | 1C ib | Base instruction set |
SBB rAX, imm16/32
SBB_OrAX_IMMz | 1D iw/id | Base instruction set |
LOCK SBB m8, imm8
SBB_LOCK_MEMb_IMMb_80r3 | 80 /3 ib | Base instruction set |
LOCK SBB m16/32/64, imm16/32
SBB_LOCK_MEMv_IMMz | 81 /3 iw/id | Base instruction set |
LOCK SBB m8, imm8 not in 64-bit mode
SBB_LOCK_MEMb_IMMb_82r3 | 82 /3 ib | Base instruction set |
LOCK SBB m16/32/64, imm8
SBB_LOCK_MEMv_IMMb | 83 /3 ib | Base instruction set |
LOCK SBB m8, r8
SBB_LOCK_MEMb_GPR8 | 18 /r | Base instruction set |
LOCK SBB m16/32/64, r16/32/64
SBB_LOCK_MEMv_GPRv | 19 /r | Base instruction set |
SBB r8, r8
SBB_GPR8i8_GPR8i8_APX | EVEX.LLZ.NP.MAP4.WIG 18 /rEVEX.LLZ.NP.MAP4.WIG 1A /r | APX_F |
SBB m8, r8
SBB_MEMi8_GPR8i8_APX | EVEX.LLZ.NP.MAP4.WIG 18 /r | APX_F |
SBB r16/32/64, r16/32/64, imm8 NDD
SBB_GPRv_GPRv_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 83 /3 ib ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, m16/32/64, imm8 NDD
SBB_GPRv_MEMv_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 83 /3 ib ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r8, r8, r8 NDD
SBB_GPR8i8_GPR8i8_GPR8i8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 18 /r ND=1EVEX.LLZ.NP.MAP4.WIG 1A /r ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r8, m8, r8 NDD
SBB_GPR8i8_MEMi8_GPR8i8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 18 /r ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, r16/32/64
SBB_GPRv_GPRv_APX | EVEX.LLZ.NP.MAP4.SCALABLE 19 /rEVEX.LLZ.NP.MAP4.SCALABLE 1B /r | APX_F |
SBB m16/32/64, r16/32/64
SBB_MEMv_GPRv_APX | EVEX.LLZ.NP.MAP4.SCALABLE 19 /r | APX_F |
SBB r16/32/64, r16/32/64, r16/32/64 NDD
SBB_GPRv_GPRv_GPRv_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 19 /r ND=1EVEX.LLZ.NP.MAP4.SCALABLE 1B /r ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, m16/32/64, r16/32/64 NDD
SBB_GPRv_MEMv_GPRv_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 19 /r ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r8, m8
SBB_GPR8i8_MEMi8_APX | EVEX.LLZ.NP.MAP4.WIG 1A /r | APX_F |
SBB r8, r8, m8 NDD
SBB_GPR8i8_GPR8i8_MEMi8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 1A /r ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, m16/32/64
SBB_GPRv_MEMv_APX | EVEX.LLZ.NP.MAP4.SCALABLE 1B /r | APX_F |
SBB r8, r8, imm8 NDD
SBB_GPR8i8_GPR8i8_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 80 /3 ib ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r8, m8, imm8 NDD
SBB_GPR8i8_MEMi8_IMM8_APX_N3 | EVEX.LLZ.NP.MAP4.WIG 80 /3 ib ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, r16/32/64, m16/32/64 NDD
SBB_GPRv_GPRv_MEMv_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 1B /r ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r8, imm8
SBB_GPR8i8_IMM8_APX | EVEX.LLZ.NP.MAP4.WIG 80 /3 ib | APX_F |
SBB m8, imm8
SBB_MEMi8_IMM8_APX | EVEX.LLZ.NP.MAP4.WIG 80 /3 ib | APX_F |
SBB r16/32/64, imm16/32
SBB_GPRv_IMMz_APX | EVEX.LLZ.NP.MAP4.SCALABLE 81 /3 iw/id | APX_F |
SBB m16/32/64, imm16/32
SBB_MEMv_IMMz_APX | EVEX.LLZ.NP.MAP4.SCALABLE 81 /3 iw/id | APX_F |
SBB r16/32/64, r16/32/64, imm16/32 NDD
SBB_GPRv_GPRv_IMMz_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 81 /3 iw/id ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, m16/32/64, imm16/32 NDD
SBB_GPRv_MEMv_IMMz_APX_N3 | EVEX.LLZ.NP.MAP4.SCALABLE 81 /3 iw/id ND=1 | APX_F + APX_NCI_NDD_NF |
SBB r16/32/64, imm8
SBB_GPRv_IMM8_APX | EVEX.LLZ.NP.MAP4.SCALABLE 83 /3 ib | APX_F |
SBB m16/32/64, imm8
SBB_MEMv_IMM8_APX | EVEX.LLZ.NP.MAP4.SCALABLE 83 /3 ib | APX_F |
Latency and throughput
| Model | m8, imm8SBB m8, imm8 | r8, imm8r16, imm16r32, imm32r16, imm8r32, imm8r64, imm8r8, r8r16, r16r32, r32r64, r64 | m16, imm16m32, imm32m64, imm32m16, imm8m32, imm8m64, imm8SBB m16, imm16SBB m32, imm32SBB m64, imm32SBB m16, imm8SBB m32, imm8SBB m64, imm8 | r64, imm32 | m8, r8SBB m8, r8 | m16, r16m32, r32m64, r64SBB m16, r16SBB m32, r32SBB 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 borrow in
flags = sub_flags(a, b, c) # AF too, which XED leaves undefined
dest.write(a - b - c) # a 32-bit register: bits 63:32 cleared
Run on AMD Zen 5 (EPYC 9645): 302 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 borrow in
flags = sub_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 |
|---|---|---|
SBB r/m8, imm8 SBB r/m16/32/64, imm16/32 SBB r/m16/32/64, imm8 LOCK SBB m8, imm8 LOCK SBB m16/32/64, imm16/32 LOCK SBB m16/32/64, imm8 | ||
r/m8/16/32/64 | explicit | read, write |
imm8/16/32 | explicit | read |
RFLAGS | implicit | read, write |
SBB r/m8, r8 SBB r/m16/32/64, r16/32/64 LOCK SBB m8, r8 LOCK SBB m16/32/64, r16/32/64 | ||
r/m8/16/32/64 | explicit | read, write |
r8/16/32/64 | explicit | read |
RFLAGS | implicit | read, write |
SBB r8, r/m8 SBB 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 |
SBB AL, imm8 SBB rAX, imm16/32 | ||
AL, rAX | explicit | read, write |
imm8/16/32 | explicit | read |
RFLAGS | implicit | read, write |
SBB r8, r/m8, imm8 NDD SBB r16/32/64, r/m16/32/64, imm8 NDD SBB 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 |
SBB r8, r/m8, r8 NDD SBB 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 |
SBB r8, r8, m8 NDD SBB 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 | U | 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.
SBB m8, imm8SBB m8, r8SBB m16/32/64, imm16/32SBB m16/32/64, imm8SBB 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
- NEG
- NOP
- NOT
- OR
- OUT
- OUTS
- PAUSE
- POP
- POPA
- POPF
- PUSH
- PUSHA
- PUSHF
- RCL
- RCR
- RET
- ROL
- ROR
- SALC
- SAR
- SCAS
- SETcc
- 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-613 (SBB)
- Intel Advanced Performance Extensions (Intel APX) Architecture Specification, revision 9.0 (355828-009, August 2026)
- Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1 (253665-093, September 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)
- 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.