Arithmetic

Integer arithmetic, flags, multiplication, division, and practical numeric patterns.

Integer arithmetic is mostly ordinary two-operand work, with two important exceptions: multiply and divide can use the paired rdx:rax result, and signed division needs the dividend extended correctly first.

The everyday instructions

add and sub update their destination. inc and dec change it by one, while neg flips the sign using two's complement. All of them update status flags that later branches can inspect.

The everyday instructions source/chapters/arith.asm
    mov x, 100
    mov y, 50
    mov rax, x
    ; -----------------------------------------------------------------------------
    ; add dest, source
    ; -----------------------------------------------------------------------------
    add rax, y
    ; -----------------------------------------------------------------------------
    ; sub dest, source
    ; -----------------------------------------------------------------------------
    sub rax, x
    ; -----------------------------------------------------------------------------
    ; inc dest
    ; -----------------------------------------------------------------------------
    inc rax
    ; -----------------------------------------------------------------------------
    ; dec dest
    ; -----------------------------------------------------------------------------
    dec rax
    ; -----------------------------------------------------------------------------
    ; neg dest
    ; -----------------------------------------------------------------------------
    neg rax

Keep in mind: The source operand is unchanged; the destination receives the result.

Multiply has useful forms

The one-operand mul/imul forms use rax implicitly and can produce a double-width result in rdx:rax. The two- and three-operand imul forms are often easier when you only need the low half.

Multiply has useful forms source/chapters/arith.asm
    mov rax, 100
    mov rcx, 100
    imul rcx
    imul rax, rcx
    imul rdx, rax, 8

Keep in mind: Use the explicit destination forms when you do not need the high half in rdx.

Division needs a prepared dividend

div and idiv divide the combined rdx:rax value. Clear rdx for a positive unsigned-sized dividend; use cqo before signed 64-bit division when rax may be negative.

Division needs a prepared dividend source/chapters/arith.asm
    xor rdx, rdx
    mov rax, 100
    mov rcx, 2
    idiv rcx

Keep in mind: After division, rax holds the quotient and rdx holds the remainder.

Bits are data too

and masks bits, or sets them, and xor toggles them. XORing a register with itself is the standard compact way to produce zero.

Bits are data too source/chapters/arith.asm
    xor rcx, rcx
    xor rdx, rdx
    mov rcx, 0101b
    mov rdx, 0011b
    xor rcx, rdx
    and rcx, rdx
    or rcx, rdx

Keep in mind: Think of masks as small yes/no filters applied independently to every bit.

Keep these rules

  • Arithmetic writes the destination and updates flags.
  • Multiply and divide have implicit rax/rdx conventions.
  • Prepare the high half of a dividend before div or idiv.