Article by Ayman Alheraki on January 11 2026 10:37 AM
Arithmetic and logic instructions form the core computational capabilities of the x86-64 processor. These instructions perform essential operations such as addition, subtraction, multiplication, division, bitwise manipulation, and comparisons that underpin all algorithmic processing in assembly code.
The x86-64 architecture provides a rich set of arithmetic and logic instructions optimized for a wide range of operand sizes, including byte (8-bit), word (16-bit), doubleword (32-bit), and quadword (64-bit), as well as vectorized SIMD data types. These instructions also include variants supporting immediate operands, register-to-register, memory-to-register, and register-to-memory operations.
Understanding these instructions, their behavior, flags impact, and encoding requirements is critical in designing a fully compliant assembler.
Purpose: Adds source operand to destination operand, storing the result in the destination.
Operands: Register, memory, immediate.
Flag effects: Updates Carry Flag (CF), Overflow Flag (OF), Zero Flag (ZF), Sign Flag (SF), Auxiliary Carry Flag (AF), and Parity Flag (PF).
Example:
ADD RAX, RBX adds the contents of RBX to RAX.
Purpose: Subtracts source operand from destination operand, storing the result in the destination.
Operands: Register, memory, immediate.
Flag effects: Same as ADD.
Example:
SUB RCX, 10 subtracts immediate 10 from RCX.
Unsigned multiply (MUL): Multiplies the accumulator register (AL, AX, EAX, RAX) by the source operand.
Signed multiply (IMUL): Similar to MUL but treats operands as signed integers.
IMUL Variants: Supports one-operand, two-operand, and three-operand forms for flexibility:
One-operand form uses RAX as implicit source/destination.
Two- and three-operand forms support destination explicit registers or memory operands with immediate values.
Flag effects: Flags are undefined or partially set depending on operand sizes.
Example:
IMUL RBX, RCX multiplies RBX by RCX storing result in RBX.
Unsigned division (DIV): Divides the accumulator (AX, DX:AX, RDX:RAX) by the operand.
Signed division (IDIV): Signed variant of DIV.
Operands: Only register or memory operand as divisor.
Results: Quotient stored in accumulator (AL, AX, EAX, RAX), remainder in AH, DX, or RDX accordingly.
Exception: Division by zero or overflow triggers processor exception.
Example:
IDIV RCX divides RDX:RAX by RCX.
Increment or decrement the operand by 1.
Does not affect the carry flag, which is crucial for certain multi-word arithmetic operations.
Commonly used for loops or counters.
Example:
INC RAX adds 1 to RAX.
Two’s complement negation of operand (computes 0 - operand).
Sets flags according to result.
Example:
NEG RAX negates RAX.
Logic instructions perform bitwise operations on operands, essential for bit masking, setting, clearing bits, and conditional operations.
Bitwise AND of source and destination.
Flags updated similarly to arithmetic instructions.
Commonly used for masking bits.
Example:
AND RAX, 0xFF masks lower byte of RAX.
Bitwise OR of operands.
Used to set bits.
Example:
OR RDX, RBX.
Bitwise exclusive OR.
Useful for toggling bits and for certain algorithms such as parity checks.
XORing a register with itself sets it to zero efficiently.
Example:
XOR RAX, RAX clears RAX.
Bitwise NOT (ones’ complement).
Inverts all bits of operand.
Example:
NOT RBX.
These instructions perform logical comparisons and set flags without changing the operands themselves.
Subtracts source from destination for flag evaluation only.
No result is stored; only flags updated.
Frequently used before conditional jumps.
Example:
CMP RAX, RBX.
Bitwise AND between operands, updating flags.
No operands are changed.
Often used to test if bits are set or clear.
Example:
TEST RAX, 1 tests if the least significant bit is set.
Used for bitwise shifting and rotating bits within a register or memory operand.
SHL/SAL (Shift Left / Shift Arithmetic Left): Shifts bits left, filling least significant bits with zero.
SHR (Shift Right Logical): Shifts bits right, filling with zero.
SAR (Shift Arithmetic Right): Shifts bits right, filling with sign bit (preserving signedness).
ROL, ROR (Rotate Left/Right): Circular bit shifts.
RCL, RCR (Rotate through Carry Left/Right): Rotate bits through carry flag.
These instructions affect CF and OF flags accordingly.
Example:
SHL RAX, 1 doubles RAX value by shifting left one bit.
x86-64 supports instructions for extended precision arithmetic critical for multi-word integer calculations.
Instructions like ADC (Add with Carry) and SBB (Subtract with Borrow) incorporate the carry flag, allowing chaining additions and subtractions across multiple registers.
These instructions maintain correctness in large integer arithmetic beyond 64 bits.
Example:
ADC RBX, RCX.
The x86-64 ISA includes vectorized arithmetic and logic instructions operating on XMM, YMM, and ZMM registers for floating-point and integer packed data.
Integer SIMD: Instructions like VPADDQ (packed add quadword), VPMULLD (packed multiply doubleword).
Floating-point SIMD: Instructions like VADDPD (add packed double-precision floating-point), VSUBPS (subtract packed single-precision).
Bitwise SIMD: VPAND, VPOR, VPXOR perform logical operations on vectors.
These instructions rely on VEX and EVEX prefixes for extended register sets and widths.
Arithmetic and logic instructions modify CPU flags, which affect control flow and conditional instructions.
Flags affected include:
CF (Carry Flag): Set on unsigned overflow (addition, subtraction).
OF (Overflow Flag): Set on signed overflow.
ZF (Zero Flag): Set if result is zero.
SF (Sign Flag): Reflects sign of result.
AF (Auxiliary Carry Flag): Used internally for BCD operations.
PF (Parity Flag): Set if result has even parity.
Careful management of flag states is essential for correct conditional branching and multi-instruction arithmetic sequences.
Arithmetic and logic instructions employ opcodes that vary based on operand size, direction, and type.
The assembler must correctly generate REX prefixes for 64-bit operands and extended registers.
Immediate operand encoding has size constraints: 8-bit immediates can be sign-extended or zero-extended automatically depending on the instruction.
Shift/rotate instructions require careful encoding of the count operand, which can be immediate or implicitly specified in the CL register.
SIMD variants use VEX/EVEX prefix encoding, with additional opcode bytes for different operations and vector sizes.
The arithmetic and logic instruction set of the x86-64 ISA is a rich and versatile collection enabling integer and floating-point computations, bitwise manipulation, and complex control flow decisions. A complete assembler must provide comprehensive support for these instructions, handling variations in operand sizes, flag behaviors, immediate values, and SIMD extensions.
Mastering these instructions enables the creation of efficient, high-performance assembly programs and underpins all higher-level language constructs that translate into machine code.