Introduction
The integer arithmetic instructions work on the general registers and memory, at the operand size: 8, 16, 32 or 64 bits. They set the status flags in EFLAGS from the result:
- CF (carry, bit 0): an unsigned carry out of, or borrow into, the top bit;
- PF (parity, bit 2): set when the low byte of the result has an even number of 1 bits;
- AF (auxiliary carry, bit 4): a carry out of bit 3, for the decimal adjustments;
- ZF (zero, bit 6), SF (sign, bit 7, a copy of the result’s top bit) and OF (overflow, bit 11, a signed overflow).
Almost all of these came with the 8086 in 1978. The 80186 added the multiply by an
immediate, the 80386 the two-operand multiply and 32-bit operands, and x86-64 the
64-bit ones. Intel’s APX adds, in 64-bit mode, forms with a new destination register
(NDD), forms that leave the flags alone (NF), and a conditional compare,
ccmpscc. A program checks for APX with CPUID leaf 7, sub-leaf 1, EDX
bit 21. The logical instructions and shifts are on the
Logic, shifts and bits page.
The instructions
The notation is as on the Data transfer
page. r/m16/32/64, imm8 is a byte immediate sign-extended to the operand
size; with a 64-bit operand size, a 32-bit immediate is sign-extended too.
Addition, subtraction and comparison
These six share one pattern of encodings, the arithmetic and logic block of the
one-byte map: for operation n (0 to 7), opcodes 8n to
8n + 5, and 80, 81 and 83 with
ModRM.reg = n. OR, AND and XOR, the other three, are on the Logic page.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
add | r/m8, r8r/m16/32/64, r16/32/64r8, r/m8r16/32/64, r/m16/32/64AL, imm8rAX, imm16/32r/m8, imm8r/m16/32/64, imm16/32r/m16/32/64, imm8(APX) r, r/m, r and the rest | 00 /r01 /r02 /r03 /r04 ib05 iw/id80 /0 ib81 /0 iw/id83 /0 ibEVEX.MAP4 00–03, 80, 81, 83 /0 | Adds the source to the destination. Sets OF, SF, ZF, AF, CF and PF. With LOCK and a memory destination it is atomic. The APX form with ND = 1 writes the sum to a new register named in EVEX.vvvv (add rdx, rax, rcx); with NF = 1 it leaves the flags alone ({nf} add). | 8086 (Intel 8086, 1978) |
adc | as add | 10–1580, 81, 83 /2EVEX.MAP4 10–13, 80, 81, 83 /2 | Adds the source and CF to the destination, for adding numbers wider than a register. Flags as add. The APX form takes ND but not NF, since it reads CF. | 8086 (Intel 8086, 1978) |
sub | as add | 28–2D80, 81, 83 /5EVEX.MAP4 28–2B, 80, 81, 83 /5 | Subtracts the source from the destination. CF is set on an unsigned borrow, OF on a signed overflow. The APX form takes ND and NF. | 8086 (Intel 8086, 1978) |
sbb | as add | 18–1D80, 81, 83 /3EVEX.MAP4 18–1B, 80, 81, 83 /3 | Subtracts the source and CF from the destination. sbb eax, eax makes EAX all ones if CF was set, else zero. The APX form takes ND but not NF. | 8086 (Intel 8086, 1978) |
cmp | as add, without the APX forms | 38–3D80, 81, 83 /7 | Subtracts the source from the destination and sets the flags as sub does, but writes no result. It cannot take LOCK. In EVEX map 4, CMP’s opcodes belong to ccmpscc. | 8086 (Intel 8086, 1978) |
ccmpsccCondition names: ccmpo, ccmpno, ccmpb, ccmpae, ccmpe, ccmpne, ccmpbe, ccmpa, ccmps, ccmpns, ccmpt, ccmpf, ccmpl, ccmpge, ccmple, ccmpg | {dfv=…} r/m8, r8{dfv=…} r/m16/32/64, r16/32/64{dfv=…} r8, r/m8{dfv=…} r16/32/64, r/m16/32/64{dfv=…} r/m8, imm8{dfv=…} r/m16/32/64, imm16/32{dfv=…} r/m16/32/64, imm8 | EVEX.MAP4 38 /rEVEX.MAP4 39 /rEVEX.MAP4 3A /rEVEX.MAP4 3B /rEVEX.MAP4 80 /7 ibEVEX.MAP4 81 /7 iw/idEVEX.MAP4 83 /7 ib | Conditional compare. If the source condition scc holds, compares as cmp; otherwise sets OF, SF, ZF and CF to the default flags value given in the instruction, which the disassembler shows as {dfv=of,sf,zf,cf} (the flags set to 1). Chains of compares joined by AND or OR then need no branches. The condition is in EVEX P2 bits 3–0 and the default flags in EVEX.vvvv (OF, SF, ZF, CF from P1 bit 6 down), not inverted. The conditions are those of Jcc, except that 1010 is t (always) and 1011 is f (never). 64-bit mode only. | APX (announced for Intel Nova Lake and Diamond Rapids) |
Increment, decrement and negation
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
inc | r16/32r/m8r/m16/32/64 | 40+rw, 40+rdFE /0FF /0EVEX.MAP4 FE /0, FF /0 | Adds 1. Sets OF, SF, ZF, AF and PF, and leaves CF alone. In 64-bit mode 40 to 4F are REX prefixes, so only the FE and FF forms are left. The APX form takes ND and NF. | 8086 (Intel 8086, 1978) |
dec | r16/32r/m8r/m16/32/64 | 48+rw, 48+rdFE /1FF /1EVEX.MAP4 FE /1, FF /1 | Subtracts 1. Flags as inc; CF is left alone. | 8086 (Intel 8086, 1978) |
neg | r/m8r/m16/32/64 | F6 /3F7 /3EVEX.MAP4 F6 /3, F7 /3 | Replaces the operand with its two’s complement (0 minus it). CF is set unless the operand was 0; the other flags as sub. The APX form takes ND and NF. | 8086 (Intel 8086, 1978) |
Multiplication and division
The one-operand forms work on the accumulator: the 8-bit forms on AL and AX, the wider ones on AX, EAX or RAX and on DX, EDX or RDX, which hold the high half of the product or of the dividend.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
mul | r/m8r/m16/32/64 | F6 /4F7 /4EVEX.MAP4 F6 /4, F7 /4 | Unsigned multiply: AX = AL × r/m8, or DX:AX, EDX:EAX, RDX:RAX = the accumulator × r/m. OF and CF are set when the high half is not zero; SF, ZF, AF and PF are undefined. The APX form takes NF. | 8086 (Intel 8086, 1978) |
imul | r/m8r/m16/32/64r16/32/64, r/m16/32/64r16/32/64, r/m16/32/64, imm8r16/32/64, r/m16/32/64, imm16/32(APX) r, r, r/m | F6 /5F7 /50F AF /r6B /r ib69 /r iw/idEVEX.MAP4 AF /r, 69, 6B, F6 /5, F7 /5 | Signed multiply. The one-operand forms are as mul, signed. The two- and three-operand forms keep only the low half of the product, at the operand size, in the register. OF and CF are set when the full product does not fit. The immediate forms came with the 80186 and the two-operand form with the 80386. In APX, AF takes ND and NF, and the others NF. | 8086 (Intel 8086, 1978); the immediate forms 80186 (Intel 80186, 1982), the two-operand form 80386 (Intel 80386, 1985) |
imulzu | r16/32/64, r/m16/32/64, imm8r16/32/64, r/m16/32/64, imm16/32 | EVEX.MAP4 6B /r ib, ND = 1EVEX.MAP4 69 /r iw/id, ND = 1 | The three-operand imul with zero upper (ZU): the result is zero-extended into the whole 64-bit destination register. With a 16-bit operand size, bits 16 to 63 are cleared instead of kept. Here EVEX.ND is part of the opcode, not a new destination. | APX (announced for Intel Nova Lake and Diamond Rapids) |
div | r/m8r/m16/32/64 | F6 /6F7 /6EVEX.MAP4 F6 /6, F7 /6 | Unsigned divide: AX ÷ r/m8 gives the quotient in AL and the remainder in AH; DX:AX, EDX:EAX or RDX:RAX ÷ r/m gives the quotient in the accumulator and the remainder in DX, EDX or RDX. A zero divisor, or a quotient too big for its register, raises #DE. All six flags are undefined. | 8086 (Intel 8086, 1978) |
idiv | r/m8r/m16/32/64 | F6 /7F7 /7EVEX.MAP4 F6 /7, F7 /7 | Signed divide, as div. The quotient is rounded towards zero, and the remainder has the sign of the dividend. Sign-extend the dividend first with cwd, cdq or cqo. | 8086 (Intel 8086, 1978) |
Decimal adjustments
These turn the binary result of an addition, subtraction, multiplication or division of BCD (binary-coded decimal) digits back into BCD. Packed BCD holds two digits in a byte, unpacked one. All six are invalid in 64-bit mode.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
daa | – | 27 | Adjusts AL after adding two packed BCD bytes. Uses and sets AF and CF. | 8086 (Intel 8086, 1978) |
das | – | 2F | Adjusts AL after subtracting two packed BCD bytes. | 8086 (Intel 8086, 1978) |
aaa | – | 37 | Adjusts AL after adding two unpacked BCD digits, carrying into AH. Sets AF and CF on a carry; the other flags are undefined. | 8086 (Intel 8086, 1978) |
aas | – | 3F | Adjusts AL after subtracting two unpacked BCD digits, borrowing from AH. | 8086 (Intel 8086, 1978) |
aam | imm8 | D4 ib | After multiplying two unpacked digits: AH = AL ÷ imm8, AL = AL mod imm8. The usual base is 10 (D4 0A), which the disassembler writes as plain aam, as LLVM does; any other base is shown. A base of 0 raises #DE. Sets SF, ZF and PF. | 8086 (Intel 8086, 1978) |
aad | imm8 | D5 ib | Before dividing: AL = AH × imm8 + AL, AH = 0. D5 0A is shown as plain aad. In 64-bit mode D5 is APX’s REX2 prefix. | 8086 (Intel 8086, 1978) |
Notes
- LOCK. ADD, ADC, SUB, SBB, INC, DEC and NEG may take LOCK when the destination is memory, which makes the read, change and write atomic. LOCK with a register destination, or on CMP, MUL or DIV, raises #UD; the explorer reports it as an issue.
- The 82 alias. Opcode
82is a copy of80(group 1 with an 8-bit immediate). It is invalid in 64-bit mode, and the disassembler shows it as the matching instruction elsewhere. - APX. The new-destination forms (EVEX.ND = 1) write their result to
the register in EVEX.vvvv and leave both sources unchanged; a new destination cannot
take LOCK. The no-flags forms (EVEX.NF = 1) are shown with
{nf}. An APX form with neither is shown with{evex}, since it reads the same as the legacy instruction. See APX’s EVEX fields. - Immediates are shown as LLVM shows them: a byte immediate signed
(
add ebx, -0x1for83 C3 FF), and a word or doubleword immediate signed only when the operand size is 64 bits.
Links
Reference
- Intel 64 and IA-32 Architectures Software Developer’s Manuals – Intel’s manuals; volume 2 describes each instruction
- AMD64 Architecture Programmer’s Manual, Volume 3 – AMD’s reference to the general-purpose and system instructions
- Intel Advanced Performance Extensions (Intel APX) – Intel’s introduction to APX, with a link to its architecture specification
- x86 and amd64 instruction reference – Félix Cloutier’s web copy of the instruction pages of Intel’s manual