AsAssembly · Lesson 4 of 10

Arithmetic & Logic

The CPU can add, subtract, multiply, divide, and do bitwise operations. Every result updates the FLAGS register — a set of bits that record whether the result was zero, negative, overflowed, etc. Branches read those flags.

x86-64 ASM
; Arithmetic
add rax, rbx        ; rax = rax + rbx
sub rax, 10         ; rax = rax - 10
inc rax             ; rax = rax + 1  (faster than add rax, 1)
dec rax             ; rax = rax - 1
neg rax             ; rax = -rax  (two's complement negate)

; imul — signed multiply
imul rax, rbx       ; rax = rax * rbx (lower 64 bits)
imul rax, rbx, 7    ; rax = rbx * 7 (three-operand form)

; idiv — signed divide (uses rdx:rax as 128-bit dividend)
; Prepare: sign-extend rax into rdx with cqo
cqo                 ; sign extend rax -> rdx:rax
idiv rbx            ; rax = rdx:rax / rbx (quotient)
                    ; rdx = rdx:rax % rbx (remainder)

; Bitwise
and rax, rbx        ; rax = rax & rbx
or  rax, rbx        ; rax = rax | rbx
xor rax, rbx        ; rax = rax ^ rbx
not rax             ; rax = ~rax  (bitwise NOT)

; xor reg, reg — idiomatic zero a register (smaller encoding than mov reg, 0)
xor eax, eax        ; eax = 0 (also zeros rax via zero-extension)

; Shifts
shl rax, 3          ; rax = rax << 3  (multiply by 8)
shr rax, 1          ; rax = rax >> 1  (divide by 2, unsigned)
sar rax, 1          ; rax = rax >> 1  (arithmetic, preserves sign)
rol rax, 4          ; rotate left 4 bits
ror rax, 4          ; rotate right 4 bits
x86-64 ASM
; FLAGS register — bits set by arithmetic/logic instructions
; ZF (zero flag)  — set if result == 0
; SF (sign flag)  — set if result < 0 (MSB is 1)
; CF (carry flag) — set if unsigned overflow occurred
; OF (of flag)    — set if signed overflow occurred
; PF (parity flag)— set if number of 1-bits is even

; cmp — subtract without storing result, just sets flags
cmp rax, rbx        ; sets flags based on (rax - rbx)
cmp rax, 0          ; common: check if rax is zero

; test — AND without storing result, just sets flags
test rax, rax       ; sets ZF if rax == 0 (common pattern!)
test rax, 1         ; sets ZF if rax is even (check lowest bit)

; Conditional moves (branchless programming)
cmp rax, rbx
cmovg  rax, rbx     ; rax = rbx  if rax > rbx (signed greater)
cmovge rax, rbx     ; rax = rbx  if rax >= rbx
cmovl  rax, rbx     ; rax = rbx  if rax < rbx
cmove  rax, rbx     ; rax = rbx  if equal (ZF set)
cmovne rax, rbx     ; rax = rbx  if not equal

; Example: max(rax, rbx) without branching
cmp rax, rbx
cmovl rax, rbx      ; if rax < rbx, rax = rbx
✦ Tip
Bit manipulation tricks that compilers know and you should too: `x & (x-1)` clears the lowest set bit, `x & (-x)` isolates the lowest set bit, `x | (x-1)` sets all bits below the lowest set bit, `(x >> 63)` extracts the sign bit of a 64-bit value. These appear constantly in optimized code.