Assembly

Instructions

These notes target Linux on x86-64 (AMD64), using Intel syntax with the GNU assembler (as). Keep in mind that assembler syntax and directives may differ when using another assembler, such as NASM, or when targeting a different CPU architecture.

Instruction C / pseudocode equivalent Meaning
Data movement and address calculation
mov rax, 0x539 rax = 0x539 Copy the constant value 0x539 into rax, replacing its previous value. A value written directly in the instruction is called an immediate value.
movabs rax, 0x1122334455667788 rax = 0x1122334455667788 Copy a full 64-bit constant into rax. movabs tells the assembler to use an instruction encoding that can contain a complete 64-bit immediate value.
mov rbx, rax rbx = rax Copy the value in rax into rbx. The original value in rax is not changed.
mov rax, [rsi] rax = *(uint64_t *)rsi Treat rsi as a memory address and load the 8 bytes stored at that address into rax. The square brackets mean "access the memory at this address". The value in memory is not changed.
mov [rdi], rax *(uint64_t *)rdi = rax Treat rdi as a memory address and store the 8-byte value from rax at that address. The value in rax is not changed.
movzx eax, BYTE PTR [rsi] eax = (uint32_t)*(uint8_t *)rsi Load one byte from the memory address in rsi and place it in eax. The remaining bits are filled with zeros, so the byte is treated as an unsigned value. For example, 0xff becomes 0x000000ff.
movsx eax, BYTE PTR [rsi] eax = (int32_t)*(int8_t *)rsi Load one byte from the memory address in rsi and sign-extend it to 32 bits. The byte is treated as a signed two's-complement value. Its sign bit is copied into the new upper bits, so 0xff, meaning −1 as an int8_t, becomes 0xffffffff.
movsxd rax, eax rax = (int64_t)(int32_t)eax Interpret eax as a signed 32-bit value and copy it into rax as a signed 64-bit value. The sign bit of eax is copied into the upper 32 bits. For example, 0xffffffff becomes 0xffffffffffffffff, preserving the value −1.
bswap rax rax = __builtin_bswap64(rax) Reverse the order of the bytes in rax. The bits inside each individual byte stay in the same order, only the positions of the eight bytes are reversed. For example, 0x1122334455667788 becomes 0x8877665544332211. This is commonly used when converting between little-endian and big-endian byte order, such as when reading or writing binary file formats or network data.
movbe rax, QWORD PTR [rsi]
movbe QWORD PTR [rdi], rax
rax = byteswap64(*(uint64_t *)rsi)
*(uint64_t *)rdi = byteswap64(rax)
Load or store an integer while reversing its byte order. The load form reads memory and byte-swaps the value before placing it in the register. The store form byte-swaps the register value before writing it. This combines a memory access with behavior similar to bswap and is useful for big-endian binary data. The CPU must support MOVBE.
lea rbx, [rsp + rax*8] rbx = rsp + rax * 8 Calculate rsp + rax * 8 and store the result in rbx. Despite the square brackets, lea does not access memory. It only calculates the address. This is useful for pointer arithmetic and locating an element in an array of 8-byte values.
lea rdi, [rip + message] rdi = &message Calculate the memory address of message and place that address in rdi. Using rip makes the address relative to the current instruction, which is commonly used to access static data in position-independent programs.
cbw
cwde
cdqe
ax = (int16_t)(int8_t)al
eax = (int32_t)(int16_t)ax
rax = (int64_t)(int32_t)eax
Sign-extend a signed value in the accumulator to the next larger accumulator register. cbw sign-extends al into ax. cwde sign-extends ax into eax. cdqe sign-extends eax into rax The original sign bit is copied into all newly added high bits, preserving the signed two's-complement value. These instructions have no explicit operands and do not change the status flags.
xlatb al = *(uint8_t *)(rbx + al) Use the unsigned value in al as an index into a 256-byte lookup table beginning at the address in rbx. Replace al with the selected table byte. This is an old but still valid compact table-lookup instruction.
Arithmetic
add rax, rbx rax = rax + rbx Add the value in rbx to rax and store the result in rax. rbx is not changed. The arithmetic flags are updated based on the result.
sub ebx, ecx ebx = ebx - ecx Subtract the value in ecx from ebx and store the result in ebx. ecx is not changed. The arithmetic flags are updated based on the result.
inc rdx rdx++ Increase rdx by 1. This is similar to add rdx, 1, but inc does not change CF, the Carry Flag. It does update other arithmetic flags such as ZF, SF and OF.
dec rdx rdx-- Decrease rdx by 1. This is similar to sub rdx, 1, but dec does not change CF, the Carry Flag. It does update other arithmetic flags such as ZF, SF and OF.
neg rax rax = 0 - rax Change the arithmetic sign of rax using two's-complement negation. For example, 5 becomes −5, −5 becomes 5 and 0 remains 0.
mul rbx rdx:rax = rax * rbx Multiply rax by rbx, treating both values as unsigned. The complete 128-bit result is split between two registers: rax receives the low 64 bits and rdx receives the high 64 bits. The original values in both destination registers are replaced.
imul rbx rdx:rax = (signed) rax * (signed) rbx Multiply rax by rbx, treating both values as signed. The complete 128-bit result is split between two registers: rax receives the low 64 bits and rdx receives the high 64 bits.
imul rax, rbx rax = rax * rbx Multiply the current value in rax by rbx, treating the values as signed, and store the low 64 bits of the result in rax. rbx is not changed. Any part of the result above 64 bits is discarded.
imul rax, rbx, 10 rax = rbx * 10 Multiply rbx by the immediate value 10, treating the values as signed, and store the low 64 bits of the result in rax. Because the destination is separate, the original value in rbx is not changed.
cwd
cdq
cqo
dx:ax = sign_extend(ax)
edx:eax = sign_extend(eax)
rdx:rax = sign_extend(rax)
Sign-extend the value in ax, eax or rax into a double-width value. The original register becomes the low half, while the corresponding high register is filled with copies of the sign bit:
  • cwd sign-extends ax into dx:ax
  • cdq sign-extends eax into edx:eax
  • cqo sign-extends rax into rdx:rax
If the original value is non-negative, the high register is filled with zeros. If it is negative, the high register is filled with ones. These instructions are commonly used before a signed idiv instruction.
div ecx eax = edx:eax / ecx
edx = edx:eax % ecx
Treat edx:eax as one unsigned 64-bit dividend and divide it by ecx. The quotient is stored in eax and the remainder is stored in edx. When dividing an ordinary 32-bit unsigned value from eax, first use xor edx, edx to clear the upper half of the dividend.
idiv rcx rax = (signed) rdx:rax / rcx
rdx = (signed) rdx:rax % rcx
Treat rdx:rax as one signed 128-bit dividend and divide it by rcx. The quotient is stored in rax and the remainder is stored in rdx. When dividing a signed 64-bit value from rax, first use cqo to sign-extend it into rdx:rax.
adc rax, rbx rax = rax + rbx + CF Add rbx and the current Carry Flag to rax. CF contributes either 0 or 1. This allows a carry from an earlier add or adc instruction to be included when adding integers that are wider than one register.
sbb rax, rbx rax = rax - rbx - CF Subtract rbx and the current Carry Flag from rax. During subtraction, CF represents a borrow from an earlier sub or sbb instruction. This is useful for subtracting integers that are wider than one register.
clc CF = 0 Clear CF, the Carry Flag, by setting it to 0. This is useful before beginning an adc or adcx carry chain when there is no initial carry to include. Other status flags are not changed.
stc CF = 1 Set CF, the Carry Flag, to 1. A following adc, sbb or adcx will therefore include an initial carry or borrow of 1. Other status flags are not changed.
cmc CF = !CF Complement, or toggle, CF. If CF was 0 it becomes 1, and if it was 1 it becomes 0. Other status flags are not changed.
adcx rax, rbx sum = (uint128_t)rax + rbx + CF
rax = (uint64_t)sum
CF = sum >> 64
Add rbx and the current Carry Flag to rax. Store the low 64 bits in rax and place the carry-out in CF. Unlike ordinary adc, adcx leaves OF unchanged. This allows it to run alongside a separate adox carry chain. The CPU must support the ADX instruction-set extension.
adox rax, rbx sum = (uint128_t)rax + rbx + OF
rax = (uint64_t)sum
OF = sum >> 64
Add rbx and the current Overflow Flag to rax. Store the low 64 bits in rax and place the carry-out in OF. adox uses OF as an unsigned carry flag and leaves CF unchanged. Together, adcx and adox allow two independent carry chains, which is useful for large-integer arithmetic and cryptography. The CPU must support ADX.
Bitwise operations, shifts and rotates
not rax rax = ~rax Invert every bit in rax: each 0 becomes 1 and each 1 becomes 0. For example, the 8-bit value 00001111 would become 11110000.
and rax, rbx rax = rax & rbx Perform a bitwise AND between rax and rbx, storing the result in rax. A result bit is 1 only when the corresponding bit is 1 in both values. This is commonly used to keep selected bits and clear the others.
or rax, rbx rax = rax | rbx Perform a bitwise OR between rax and rbx, storing the result in rax. A result bit is 1 when the corresponding bit is 1 in either value. This is commonly used to turn selected bits on.
xor rcx, rdx rcx = rcx ^ rdx Perform a bitwise XOR between rcx and rdx, storing the result in rcx. A result bit is 1 when the two corresponding bits are different. XORing a register with itself, such as xor rcx, rcx, efficiently sets it to zero. In C, ^ means XOR, not exponentiation.
bsf rax, rbx rax = index_of_lowest_set_bit(rbx) Find the position of the lowest bit in rbx that is set to 1, counting from the least significant bit. The bit positions start at 0. For example, if rbx contains 00101000, the lowest set bit is at position 3, so rax becomes 3. If the source is zero, ZF is set to 1 and the destination value is undefined, so the program must check ZF before using it.
bsr rax, rbx rax = index_of_highest_set_bit(rbx) Find the position of the highest bit in rbx that is set to 1, counting from the least significant bit. The bit positions start at 0. For example, if rbx contains 00101000, the highest set bit is at position 5, so rax becomes 5. If the source is zero, ZF is set to 1 and the destination value is undefined, so the program must check ZF before using it.
popcnt rax, rbx rax = number_of_set_bits(rbx) Count how many bits in rbx are set to 1 and store the count in rax. For example, 00101101 contains four 1 bits, so the result is 4. This is also known as the population count or Hamming weight. If the source is zero, the result is zero.
tzcnt rax, rbx rax = count_trailing_zeros(rbx) Count the consecutive zero bits at the low, or least significant, end of rbx. For example, 00101000 ends in three zero bits, so the result is 3. This also gives the position of the lowest set bit when the source is not zero. Unlike bsf, a zero source has a defined result: it produces the operand size, such as 64 for a 64-bit register.
lzcnt rax, rbx rax = count_leading_zeros(rbx) Count the consecutive zero bits at the high, or most significant, end of rbx. For example, the 8-bit value 00101000 begins with two zero bits, so an 8-bit leading-zero count would produce 2. With lzcnt rax, rbx, all 64 bits of rbx are counted. Unlike bsr, a zero source has a defined result: it produces the operand size, such as 64 for a 64-bit register.
bt rax, rbx CF = (rax >> (rbx & 63)) & 1 Test one bit in rax without changing rax. rbx selects which bit to test, with bit 0 being the least significant bit. The selected bit is copied into CF, the Carry Flag: CF becomes 1 if the bit was set, or 0 if it was clear. For a 64-bit register, only the lowest 6 bits of the bit index are used, so the selected position is effectively rbx % 64.
bts rax, rbx CF = (rax >> (rbx & 63)) & 1
rax |= 1ULL << (rbx & 63)
Test one bit in rax, then set that bit to 1. The bit's original value is copied into CF before the bit is changed. This allows the program to determine whether the bit was already set. rbx selects the bit position, counting from bit 0 at the least significant end.
btr rax, rbx CF = (rax >> (rbx & 63)) & 1
rax &= ~(1ULL << (rbx & 63))
Test one bit in rax, then reset that bit to 0. The bit's original value is copied into CF before the bit is cleared. This allows the program to determine whether the bit was previously set. rbx selects the bit position, counting from bit 0 at the least significant end.
btc rax, rbx CF = (rax >> (rbx & 63)) & 1
rax ^= 1ULL << (rbx & 63)
Test one bit in rax, then complement, or toggle, that bit. The bit's original value is copied into CF before it is changed. A bit containing 0 becomes 1, while a bit containing 1 becomes 0. rbx selects the bit position, counting from bit 0 at the least significant end.
shl rax, 10 rax = rax << 10 Move every bit in rax 10 positions to the left. Zeros are inserted into the 10 empty low-bit positions, and bits that leave the high end are discarded. When no important bits are lost, shifting left by 10 is equivalent to multiplying an unsigned value by 210, or 1024.
shr rax, 10 rax = (uint64_t)rax >> 10 Move every bit in rax 10 positions to the right. Zeros are inserted into the 10 empty high-bit positions, and bits that leave the low end are discarded. This is a logical shift intended for unsigned values and is equivalent to unsigned division by 1024, rounded down.
sar rax, 10 rax = (int64_t)rax >> 10 Move every bit in rax 10 positions to the right while copying the original sign bit into the empty high-bit positions. This preserves the sign of a signed two's-complement value. It is often used for division by a power of two, although rounding for negative values can differ from ordinary signed division in C.
rol rax, 10 rax = rotate_left_64(rax, 10) Rotate all 64 bits in rax 10 positions to the left. Bits that leave the high end are not discarded, they re-enter at the low end. Unlike a shift, a rotate does not permanently lose any bits.
ror rax, 10 rax = rotate_right_64(rax, 10) Rotate all 64 bits in rax 10 positions to the right. Bits that leave the low end are not discarded, they re-enter at the high end. Unlike a shift, a rotate does not permanently lose any bits.
shld rax, rbx, 8 rax = (rax << 8) | (rbx >> 56) Shift rax left by 8 bits and fill its newly empty low bits with bits taken from the high end of rbx. Bits leaving the high end of rax are discarded. rbx is not changed. This is useful when shifting a value that spans multiple registers.
shrd rax, rbx, 8 rax = (rax >> 8) | (rbx << 56) Shift rax right by 8 bits and fill its newly empty high bits with bits taken from the low end of rbx. Bits leaving the low end of rax are discarded. rbx is not changed. This is useful when shifting a value that spans multiple registers.
rcl rax, 1 CF:rax = rotate_left_65(CF:rax, 1) Rotate rax left through CF. CF acts as an extra bit beside the 64 bits in rax, producing a 65-bit rotation: the old CF enters bit 0, and the old bit 63 becomes the new CF. This can move bits between registers when processing integers wider than one register.
rcr rax, 1 CF:rax = rotate_right_65(CF:rax, 1) Rotate rax right through CF. The old CF enters bit 63, and the old bit 0 becomes the new CF. CF and rax therefore act as one 65-bit value during the rotation.
andn rax, rbx, rcx rax = (~rbx) & rcx Invert every bit in rbx, then AND the inverted value with rcx. Store the result in rax without changing either source register. Requires BMI1.
bextr rax, rbx, rcx start = rcx & 0xff
length = (rcx >> 8) & 0xff
rax = extract_bits(rbx, start, length)
Extract a consecutive range of bits from rbx and place them at the low end of rax. The low byte of rcx supplies the starting bit position, and the next byte supplies the number of bits to extract. Requires BMI1.
blsi rax, rbx rax = rbx & -rbx Isolate the lowest bit in rbx that is set to 1. Every other bit is cleared. For example, 00101100 becomes 00000100. A zero source produces zero. Requires BMI1.
blsmsk rax, rbx rax = rbx ^ (rbx - 1) Create a mask containing 1 bits from bit 0 through the lowest set bit in rbx. For example, 00101000 produces 00001111. If the source is zero, the result contains all 1 bits. Requires BMI1.
blsr rax, rbx rax = rbx & (rbx - 1) Clear the lowest set bit in rbx and copy the remaining bits into rax. For example, 00101100 becomes 00101000. Requires BMI1.
bzhi rax, rbx, rcx rax = clear_bits_at_and_above(rbx, rcx & 0xff) Copy rbx into rax, but clear every bit at or above the position selected by the low byte of rcx. If the position is at least 64, the source is copied unchanged and CF is set. Requires BMI2.
mulx r9, r8, rbx r9:r8 = (uint128_t)rdx * rbx Multiply the unsigned value in the implicit rdx register by rbx. Store the high 64 bits in r9 and the low 64 bits in r8. Unlike mul, the destination registers are explicit and no status flags are changed. Requires BMI2.
pdep rax, rbx, rcx rax = deposit_bits(rbx, rcx) Take consecutive low bits from rbx and deposit them into the bit positions where rcx contains 1 bits. Positions not selected by the mask become zero. This is sometimes described as scattering bits. Requires BMI2.
pext rax, rbx, rcx rax = extract_masked_bits(rbx, rcx) Extract the bits from rbx whose positions are selected by 1 bits in rcx. Pack the extracted bits consecutively into the low end of rax. This is sometimes described as gathering bits. Requires BMI2.
rorx rax, rbx, 13 rax = rotate_right_64(rbx, 13) Rotate rbx right by 13 bits and store the result in rax. Bits leaving the low end re-enter at the high end. Unlike ror, this instruction does not change any status flags. Requires BMI2.
sarx rax, rbx, rcx rax = (int64_t)rbx >> (rcx & 63) Perform a variable arithmetic right shift of rbx, using rcx as the shift count. The sign bit is copied into the new high positions. Unlike sar, no status flags are changed. Requires BMI2.
shlx rax, rbx, rcx rax = rbx << (rcx & 63) Shift rbx left by the count in rcx, inserting zeros at the low end. Store the result in a separate destination without changing the status flags. Requires BMI2.
shrx rax, rbx, rcx rax = (uint64_t)rbx >> (rcx & 63) Shift rbx logically right by the count in rcx, inserting zeros at the high end. Store the result in a separate destination without changing the status flags. Requires BMI2.
Stack, control, comparison and system instructions
push rax rsp -= 8
*(uint64_t *)rsp = rax
Put the 64-bit value in rax on top of the stack. Because the stack grows toward lower memory addresses, rsp is first decreased by 8. The value is then stored at the new address in rsp.
pop rax rax = *(uint64_t *)rsp
rsp += 8
Remove the 64-bit value from the top of the stack and copy it into rax. The value at [rsp] is loaded first, and rsp is then increased by 8 to move past it.
cmp rax, rbx flags = rax - rbx Compare rax with rbx. The CPU acts as though it subtracts rbx from rax, but it does not save the result. It only updates flags such as ZF, SF, CF and OF, which can then be checked by a conditional jump or setcc instruction.
test rax, rax flags = rax & rax Check properties of rax without changing it. The CPU performs a bitwise AND only to update the flags and discards the result. Testing a register against itself is commonly used to check whether it is zero: ZF becomes 1 when rax == 0.
setz dil dil = (ZF == 1) ? 1 : 0 Store the result of an equality or zero check in dil. Write 1 when the zero flag is set, or 0 when it is not set. This is commonly used after cmp or test.
cmovcc dest, source
cmove rax, rbx
if (rax == compared_value) rax = rbx Conditionally copy the source value into the destination register. The cc part is replaced by a condition-code suffix that specifies which flags to check. If the condition is true, the source is copied into the destination. If the condition is false, the destination remains unchanged. For example, after a comparison: cmove rax, rbx copies rbx into rax when the compared values were equal. Conditional moves can sometimes replace a short if statement without using a branch. They do not change the flags. All condition codes can be found here: https://www.felixcloutier.com/x86/cmovcc
setcc destination
sete al
al = condition ? 1 : 0 Store the result of a condition as either 1 or 0. The cc part is replaced by a condition-code suffix that specifies which flags to check. If the condition is true, the destination byte becomes 1. Otherwise, it becomes 0. For example, after cmp rax, rbx, sete al sets al to 1 when rax == rbx, or to 0 when they are not equal. The destination must be an 8-bit register or a byte-sized memory location. setcc does not change the flags. All condition codes can be found here: https://www.felixcloutier.com/x86/setcc
pushfq rsp -= 8
*(uint64_t *)rsp = rflags
Save the current flags register on the stack. rsp is decreased by 8, and a 64-bit copy of rflags is stored at [rsp]. This allows the program to preserve condition flags before executing instructions that may change them. The saved value can later be restored using popfq. Some special internal flag bits are not saved exactly as they appear in the live flags register.
popfq rflags = *(uint64_t *)rsp
rsp += 8
Restore flags from a 64-bit value on top of the stack. The value at [rsp] is loaded into rflags, and rsp is then increased by 8. This is commonly paired with pushfq. In normal user-space programs, some privileged or reserved flags cannot be changed, so popfq may not restore every bit supplied by the stack value.
lahf ah = flags_to_byte(SF, ZF, AF, PF, CF) Copy several commonly used status flags into ah, the high byte of ax. The following flags are copied: SF (Sign Flag), ZF (Zero Flag), AF (Auxiliary Carry Flag), PF (Parity Flag) and CF (Carry Flag) . The resulting byte has this layout: SF:ZF:0:AF:0:PF:1:CF. This provides a compact way to save these flags in a register without using the stack. It does not copy OF, the Overflow Flag.
sahf flags_from_byte(SF, ZF, AF, PF, CF) = ah Copy selected bits from ah into the status flags. It restores the following flags: SF (Sign Flag), ZF (Zero Flag), AF (Auxiliary Carry Flag), PF (Parity Flag) and CF (Carry Flag) Other bits in ah are ignored. Like lahf, sahf does not handle OF, the Overflow Flag. It can be used to restore status flags previously saved with lahf .
jmp label goto label Continue execution at label, regardless of the current flag values. Unlike a conditional jump, jmp always jumps.
call target target() Call a function or subroutine named target. The address of the instruction immediately after call is pushed onto the stack as the return address. Execution then jumps to target.
ret return Return from the current function by popping the return address from the stack into rip. The function's return value is not handled by ret itself. Integer and pointer return values are normally placed in rax before executing ret.
leave rsp = rbp
rbp = *(uint64_t *)rsp
rsp += 8
Remove the current function's stack frame and restore the caller's rbp value. It is approximately equivalent to: mov rsp, rbp followed by pop rbp. First, rsp is restored to the value in rbp, discarding any local stack space used by the function. The old frame pointer is then popped from the stack into rbp. It is commonly placed directly before ret in a function epilogue.
enter 32, 0 push(rbp)
rbp = rsp
rsp -= 32
Create a stack frame and reserve space for local variables. The first immediate selects the number of local-stack bytes, while the second selects a nesting level for language features using nested procedure scopes. With a nesting level of 0, it is approximately equivalent to push rbp, mov rbp, rsp and sub rsp, 32. Modern compilers usually prefer the separate instructions.
syscall syscall(rax, rdi, rsi, rdx, r10, r8, r9) Ask the Linux kernel to perform an operating-system service, such as reading, writing, opening a file or exiting the program. Before executing syscall, place the syscall number in rax and its arguments in rdi, rsi, rdx, r10, r8 and r9. The return value is placed in rax.
sysretq rip = rcx
rflags = r11
return_to_user_mode()
Return from a 64-bit operating-system system-call handler to less-privileged code. It is the kernel-side companion commonly used with syscall. The return instruction address is taken from rcx, and the user flags are restored from r11. User code and stack segment selectors are derived from model-specific register configuration. sysretq does not restore rsp. The kernel must arrange the intended user stack pointer separately before returning. This is a privileged operating-system instruction.
sysenter cs = IA32_SYSENTER_CS
instruction_pointer = IA32_SYSENTER_EIP
stack_pointer = IA32_SYSENTER_ESP
Enter an operating-system system-call handler using entry addresses configured in the IA32_SYSENTER_* model-specific registers. Unlike an ordinary call, sysenter does not push a return address and does not automatically preserve the user's stack pointer. The operating-system calling convention must arrange the information needed for returning. This mechanism is primarily associated with fast 32-bit system calls. Modern 64-bit Linux normally uses syscall instead.
sysexit user_instruction_pointer = edx
user_stack_pointer = ecx
return_to_user_mode()
Return from a handler entered through sysenter. In its traditional 32-bit use, the user instruction pointer is taken from edx and the user stack pointer is taken from ecx. Segment selectors are derived from the configured SYSENTER code-segment value. A 64-bit operand-size form uses the corresponding 64-bit registers. This is a privileged kernel-side instruction. It does not behave like an ordinary ret and does not pop a return address.
int3 raise(SIGTRAP) Deliberately trigger a breakpoint exception. When the program is running inside a debugger such as GDB, the debugger normally pauses the program at this instruction so that registers and memory can be examined.
nop (void)0 Perform no useful operation and continue with the next instruction. It is commonly used for padding, instruction alignment, reserving space for a later patch or temporarily replacing another instruction.
ud2 __builtin_trap() Deliberately execute an instruction that is defined to be invalid. This immediately raises an invalid-opcode exception. On Linux, the program will normally receive SIGILL and terminate unless the signal is handled. Compilers use this to mark code that should never be reached.
loop label rcx--;
if (rcx != 0) goto label;
Decrease rcx by 1, then jump to label if rcx is not zero. This combines updating a loop counter and performing a conditional jump in one instruction. The counter is decreased before it is checked, so an initial value of 5 allows the loop body to repeat five times when the instruction is placed at the end of the loop. Unlike dec rcx, loop does not change any status flags.
loope label
loopz label
rcx--;
if (rcx != 0 && ZF == 1) goto label;
Decrease rcx by 1, then jump when rcx is not zero and ZF, the Zero Flag, is 1. ZF must have been set by an earlier instruction such as cmp, test or an arithmetic instruction. loope itself checks ZF but does not change it. loope means “loop while equal”, while loopz means “loop while zero”. They are two names for exactly the same instruction.
loopne label
loopnz label
rcx--;
if (rcx != 0 && ZF == 0) goto label;
Decrease rcx by 1, then jump when rcx is not zero and ZF, the Zero Flag, is 0. ZF must have been set by an earlier instruction such as cmp, test or an arithmetic instruction. loopne itself checks ZF but does not change it. loopne means “loop while not equal”, while loopnz means “loop while not zero”. They are two names for exactly the same instruction.
jrcxz label
jecxz label
if (rcx == 0) goto label
if (ecx == 0) goto label
Jump when the selected counter register is already zero. jrcxz tests the full 64-bit rcx. jecxz tests the low 32-bit ecx. Unlike loop, these instructions do not decrease the counter first. They do not read or change any status flags.
Conditional jumps
je label
jz label
if (rax == rbx) goto label Jump when the compared values were equal, or when the previous result was zero. Both instructions do exactly the same thing: they jump when ZF, the Zero Flag, is 1. je means "jump if equal", while jz means "jump if zero".
jne label
jnz label
if (rax != rbx) goto label Jump when the compared values were not equal, or when the previous result was not zero. Both instructions jump when ZF, the Zero Flag, is 0. jne means "jump if not equal", while jnz means "jump if not zero".
jg label
jnle label
if ((int64_t)rax > (int64_t)rbx) goto label Perform a signed greater-than comparison. After cmp rax, rbx, jump when rax is greater than rbx, treating both values as signed integers. The jump is taken when ZF is 0 and SF equals OF.
jge label
jnl label
if ((int64_t)rax >= (int64_t)rbx) goto label Perform a signed greater-than-or-equal comparison. After cmp rax, rbx, jump when rax is greater than or equal to rbx, treating both values as signed integers. The jump is taken when SF equals OF.
jl label
jnge label
if ((int64_t)rax < (int64_t)rbx) goto label Perform a signed less-than comparison. After cmp rax, rbx, jump when rax is less than rbx, treating both values as signed integers. The jump is taken when SF does not equal OF.
jle label
jng label
if ((int64_t)rax <= (int64_t)rbx) goto label Perform a signed less-than-or-equal comparison. After cmp rax, rbx, jump when rax is less than or equal to rbx, treating both values as signed integers. The jump is taken when ZF is 1 or SF does not equal OF.
ja label
jnbe label
if ((uint64_t)rax > (uint64_t)rbx) goto label Perform an unsigned greater-than comparison. After cmp rax, rbx, jump when rax is above rbx, treating both values as unsigned integers. The jump is taken when CF is 0 and ZF is 0.
jae label
jnb label
jnc label
if ((uint64_t)rax >= (uint64_t)rbx) goto label Perform an unsigned greater-than-or-equal comparison. After cmp rax, rbx, jump when rax is above or equal to rbx. All three instructions jump when CF, the Carry Flag, is 0. jnc can also mean "jump if no carry" after an arithmetic instruction.
jb label
jnae label
jc label
if ((uint64_t)rax < (uint64_t)rbx) goto label Perform an unsigned less-than comparison. After cmp rax, rbx, jump when rax is below rbx. All three instructions jump when CF, the Carry Flag, is 1. jc can also mean "jump if carry" after an arithmetic instruction.
jbe label
jna label
if ((uint64_t)rax <= (uint64_t)rbx) goto label Perform an unsigned less-than-or-equal comparison. After cmp rax, rbx, jump when rax is below or equal to rbx, treating both values as unsigned integers. The jump is taken when CF is 1 or ZF is 1.
js label if (SF == 1) goto label Jump when SF, the Sign Flag, is 1. This means the most significant bit of the previous result was 1, which usually indicates a negative result when it is interpreted as a signed integer.
jns label if (SF == 0) goto label Jump when SF, the Sign Flag, is 0. This means the most significant bit of the previous result was 0, which usually indicates a non-negative result when interpreted as a signed integer.
jo label if (OF == 1) goto label Jump when OF, the Overflow Flag, is 1. This indicates that the previous signed arithmetic result was too large or too small to fit in the destination operand.
jno label if (OF == 0) goto label Jump when OF, the Overflow Flag, is 0. This means the previous signed arithmetic operation did not overflow the size of its destination operand.
Atomic operations and synchronization
xchg QWORD PTR [rdi], rax temporary = *(uint64_t *)rdi
*(uint64_t *)rdi = rax
rax = temporary
Exchange, or swap, the two operand values. The original value from the memory address in rdi is loaded into rax, while the original value from rax is stored in memory. When one operand is a memory location, xchg performs the exchange atomically, even when the lock prefix is not written. This means another CPU core cannot observe or modify the memory value halfway through the exchange. xchg can also exchange two registers, but a register-to-register exchange does not involve shared memory.
xadd QWORD PTR [rdi], rax temporary = *(uint64_t *)rdi
*(uint64_t *)rdi += rax
rax = temporary
Exchange the source with the destination, then add the original source value to the destination. In this example, the original value from [rdi] is copied into rax. The memory location is then replaced with the sum of its original value and the original value from rax. This is useful when a program needs both the old value and the newly increased value, such as when implementing an atomic counter. A memory form of xadd is not automatically atomic. Prefix it with lock when multiple threads or CPU cores may access the same memory.
cmpxchg rbx, rcx if (rax == rbx) {
    rbx = rcx;
    ZF = 1;
} else {
    rax = rbx;
    ZF = 0;
}
Compare the destination value in rbx with the expected value in rax. If they are equal, copy the replacement value from rcx into rbx and set ZF to 1. If they are not equal, leave rbx unchanged, copy its current value into rax and clear ZF to 0. Despite the operand order, cmpxchg compares the accumulator with the destination, the second operand contains the proposed replacement value. The accumulator is al, ax, eax or rax, depending on the operand size. When the destination is in memory, add the lock prefix when the operation must be atomic between threads or CPU cores.
cmpxchg8b QWORD PTR [rdi] if (*(uint64_t *)rdi == edx:eax) {
    *(uint64_t *)rdi = ecx:ebx;
    ZF = 1;
} else {
    edx:eax = *(uint64_t *)rdi;
    ZF = 0;
}
Perform a compare-and-exchange operation on an 8-byte value in memory. Compare the 64-bit value at [rdi] with the expected value in edx:eax. Here, edx contains the high 32 bits and eax contains the low 32 bits. If the values are equal, store the replacement value from ecx:ebx in memory and set ZF to 1. If they are not equal, leave memory unchanged, load its current value into edx:eax and clear ZF to 0. The operand must be a memory location, there is no register-destination form. Use lock cmpxchg8b when the operation must be atomic between threads or CPU cores.
cmpxchg16b XMMWORD PTR [rdi] if (*(uint128_t *)rdi == rdx:rax) {
    *(uint128_t *)rdi = rcx:rbx;
    ZF = 1;
} else {
    rdx:rax = *(uint128_t *)rdi;
    ZF = 0;
}
Perform a compare-and-exchange operation on a 16-byte value in memory. Compare the 128-bit value at [rdi] with the expected value in rdx:rax. Here, rdx contains the high 64 bits and rax contains the low 64 bits. If the values are equal, store the replacement value from rcx:rbx in memory and set ZF to 1. If they are not equal, leave memory unchanged, load its current value into rdx:rax and clear ZF to 0. The operand must be a 16-byte-aligned memory location, there is no register-destination form. The CPU must support the CMPXCHG16B, or CX16, feature. Use lock cmpxchg16b when the operation must be atomic between threads or CPU cores.
lock add QWORD PTR [rdi], 1 atomic_fetch_add((_Atomic uint64_t *)rdi, 1) Perform the following read-modify-write instruction atomically on memory. In this example, the value at [rdi] is read, increased by 1 and written back as one indivisible operation. Another CPU core cannot modify that memory value between the read and the write. lock is an instruction prefix, not a standalone instruction. It can only be used with supported instructions that modify memory, such as add, xadd, cmpxchg, bts, btr and btc. It cannot make a whole sequence of several instructions atomic, it only applies to the single instruction that follows it.
pause _mm_pause() Tell the CPU that the program is temporarily waiting inside a spin-wait loop. It does not pause the program for a specific amount of time. Instead, it helps the CPU use its execution resources more efficiently while repeatedly checking a condition.
lfence _mm_lfence() Create a load fence. Loads before the fence must complete before loads after the fence are allowed to proceed. This prevents later memory reads from passing earlier memory reads when ordering is important. lfence is used when a program must ensure that earlier reads have happened before it performs later reads. It does not make the reads atomic and does not protect a shared value by itself.
sfence _mm_sfence() Create a store fence. Stores before the fence must become visible before stores after the fence become visible. This prevents later memory writes from passing earlier memory writes when ordering is important. It is especially useful after non-temporal, or streaming, stores, which use weaker ordering rules than ordinary cached stores. It does not make several writes into one atomic operation.
mfence _mm_mfence() Create a full memory fence for loads and stores. Memory reads and writes before the fence must be ordered before memory reads and writes after the fence. It is stronger than lfence or sfence because it orders both kinds of memory access. This is useful when threads or CPU cores communicate through shared memory and both reads and writes must occur in a specific order. A memory fence controls ordering and visibility, but it does not by itself make a group of instructions atomic.
String and block-processing instructions
cld DF = 0 Clear DF, the Direction Flag. After cld, string instructions process memory from lower addresses toward higher addresses: rsi and rdi are increased after each element. This is the usual direction for copying, filling, comparing and searching memory. For byte instructions such as movsb, the registers increase by 1 after every byte.
std DF = 1 Set DF, the Direction Flag. After std, string instructions process memory from higher addresses toward lower addresses: rsi and rdi are decreased after each element. This is useful when data must be processed backward, such as during some overlapping memory copies. Code should normally execute cld afterward when forward processing is needed again.
rep movsb while (rcx != 0) {
    *(uint8_t *)rdi = *(uint8_t *)rsi;
    rsi += DF ? -1 : 1;
    rdi += DF ? -1 : 1;
    rcx--;
}
Copy rcx bytes from the memory address in rsi to the memory address in rdi. One byte is copied during each repetition. After every byte, rsi and rdi move by one byte, and rcx is decreased by 1. When DF is 0, the addresses increase. When DF is 1, the addresses decrease. The instruction stops when rcx reaches 0. This is similar to memcpy() when the source and destination regions do not overlap. Handling overlap correctly requires choosing the appropriate direction.
rep stosb while (rcx != 0) {
    *(uint8_t *)rdi = al;
    rdi += DF ? -1 : 1;
    rcx--;
}
Fill rcx bytes of memory with the byte value stored in al. During each repetition, al is stored at [rdi]. Then rdi moves by one byte and rcx is decreased by 1. When DF is 0, rdi increases. When DF is 1, it decreases. The instruction stops when rcx reaches 0. With DF clear, this is similar to memset(rdi, al, rcx).
repe cmpsb
repz cmpsb
while (rcx != 0) {
    flags = *(uint8_t *)rsi - *(uint8_t *)rdi;
    rsi += DF ? -1 : 1;
    rdi += DF ? -1 : 1;
    rcx--;
    if (ZF == 0) break;
}
Compare two sequences of bytes while their corresponding bytes are equal. During each repetition, compare the byte at [rsi] with the byte at [rdi]. The flags are set as if [rsi] - [rdi] had been calculated, but the subtraction result is discarded. After each comparison, rsi and rdi move by one byte, and rcx is decreased by 1. Repetition stops when either rcx reaches 0, or the compared bytes differ, making ZF equal to 0. When a difference is found, the flags describe the final pair of bytes that were compared. The pointer registers have already moved past those bytes. repe and repz are two names for the same prefix: repeat while ZF is 1.
repne scasb
repnz scasb
while (rcx != 0) {
    flags = al - *(uint8_t *)rdi;
    rdi += DF ? -1 : 1;
    rcx--;
    if (ZF == 1) break;
}
Search through a sequence of bytes for the byte value stored in al. During each repetition, compare al with the byte at [rdi]. The flags are set as if al - [rdi] had been calculated, but the subtraction result is discarded. After each comparison, rdi moves by one byte and rcx is decreased by 1. Repetition stops when either: rcx reaches 0, or a matching byte is found, making ZF equal to 1. With DF equal to 0, rdi points one byte past the matching byte when the search succeeds. The matching byte is therefore at [rdi - 1]. repne and repnz are two names for the same prefix: repeat while ZF is 0.
Random-number generation and cryptographic instructions
rdrand rax success = _rdrand64_step(&rax) Request a 64-bit random value from the processor's hardware-backed random-number generator. If a value is available, it is written to rax and CF, the Carry Flag, becomes 1. If no value is currently available, CF becomes 0 and the instruction should be retried or another random source should be used. Always check CF rather than checking whether rax is zero, because zero is itself a valid random value. The destination may be a 16-, 32- or 64-bit register. The CPU must support the RDRAND feature.
rdseed rax success = _rdseed64_step(&rax) Request a 64-bit hardware-generated seed value intended for seeding a software PRNG or DRBG. If a seed is available, it is written to rax and CF becomes 1. If no seed is currently available, CF becomes 0 and the instruction should be retried or another entropy source should be used. rdseed obtains fresh seed material more slowly than rdrand produces ordinary random output, so temporary failure is more common. Always check CF. The destination may be a 16-, 32- or 64-bit register, and the CPU must support the RDSEED feature.
aesenc xmm0, xmm1 xmm0 = _mm_aesenc_si128(xmm0, xmm1) Perform one normal, non-final AES encryption round. xmm0 contains the current 128-bit AES state, while xmm1 contains the round key. The result replaces xmm0. The instruction performs the AES SubBytes, ShiftRows, MixColumns and AddRoundKey steps. It performs only one round, not an entire AES encryption. A complete AES operation requires an initial key addition, several aesenc rounds and one final aesenclast round.
aesenclast xmm0, xmm1 xmm0 = _mm_aesenclast_si128(xmm0, xmm1) Perform the final AES encryption round. xmm0 contains the current AES state and xmm1 contains the final round key. The result replaces xmm0. The final AES round performs SubBytes, ShiftRows and AddRoundKey, but deliberately omits MixColumns, as required by the AES algorithm.
aesdec xmm0, xmm1 xmm0 = _mm_aesdec_si128(xmm0, xmm1) Perform one normal, non-final AES decryption round. xmm0 contains the current 128-bit AES state, while xmm1 contains the corresponding decryption round key. The result replaces xmm0. The instruction performs InvShiftRows, InvSubBytes, InvMixColumns and AddRoundKey. It performs only one round, not an entire AES decryption.
aesdeclast xmm0, xmm1 xmm0 = _mm_aesdeclast_si128(xmm0, xmm1) Perform the final AES decryption round. xmm0 contains the current AES state and xmm1 contains the final decryption round key. The result replaces xmm0. The final decryption round performs InvShiftRows, InvSubBytes and AddRoundKey, but omits InvMixColumns.
aesimc xmm0, xmm1 xmm0 = _mm_aesimc_si128(xmm1) Apply the AES inverse MixColumns transformation to the 128-bit value in xmm1 and store the result in xmm0. This is normally used to transform the middle encryption round keys into the form expected by aesdec. It does not decrypt data and does not create a complete decryption key schedule by itself.
aeskeygenassist xmm0, xmm1, 0x01 xmm0 = _mm_aeskeygenassist_si128(xmm1, 0x01) Perform AES S-box, rotation and round-constant operations that assist with generating the next AES round key. xmm1 contains part of the current key schedule, while the immediate value supplies the AES round constant. Despite its name, this instruction does not generate a complete round key by itself. Its result must be combined with shifts and XOR operations as part of the AES-128, AES-192 or AES-256 key-expansion algorithm.
pclmulqdq xmm0, xmm1, 0x00 xmm0 = _mm_clmulepi64_si128(xmm0, xmm1, 0x00) Perform a carry-less multiplication of two selected 64-bit values and store the complete 128-bit result in xmm0. With immediate 0x00, the low 64 bits of xmm0 are multiplied by the low 64 bits of xmm1. Carry-less multiplication uses XOR instead of carrying between bit positions, so it is different from ordinary integer multiplication. It performs multiplication over binary polynomials and is commonly used by AES-GCM authentication, GHASH, CRC calculations and other finite-field operations. Immediate bit 0 selects the low or high 64-bit half of the first operand, while immediate bit 4 selects the low or high half of the second operand:
  • 0x00 — low × low
  • 0x01 — high × low
  • 0x10 — low × high
  • 0x11 — high × high
sha1msg1 xmm0, xmm1 xmm0 = _mm_sha1msg1_epu32(xmm0, xmm1) Perform the first stage of generating four new 32-bit words for the SHA-1 message schedule. The instruction combines words from xmm0 and xmm1 using the XOR operations required by SHA-1. This instruction does not finish the new message words by itself. Its result is normally combined with another message vector and then passed through sha1msg2.
sha1msg2 xmm0, xmm1 xmm0 = _mm_sha1msg2_epu32(xmm0, xmm1) Perform the final stage of generating four new 32-bit words for the SHA-1 message schedule. It completes the required XOR operations and one-bit left rotations, producing message words that can be used by later SHA-1 rounds. It is normally used after sha1msg1 and additional XOR processing.
sha1nexte xmm0, xmm1 xmm0 = _mm_sha1nexte_epu32(xmm0, xmm1) Calculate the SHA-1 E-state values needed for the next group of four rounds and combine them with four message words. The result replaces xmm0 and is prepared for use as an input to sha1rnds4. This is a specialized helper for arranging the SHA-1 working state. It does not calculate a complete SHA-1 digest or a complete round group by itself.
sha1rnds4 xmm0, xmm1, 0 xmm0 = _mm_sha1rnds4_epu32(xmm0, xmm1, 0) Perform four consecutive SHA-1 compression rounds. xmm0 contains four SHA-1 working variables, while xmm1 supplies four prepared message values together with the E-state contribution. The lowest two bits of the immediate select the SHA-1 Boolean function and round constant:
  • 0 — rounds 0–19
  • 1 — rounds 20–39
  • 2 — rounds 40–59
  • 3 — rounds 60–79
SHA-1 requires 80 rounds for each 64-byte block, so this instruction is used repeatedly with the message-schedule helpers.
sha256msg1 xmm0, xmm1 xmm0 = _mm_sha256msg1_epu32(xmm0, xmm1) Perform the first stage of generating four new 32-bit words for the SHA-256 message schedule. It calculates the portions involving the SHA-256 small-sigma-zero function and earlier message words. The result is an intermediate schedule value. Additional additions and sha256msg2 are needed to finish the four new message words.
sha256msg2 xmm0, xmm1 xmm0 = _mm_sha256msg2_epu32(xmm0, xmm1) Perform the final stage of generating four new 32-bit words for the SHA-256 message schedule. It incorporates the SHA-256 small-sigma-one function and the remaining earlier message words needed to complete the schedule values. It is normally used after sha256msg1 and additional packed 32-bit additions.
sha256rnds2 xmm1, xmm2 xmm1 = _mm_sha256rnds2_epu32(xmm1, xmm2, xmm0) Perform two consecutive SHA-256 compression rounds. The instruction uses the two explicit operands together with an implicit third input in xmm0. xmm0 contains two prepared values formed by adding message-schedule words to their SHA-256 round constants. The eight SHA-256 working variables are divided between the two explicit XMM registers in the specialized arrangement expected by the instruction. Because the destination is also one of the state inputs, its previous value is replaced. SHA-256 requires 64 rounds for every 64-byte block, so sha256rnds2 must be used repeatedly together with the message-schedule instructions and ordinary vector operations.
crc32 rax, rbx rax = _mm_crc32_u64(rax, rbx) Update a CRC-32C checksum using the 8-byte value in rbx. The current checksum is taken from the low 32 bits of rax. After processing the source value, the updated 32-bit checksum is stored in the low 32 bits of rax, and its upper 32 bits are cleared. Despite its name, this instruction calculates CRC-32C using the Castagnoli polynomial. It does not calculate the different CRC-32 variant commonly used by formats such as PNG and ZIP. One instruction processes only one source operand, not an entire buffer. To checksum a larger block of data, repeatedly use crc32 on consecutive bytes, words, doublewords or quadwords while carrying the checksum forward in the destination register. CRC-32C is useful for detecting accidental data corruption, but it is not a cryptographic hash and must not be used to prevent intentional modification, authenticate data or store passwords. The CPU must support the CRC32 instruction, introduced with SSE4.2.
Timing and performance measurement
rdtsc edx:eax = read_timestamp_counter() Read the processor's 64-bit Time-Stamp Counter into edx:eax. edx receives the high 32 bits and eax receives the low 32 bits. The counter is useful for low-level timing, profiling and side-channel research, but its ticks are not necessarily equal to current core clock cycles. rdtsc is not fully serializing, so nearby instructions may execute out of order around it unless fences or serialization are used.
rdtscp edx:eax = read_timestamp_counter()
ecx = IA32_TSC_AUX
Read the Time-Stamp Counter into edx:eax and copy the IA32_TSC_AUX value into ecx. The operating system may use IA32_TSC_AUX to identify the logical CPU or another execution domain, which can help detect whether a thread moved while being measured. rdtscp provides stronger ordering for earlier work than rdtsc, but it is not a complete substitute for every required fence.
serialize serialize_instruction_execution() Wait until all earlier instructions have completed and all their architectural effects are visible before later instructions begin executing. This provides strong instruction-execution serialization without using cpuid and without requiring input or output registers. It does not change registers, memory or status flags. The CPU must support the SERIALIZE feature.
Non-temporal and streaming stores
movnti QWORD PTR [rdi], rax non_temporal_store64((uint64_t *)rdi, rax) Store the 64-bit integer in rax at [rdi] using a non-temporal store hint. A non-temporal store tells the processor that the written data is unlikely to be needed again soon. This allows the processor to reduce pollution of its ordinary cache hierarchy, often by using write-combining resources. The hint does not guarantee that every cache level is bypassed. The exact behaviour depends on the processor and the memory type. Use sfence when later operations must wait until preceding non-temporal stores are globally ordered.
movntdq XMMWORD PTR [rdi], xmm0
vmovntdq XMMWORD PTR [rdi], xmm0
vmovntdq YMMWORD PTR [rdi], ymm0
stream_store_128((__m128i *)rdi, xmm0)
stream_store_256((__m256i *)rdi, ymm0)
Store 16 or 32 bytes of packed integer or raw binary data using a non-temporal store hint. The legacy XMM destination must be aligned to a 16-byte boundary. A YMM destination must be aligned to a 32-byte boundary. This is useful when producing a large output buffer that is unlikely to be read again immediately. Avoiding ordinary cache allocation can leave more cache space available for data with greater temporal locality. Use an appropriate fence when completion or ordering must be guaranteed.
movntps XMMWORD PTR [rdi], xmm0
vmovntps XMMWORD PTR [rdi], xmm0
vmovntps YMMWORD PTR [rdi], ymm0
stream_store_packed_floats(rdi, vector) Store packed 32-bit single-precision floating-point values using a non-temporal hint: an XMM register stores four floats, or 16 bytes; a YMM register stores eight floats, or 32 bytes. The XMM memory destination must be 16-byte aligned, and the YMM destination must be 32-byte aligned. Despite the floating-point mnemonic, the instruction simply copies the bits. It does not perform a floating-point calculation or conversion.
movntpd XMMWORD PTR [rdi], xmm0
vmovntpd XMMWORD PTR [rdi], xmm0
vmovntpd YMMWORD PTR [rdi], ymm0
stream_store_packed_doubles(rdi, vector) Store packed 64-bit double-precision floating-point values using a non-temporal hint: an XMM register stores two doubles; a YMM register stores four doubles. The destination must be aligned to the vector width. The instruction copies the binary data without changing it. It is intended for streaming writes where the values are not expected to be read again soon. Use sfence when later code must wait for the stores to become ordered and visible.
Cache control and prefetching
prefetcht0 [rdi] _mm_prefetch((const char *)rdi, _MM_HINT_T0) Hint that the cache line containing the memory address in rdi will be read soon and is likely to be reused. The processor is asked to bring the cache line close to the executing core, normally into all levels of the data-cache hierarchy, including L1. The instruction does not load a value into a register. The program must still perform an ordinary load later, but that load may complete faster if the prefetch finished in time. Because this is only a performance hint, the processor may ignore it, and the cache line is not guaranteed to remain cached.
prefetchnta [rdi] _mm_prefetch((const char *)rdi, _MM_HINT_NTA) Hint that the cache line containing the memory address in rdi will be read soon but probably will not be reused many times. NTA means non-temporal access. The processor is asked to fetch the data in a way that reduces pollution of the normal cache hierarchy, so frequently reused data is less likely to be displaced. This is useful when processing a large amount of data only once, such as while scanning or streaming through a large buffer. The exact cache level and treatment of the line depend on the processor. The instruction does not load a value into a register and may be ignored.
prefetchw [rdi] _m_prefetchw((void *)rdi) Hint that the cache line containing the memory address in rdi will soon be written to. The processor is asked to bring the line into cache and begin obtaining writable ownership of it. This can reduce the delay when the later store is performed, especially when another CPU core currently has a copy of the same cache line. prefetchw does not write to memory and does not change the contents of the cache line. It only prepares for a possible later write. The exact effect depends on the processor, the instruction may be ignored, and the CPU must support the PREFETCHW feature.
clflush BYTE PTR [rdi] flush_and_invalidate_cache_line(rdi) Write the cache line containing [rdi] back toward memory if it is modified, then invalidate that line from the cache hierarchy in the cache-coherence domain. The operand identifies an address within the line. Ihe instruction acts on the entire cache line rather than one byte. It is useful for persistent-memory handling, cache experiments and some side-channel techniques.
clflushopt BYTE PTR [rdi] flush_cache_line_optimized(rdi) Write back and invalidate the cache line containing [rdi], similarly to clflush. The optimized form has weaker ordering, allowing software to begin several flushes without waiting for each one individually. Use an appropriate fence, commonly sfence, when their completion must be ordered before later operations. The CPU must support CLFLUSHOPT.
clwb BYTE PTR [rdi] write_back_cache_line(rdi) Write a modified cache line back toward memory without requiring the processor to invalidate its clean cached copy. The processor may retain the line in cache for faster later access, although retaining it is a performance hint rather than a guarantee. This makes clwb useful for persistent-memory updates where the data may soon be reused. Use an appropriate fence, commonly sfence, when completion must be ordered.
Floating-point environment and control
stmxcsr DWORD PTR [rdi] *(uint32_t *)rdi = MXCSR Store the current 32-bit mxcsr control and status register at the memory address in rdi. mxcsr controls and records the behaviour of SSE, AVX and related floating-point instructions. It contains: floating-point exception status flags, exception-mask bits, the rounding-control setting, the denormals-are-zero setting, and the flush-to-zero setting. This instruction only copies the register to memory. It does not clear any exception flags and does not otherwise change mxcsr.
ldmxcsr DWORD PTR [rdi] MXCSR = *(uint32_t *)rdi Load a new 32-bit value into mxcsr from the memory address in rdi. This can change SIMD floating-point rounding, exception masks, status flags and denormal handling. For example, the rounding-control field can select: round to nearest, round down toward negative infinity, round up toward positive infinity, or truncate toward zero. Reserved bits must contain valid values. Loading a value with an unsupported reserved bit set raises a general-protection exception. Changing mxcsr affects later SIMD floating-point operations, but does not change the separate x87 control word.
Scalar floating-point instructions (SSE/SSE2)
movss xmm0, DWORD PTR [rsi]
movsd xmm0, QWORD PTR [rsi]
xmm0.f32[0] = *(float *)rsi
xmm0.f64[0] = *(double *)rsi
Load one scalar floating-point value into the low part of xmm0. movss loads one 32-bit single-precision value. movsd loads one 64-bit double-precision value. Reversing the operands stores the low value from the XMM register into memory. The operands distinguish scalar floating-point movsd from the unrelated doubleword string instruction with the same mnemonic.
addss xmm0, xmm1
addsd xmm0, xmm1
xmm0.f32[0] += xmm1.f32[0]
xmm0.f64[0] += xmm1.f64[0]
Add the low scalar floating-point values and store the result in the low element of xmm0. addss uses a 32-bit float, while addsd uses a 64-bit double. The remaining high bits of the legacy destination are preserved.
subss xmm0, xmm1
subsd xmm0, xmm1
xmm0.f32[0] -= xmm1.f32[0]
xmm0.f64[0] -= xmm1.f64[0]
Subtract the low scalar value in xmm1 from the low scalar value in xmm0. Store the result in xmm0 and preserve its remaining high elements.
mulss xmm0, xmm1
mulsd xmm0, xmm1
xmm0.f32[0] *= xmm1.f32[0]
xmm0.f64[0] *= xmm1.f64[0]
Multiply the low scalar values and store the result in the low element of xmm0. The `ss` form uses single precision, while the `sd` form uses double precision.
divss xmm0, xmm1
divsd xmm0, xmm1
xmm0.f32[0] /= xmm1.f32[0]
xmm0.f64[0] /= xmm1.f64[0]
Divide the low scalar value in xmm0 by the corresponding value in xmm1. Floating-point zero, infinity, NaN, rounding and exception behavior are controlled by IEEE-754 rules and mxcsr.
sqrtss xmm0, xmm1
sqrtsd xmm0, xmm1
xmm0.f32[0] = sqrtf(xmm1.f32[0])
xmm0.f64[0] = sqrt(xmm1.f64[0])
Calculate the square root of the low scalar value in xmm1 and store it in xmm0. The remaining high elements come from the original destination in the legacy two-operand form.
minss xmm0, xmm1
minsd xmm0, xmm1
xmm0.low = sse_min(xmm0.low, xmm1.low) Select the smaller low scalar floating-point value and store it in xmm0. The exact handling of NaNs and signed zero follows the x86 instruction rules and is not identical to C's fmin() in every case.
maxss xmm0, xmm1
maxsd xmm0, xmm1
xmm0.low = sse_max(xmm0.low, xmm1.low) Select the larger low scalar floating-point value and store it in xmm0. NaNs and signed zero follow the instruction's specific selection rules rather than exactly matching C's fmax().
ucomiss xmm0, xmm1
ucomisd xmm0, xmm1
flags = compare_floating_point(xmm0.low, xmm1.low) Compare the low scalar floating-point values and record the result in ZF, PF and CF without changing either operand. Conditional jumps such as je, jb and ja can then inspect the result. If either operand is NaN, the comparison is unordered and ZF, PF, CF all become 1.
cvtsi2ss xmm0, rax
cvtsi2sd xmm0, rax
xmm0.f32[0] = (float)(int64_t)rax
xmm0.f64[0] = (double)(int64_t)rax
Convert a signed integer into a scalar floating-point value. The result may be rounded if the integer cannot be represented exactly in the chosen floating-point format.
cvtss2si rax, xmm0
cvtsd2si rax, xmm0
rax = round_according_to_mxcsr(xmm0.low) Convert the low scalar floating-point value into a signed integer. The rounding mode selected in mxcsr determines whether the value is rounded toward nearest, zero, positive infinity or negative infinity.
cvttss2si rax, xmm0
cvttsd2si rax, xmm0
rax = (int64_t)truncate_toward_zero(xmm0.low) Convert the low scalar floating-point value into a signed integer by always truncating toward zero. Unlike the forms without the extra `t`, these instructions ignore the normal rounding-mode selection for the conversion.
cvtss2sd xmm0, xmm1
cvtsd2ss xmm0, xmm1
xmm0.f64[0] = (double)xmm1.f32[0]
xmm0.f32[0] = (float)xmm1.f64[0]
Convert between scalar single-precision and double-precision floating point. Expanding from single to double is exact. Converting from double to single may require rounding and may overflow or underflow the smaller format.
Fused multiply-add instructions (FMA3)
vfmadd132ps ymm0, ymm1, ymm2
vfmadd132pd ymm0, ymm1, ymm2
vfmadd132ss xmm0, xmm1, xmm2
vfmadd132sd xmm0, xmm1, xmm2
destination = destination * source2 + source1 Multiply the original destination by the second explicit source, then add the first explicit source: ymm0 = ymm0 * ymm2 + ymm1. The digits 132 describe the operand roles: operands 1 and 3 are multiplied, and operand 2 is added. The multiplication and addition are fused into one operation with only one final rounding step. This can be both faster and more accurate than performing a separate multiply followed by a separate add. The suffix determines the element format: ps for packed 32-bit floats, pd for packed 64-bit doubles, ss for one low 32-bit float, and sd for one low 64-bit double. The scalar forms modify only the low floating-point element. The remaining low 128-bit register contents come from the original destination. The CPU must support FMA.
vfmadd213ps ymm0, ymm1, ymm2
vfmadd213pd ymm0, ymm1, ymm2
vfmadd213ss xmm0, xmm1, xmm2
vfmadd213sd xmm0, xmm1, xmm2
destination = source1 * destination + source2 Multiply the first explicit source by the original destination, then add the second explicit source: ymm0 = ymm1 * ymm0 + ymm2. The digits 213 mean operands 2 and 1 are multiplied, and operand 3 is added. Because floating-point multiplication is commutative, the multiplication itself could also be written as destination * source1. The important difference between the three FMA forms is which operand supplies the addend and which register is overwritten. The operation performs only one final rounding step. The CPU must support FMA.
vfmadd231ps ymm0, ymm1, ymm2
vfmadd231pd ymm0, ymm1, ymm2
vfmadd231ss xmm0, xmm1, xmm2
vfmadd231sd xmm0, xmm1, xmm2
destination = source1 * source2 + destination Multiply the two explicit source operands, then add the original destination: ymm0 = ymm1 * ymm2 + ymm0. The digits 231 mean operands 2 and 3 are multiplied, and operand 1 is added. This form is especially intuitive when the destination already contains an accumulated total: sum = a * b + sum. The multiplication and addition are fused and rounded only once. The CPU must support FMA.
x87 floating-point instructions
fld QWORD PTR [rsi] x87_push((long double)*(double *)rsi) Load a floating-point value from memory and push it onto the x87 register stack. The newly loaded value becomes st(0), and the previous values move down to st(1), st(2) and so on. The x87 unit has eight logical stack registers, st(0) through st(7). Internally, x87 calculations use 80-bit extended precision. Common memory forms load 32-bit single precision, 64-bit double precision, or 80-bit extended precision.
fst QWORD PTR [rdi]
fstp QWORD PTR [rdi]
*(double *)rdi = (double)st(0)
/* fstp also performs x87_pop() */
Store the value in st(0) in memory: fst stores the value without removing it from the x87 stack; fstp stores the value and then pops the x87 stack. When storing to a smaller floating-point format, the value may need to be rounded. The x87 control word determines the rounding mode.
fadd st(0), st(1)
faddp st(1), st(0)
st(0) = st(0) + st(1)
st(1) = st(1) + st(0); x87_pop()
Add two x87 floating-point values. The non-p form stores the result without changing the x87 stack depth. The faddp form stores the result in the non-top operand and then pops the old st(0), reducing the stack depth by one.
fsub st(0), st(1)
fsubp st(1), st(0)
st(0) = st(0) - st(1)
st(1) = st(1) - st(0); x87_pop()
Subtract one x87 floating-point value from another. Operand order matters: fsub st(0), st(1) calculates st(0) - st(1). The p form pops the x87 stack after storing the result. The related fsubr and fsubrp forms reverse the subtraction order.
fmul st(0), st(1)
fmulp st(1), st(0)
st(0) = st(0) * st(1)
st(1) = st(1) * st(0); x87_pop()
Multiply two x87 floating-point values. fmulp combines the result with a stack pop, which is convenient when two operands should be replaced by one result.
fdiv st(0), st(1)
fdivp st(1), st(0)
st(0) = st(0) / st(1)
st(1) = st(1) / st(0); x87_pop()
Divide one x87 floating-point value by another. Operand order matters. The related fdivr and fdivrp forms reverse the division order. The p form pops the stack after calculating the result.
fucomi st(0), st(1)
fucomip st(0), st(1)
flags = unordered_compare(st(0), st(1))
/* fucomip also performs x87_pop() */
Compare two x87 floating-point values and store the comparison result directly in the integer flags ZF, PF and CF. This allows ordinary conditional jumps to inspect the result. The possible flag results are:
  • greater than: ZF=0, PF=0, CF=0;
  • less than: ZF=0, PF=0, CF=1;
  • equal: ZF=1, PF=0, CF=0;
  • unordered because of NaN: ZF=1, PF=1, CF=1.
fucomip pops the x87 stack after the comparison.
fnstcw WORD PTR [rdi] *(uint16_t *)rdi = X87_CONTROL_WORD Store the 16-bit x87 control word in memory. The control word contains x87 exception masks, precision control and rounding control. The leading fn means the instruction does not first wait for pending unmasked x87 exceptions. The older fstcw form performs an x87 wait before storing the value.
fldcw WORD PTR [rdi] X87_CONTROL_WORD = *(uint16_t *)rdi Load a new x87 control word from memory. This changes x87 exception masks, intermediate precision and rounding behaviour for later x87 calculations. It does not change mxcsr; x87 and SIMD floating-point state use separate control registers.
fninit
finit
reset_x87_to_default_state() Reset the x87 unit to its architectural default state. This marks all eight x87 stack registers as empty, clears x87 status information and loads the default control word. fninit performs the reset without first waiting for pending x87 exceptions. finit performs an x87 wait and then executes the initialization.
SIMD and vector instructions (SSE/SSE2 and AVX/AVX2)
movaps xmm0, XMMWORD PTR [rsi]
movups xmm0, XMMWORD PTR [rsi]
xmm0 = _mm_load_ps((const float *)rsi)
xmm0 = _mm_loadu_ps((const float *)rsi)
Copy 16 bytes commonly interpreted as four packed single-precision values. movaps requires a 16-byte-aligned memory address, while movups permits an unaligned address. Neither instruction converts the copied bits.
movapd xmm0, XMMWORD PTR [rsi]
movupd xmm0, XMMWORD PTR [rsi]
xmm0 = _mm_load_pd((const double *)rsi)
xmm0 = _mm_loadu_pd((const double *)rsi)
Copy 16 bytes commonly interpreted as two packed double-precision values. movapd requires 16-byte alignment, while movupd supports unaligned memory.
movdqa xmm0, XMMWORD PTR [rsi]
movdqu xmm0, XMMWORD PTR [rsi]
xmm0 = _mm_load_si128((const __m128i *)rsi)
xmm0 = _mm_loadu_si128((const __m128i *)rsi)
Copy 16 bytes of integer or raw binary data. movdqa requires a 16-byte-aligned memory address. movdqu allows an unaligned address. The copied bits are not converted.
movd xmm0, eax
movq xmm0, rax
xmm0.low32 = eax
xmm0.low64 = rax
Copy a 32-bit or 64-bit integer between a general-purpose register, memory and the low part of an XMM register. When loading into an XMM register, the remaining high bits are cleared. Reversing the operands copies the low integer out of the XMM register.
pxor xmm0, xmm1 xmm0 = _mm_xor_si128(xmm0, xmm1) Perform a bitwise XOR between all 128 bits in xmm0 and the corresponding bits in xmm1. Store the result in xmm0. xmm1 remains unchanged. Each result bit becomes 1 when the two corresponding input bits are different, or 0 when they are the same. XORing a register with itself clears the entire register: pxor xmm0, xmm0 sets all 128 bits of xmm0 to zero. The instruction does not update the integer status flags.
paddb xmm0, xmm1
paddw xmm0, xmm1
paddd xmm0, xmm1
paddq xmm0, xmm1
xmm0 = _mm_add_epi8(xmm0, xmm1)
xmm0 = _mm_add_epi16(xmm0, xmm1)
xmm0 = _mm_add_epi32(xmm0, xmm1)
xmm0 = _mm_add_epi64(xmm0, xmm1)
Add corresponding packed integers from xmm0 and xmm1, storing all results in xmm0. The final letter determines how the 128-bit register is divided: paddb adds sixteen 8-bit bytes, paddw adds eight 16-bit words, paddd adds four 32-bit doublewords , and paddq adds two 64-bit quadwords. Each packed element is added independently. A carry leaving one element does not continue into the next element. These instructions use wrapping addition rather than saturating addition. If a result is too large for its element, the extra high bits are discarded. For example, an 8-bit addition of 0xff + 1 produces 0x00. The same bit-level operation works for signed and unsigned values, but signed overflow is not reported. The integer status flags are not updated.
addps xmm0, xmm1 xmm0 = _mm_add_ps(xmm0, xmm1) Treat each XMM register as four packed 32-bit single-precision floating-point values. Add each value in xmm1 to the corresponding value in xmm0, and store the four results in xmm0. Conceptually: xmm0[i] = xmm0[i] + xmm1[i] for elements 0 through 3. The suffix ps means packed single-precision. For example: { 1.0, 2.0, 3.0, 4.0 } plus { 10.0, 20.0, 30.0, 40.0 } produces { 11.0, 22.0, 33.0, 44.0 }. Floating-point rounding and exception behaviour are controlled by mxcsr. The ordinary integer condition flags are not updated.
vmovaps ymm0, YMMWORD PTR [rsi]
vmovups ymm0, YMMWORD PTR [rsi]
ymm0 = _mm256_load_ps((const float *)rsi)
ymm0 = _mm256_loadu_ps((const float *)rsi)
Copy 32 bytes commonly interpreted as eight packed single-precision values. vmovaps requires 32-byte alignment for the YMM memory form, while vmovups permits an unaligned address. Requires AVX.
vmovdqa ymm0, YMMWORD PTR [rsi]
vmovdqu ymm0, YMMWORD PTR [rsi]
ymm0 = _mm256_load_si256((const __m256i *)rsi)
ymm0 = _mm256_loadu_si256((const __m256i *)rsi)
Copy 32 bytes of integer or raw binary data into a YMM register. vmovdqa requires 32-byte alignment, while vmovdqu permits an unaligned memory address.
psubb/psubw/psubd/psubq xmm0, xmm1
vpsubb/vpsubw/vpsubd/vpsubq ymm0, ymm1, ymm2
destination[i] = source1[i] - source2[i] Subtract corresponding packed integers independently. The suffix selects 8-, 16-, 32- or 64-bit elements. These are wrapping subtractions: bits that do not fit are discarded, and a borrow does not continue into the neighboring element. The 256-bit YMM forms require AVX2.
pmullw xmm0, xmm1
pmulld xmm0, xmm1
vpmullw/vpmulld ymm0, ymm1, ymm2
destination[i] = low_half(source1[i] * source2[i]) Multiply corresponding packed integers and keep only the low half of each product. pmullw multiplies 16-bit elements and keeps 16 bits. pmulld multiplies 32-bit elements and keeps 32 bits. High product bits are discarded. The YMM forms require AVX2.
subps/subpd xmm0, xmm1
vsubps/vsubpd ymm0, ymm1, ymm2
destination[i] = source1[i] - source2[i] Subtract corresponding packed floating-point values. `ps` operates on 32-bit single-precision elements and `pd` operates on 64-bit double-precision elements. The YMM forms process eight floats or four doubles.
mulps/mulpd xmm0, xmm1
vmulps/vmulpd ymm0, ymm1, ymm2
destination[i] = source1[i] * source2[i] Multiply corresponding packed single-precision or double-precision values. Each vector element is processed independently.
divps/divpd xmm0, xmm1
vdivps/vdivpd ymm0, ymm1, ymm2
destination[i] = source1[i] / source2[i] Divide corresponding packed floating-point values. IEEE-754 special values, exceptions and rounding are controlled by the operands and mxcsr.
sqrtps/sqrtpd xmm0, xmm1
vsqrtps/vsqrtpd ymm0, ymm1
destination[i] = sqrt(source[i]) Calculate the square root of every packed single-precision or double-precision element. The source register is not changed by the AVX form.
pcmpeqb/pcmpeqw/pcmpeqd xmm0, xmm1
vpcmpeqb/vpcmpeqw/vpcmpeqd ymm0, ymm1, ymm2
destination[i] = source1[i] == source2[i] ? ALL_ONES : 0 Compare corresponding packed integer elements for equality. Each result element becomes all 1 bits when equal, or all 0 bits when not equal. This produces a vector mask rather than a single Boolean value.
pcmpgtb/pcmpgtw/pcmpgtd xmm0, xmm1
vpcmpgtb/vpcmpgtw/vpcmpgtd ymm0, ymm1, ymm2
destination[i] = source1[i] > source2[i] ? ALL_ONES : 0 Compare corresponding packed signed integers using a greater-than comparison. Each result element becomes all 1 bits when the condition is true, or zero when it is false.
cmpps xmm0, xmm1, imm8
cmppd xmm0, xmm1, imm8
vcmpps/vcmppd ymm0, ymm1, ymm2, imm8
destination[i] = compare(source1[i], source2[i], imm8) Compare corresponding packed floating-point values and create a vector mask. The immediate value selects the predicate, such as equal, less than, less than or equal, unordered or one of the extended AVX predicates. True elements become all 1 bits; false elements become zero.
movmskps eax, xmm0
vmovmskps eax, ymm0
eax = collect_float_sign_bits(vector) Copy the sign bit of each packed 32-bit floating-point element into consecutive low bits of eax. movmskps with an XMM source collects 4 sign bits into bits 0–3. vmovmskps with a YMM source collects 8 sign bits into bits 0–7. The remaining bits of eax are cleared. SIMD comparisons usually represent true using an element containing all 1 bits. Because such an element has its sign bit set, this instruction converts four or eight packed comparison results into a compact scalar mask that can be tested using ordinary integer instructions.
movmskpd eax, xmm0
vmovmskpd eax, ymm0
eax = collect_double_sign_bits(vector) Copy the sign bit of each packed 64-bit floating-point element into consecutive low bits of eax. The XMM form collects 2 bits, the YMM form collects 4 bits. All remaining result bits are cleared. This is commonly used to turn packed double-precision comparison results into a scalar mask suitable for test, cmp or branching.
pmovmskb eax, xmm0 eax = collect_high_bit_of_each_byte(xmm0) Copy the most significant bit of each of the 16 bytes in xmm0 into bits 0–15 of eax. The remaining result bits are cleared. For example, after pcmpeqb, every matching byte contains 0xff and therefore contributes a 1 bit to the mask. Every non-matching byte contains 0 and contributes a 0 bit.
vpmovmskb eax, xmm0
vpmovmskb eax, ymm0
eax = collect_high_bit_of_each_byte(vector) Copy the most significant bit of every byte in the vector into consecutive bits of eax. The XMM form produces a 16-bit mask, the YMM form produces a 32-bit mask. This is the VEX-encoded form of pmovmskb. The 256-bit YMM form requires AVX2.
pshufd xmm0, xmm1, imm8
vpshufd ymm0, ymm1, imm8
destination = shuffle_32bit_elements(source, imm8) Rearrange packed 32-bit elements according to the immediate control byte. The same source element may be selected more than once, making this useful for reordering or broadcasting values.
pshufb xmm0, xmm1
vpshufb ymm0, ymm1, ymm2
destination = byte_shuffle(source, control) Rearrange bytes using a separate control byte for every destination position. The low control bits select a source byte, while a set high control bit writes zero. In a YMM register, each 128-bit lane is shuffled independently.
punpcklbw/punpckhbw
punpcklwd/punpckhwd
punpckldq/punpckhdq
punpcklqdq/punpckhqdq
vpunpck* xmm/ymm
destination = interleave_low_or_high(source1, source2) Interleave corresponding elements from two vectors. The `l` forms use elements from the low half, while the `h` forms use elements from the high half. The ending selects byte, word, doubleword or quadword elements. These instructions are frequently used to widen, transpose or rearrange SIMD data. YMM forms operate independently within each 128-bit lane.
packsswb/packssdw
packuswb/packusdw
vpack* xmm/ymm
destination = pack_with_saturation(source1, source2) Convert wider packed integers into narrower elements and combine two source vectors into one result. Values that do not fit are clamped rather than wrapped. `ss` uses signed saturation. `us` produces unsigned saturated results. Examples include packing 16-bit values into 8-bit values or 32-bit values into 16-bit values.
palignr xmm0, xmm1, 8
vpalignr ymm0, ymm1, ymm2, 8
destination = align_bytes(source1, source2, 8) Concatenate two vectors, shift the combined byte sequence right by the immediate number of bytes and keep one vector-width result. This allows a window of bytes to be selected across the boundary between two registers. YMM operation is performed separately in each 128-bit lane.
psllw/pslld/psllq xmm0, count
vpsllw/vpslld/vpsllq ymm0, ymm1, count
destination[i] = source[i] << count Shift every packed 16-, 32- or 64-bit element left by the same count. Zeros enter at the low end, and bits leaving one element are discarded rather than entering the neighboring element.
psrlw/psrld/psrlq xmm0, count
vpsrlw/vpsrld/vpsrlq ymm0, ymm1, count
destination[i] = (unsigned)source[i] >> count Logically shift every packed 16-, 32- or 64-bit element right by the same count. Zeros enter at the high end of each independent element.
psraw/psrad xmm0, count
vpsraw/vpsrad ymm0, ymm1, count
destination[i] = (signed)source[i] >> count Arithmetically shift every packed signed 16- or 32-bit element right. The original sign bit is copied into the newly empty high positions of each element.
vzeroupper clear_upper_halves_of_ymm_registers() Clear the upper 128 bits of all YMM registers while preserving their lower XMM halves. This is commonly used before calling code that uses legacy SSE instructions, avoiding AVX-to-SSE transition penalties on processors where they occur.
vzeroall clear_all_xmm_and_ymm_registers() Clear all architectural XMM and YMM register contents. Unlike vzeroupper, this also destroys the lower 128-bit values, so it is only appropriate when none of the vector-register contents need to be preserved.
vpxor xmm0, xmm1, xmm2
vpxor ymm0, ymm1, ymm2
xmm0 = _mm_xor_si128(xmm1, xmm2)
ymm0 = _mm256_xor_si256(ymm1, ymm2)
Perform a bitwise XOR between the two source vectors and store the result in a separate destination register. Each result bit becomes 1 when the corresponding source bits are different, or 0 when they are the same: The XMM form operates on 128 bits, and the YMM form operates on 256 bits Unlike the older two-operand pxor xmm0, xmm1, the AVX form does not need to overwrite either source: xmm0 = xmm1 ^ xmm2. Using the same source twice clears the destination: vpxor ymm0, ymm1, ymm1 sets all bits in ymm0 to zero. The 128-bit XMM form requires AVX, the 256-bit YMM form requires AVX2.
vpaddb xmm0, xmm1, xmm2
vpaddw xmm0, xmm1, xmm2
vpaddd xmm0, xmm1, xmm2
vpaddq xmm0, xmm1, xmm2
vpaddb ymm0, ymm1, ymm2
vpaddw ymm0, ymm1, ymm2
vpaddd ymm0, ymm1, ymm2
vpaddq ymm0, ymm1, ymm2
xmm0 = _mm_add_epi8(xmm1, xmm2)
xmm0 = _mm_add_epi16(xmm1, xmm2)
xmm0 = _mm_add_epi32(xmm1, xmm2)
xmm0 = _mm_add_epi64(xmm1, xmm2)
ymm0 = _mm256_add_epi8(ymm1, ymm2)
ymm0 = _mm256_add_epi16(ymm1, ymm2)
ymm0 = _mm256_add_epi32(ymm1, ymm2)
ymm0 = _mm256_add_epi64(ymm1, ymm2)
Add corresponding packed integers from the two source registers and store the results in a separate destination register. The final letter selects the size of each packed integer: vpaddb for 8-bit bytes, vpaddw for 16-bit words, vpaddd for 32-bit doublewords, and vpaddq for 64-bit quadwords. A 128-bit XMM register contains: sixteen 8-bit integers, eight 16-bit integers, four 32-bit integers, or two 64-bit integers. A 256-bit YMM register contains twice as many: thirty-two 8-bit integers, sixteen 16-bit integers, eight 32-bit integers, or four 64-bit integers. Every packed element is added independently. A carry leaving one element does not continue into the next element. These instructions use wrapping addition: extra high bits are discarded when a result does not fit in its element. The 128-bit XMM forms require AVX. The 256-bit YMM forms require AVX2.
vaddps xmm0, xmm1, xmm2
vaddps ymm0, ymm1, ymm2
xmm0 = _mm_add_ps(xmm1, xmm2)
ymm0 = _mm256_add_ps(ymm1, ymm2)
Add corresponding packed 32-bit single-precision floating-point values from the two source registers and store the results in a separate destination register. The XMM form adds four values at once: xmm0[i] = xmm1[i] + xmm2[i] for elements 0 through 3. The YMM form adds eight values at once: ymm0[i] = ymm1[i] + ymm2[i] for elements 0 through 7. Unlike the older two-operand addps xmm0, xmm1, neither source needs to be overwritten. For example: vaddps ymm0, ymm1, ymm2 calculates ymm0 = ymm1 + ymm2 while leaving ymm1 and ymm2 unchanged. Both the XMM and YMM forms require AVX. Floating-point rounding and exception behaviour are controlled by mxcsr.
SIMD and vector instructions (AVX-512)
vaddps zmm0 {k1}{z}, zmm1, zmm2 for (i = 0; i < 16; i++) {
  if (k1[i]) {
    zmm0.f32[i] = zmm1.f32[i] + zmm2.f32[i];
  } else {
    zmm0.f32[i] = 0;
  }
}
Perform a masked vector operation using AVX-512's EVEX encoding. In 64-bit mode, AVX-512 can provide: 32 vector registers named zmm0 through zmm31; 8 opmask registers named k0 through k7; 128-, 256- and 512-bit vector operations; per-element conditional execution; embedded memory broadcasts; and embedded rounding and exception-suppression controls on supported instructions. A mask such as {k1} selects which destination elements are written. Without {z}, inactive elements normally keep their previous destination values. With {z}, inactive elements become zero. For most masked vector instructions, k0 means no masking rather than acting as an ordinary selectable mask.
kaddb/kaddw/kaddd/kaddq
kandb/kandw/kandd/kandq
kandnb/kandnw/kandnd/kandnq
korb/korw/kord/korq
kxorb/kxorw/kxord/kxorq
kxnorb/kxnorw/kxnord/kxnorq
knotb/knotw/knotd/knotq
k_destination = mask_operation(k_source1, k_source2) Perform arithmetic or bitwise operations directly on AVX-512 opmask registers. The final letter selects the mask width: b for 8 bits; w for 16 bits; d for 32 bits; q for 64 bits. Opmask values are ordinary bit masks, one mask bit usually corresponds to one packed vector element.
kmovb/kmovw/kmovd/kmovq
kshiftlb/kshiftlw/kshiftld/kshiftlq
kshiftrb/kshiftrw/kshiftrd/kshiftrq
kunpckbw/kunpckwd/kunpckdq
move_or_rearrange_mask_bits() Move, shift or combine opmask values. kmov* transfers masks between k registers, general-purpose registers and memory. kshiftl* and kshiftr* shift mask bits. kunpck* combines the low halves of two mask registers into a wider result.
ktestb/ktestw/ktestd/ktestq
kortestb/kortestw/kortestd/kortestq
flags = test_mask_bits(k1, k2) Test opmask bits and write the result into the ordinary integer status flags. ktest* performs mask tests based on AND and AND-NOT relationships. kortest* tests OR relationships. These instructions are commonly used before jz, jnz, jc or jnc.
vaddps/vaddpd/vaddss/vaddsd
vsubps/vsubpd/vsubss/vsubsd
vmulps/vmulpd/vmulss/vmulsd
vdivps/vdivpd/vdivss/vdivsd
vsqrtps/vsqrtpd/vsqrtss/vsqrtsd
vminps/vminpd/vminss/vminsd
vmaxps/vmaxpd/vmaxss/vmaxsd
destination[i] = floating_point_operation(source1[i], source2[i]) AVX-512 forms of common packed and scalar floating-point arithmetic. ZMM forms operate on sixteen 32-bit floats, or eight 64-bit doubles. Supported forms may use masking, zero masking, memory broadcast, embedded rounding and suppress-all-exceptions controls. Scalar forms modify only the low element.
vfmadd132*/vfmadd213*/vfmadd231*
vfmsub132*/vfmsub213*/vfmsub231*
vfnmadd132*/vfnmadd213*/vfnmadd231*
vfnmsub132*/vfnmsub213*/vfnmsub231*
vfmaddsub132*/vfmaddsub213*/vfmaddsub231*
vfmsubadd132*/vfmsubadd213*/vfmsubadd231*
destination = fused_multiply_add_or_subtract(...) AVX-512 fused multiply-add and multiply-subtract families. They support 512-bit ZMM vectors and AVX-512 masking while preserving the single-rounding behaviour of FMA3. The numeric suffix still identifies the operand roles, while the mnemonic identifies whether the product or addend is negated and whether alternating elements add or subtract.
vrcp14ps/vrcp14pd/vrcp14ss/vrcp14sd
vrsqrt14ps/vrsqrt14pd/vrsqrt14ss/vrsqrt14sd
vscalefps/vscalefpd/vscalefss/vscalefsd
vgetexpps/vgetexppd/vgetexpss/vgetexpsd
vgetmantps/vgetmantpd/vgetmantss/vgetmantsd
vrndscaleps/vrndscalepd/vrndscaless/vrndscalesd
vreduceps/vreducepd/vreducess/vreducesd
destination = approximate_or_decompose_floating_point(source) Floating-point helper instructions intended for optimized mathematics libraries. They provide approximate reciprocal or reciprocal-square-root values, exponent and mantissa extraction, scaling by powers of two, configurable rounding and range reduction. Approximation instructions normally require one or more refinement steps when full floating-point precision is needed.
vpaddd/vpaddq
vpsubd/vpsubq
vpmulld/vpmuldq/vpmuludq
vpandd/vpandq
vpandnd/vpandnq
vpord/vporq
vpxord/vpxorq
vpminsd/vpminud/vpmaxsd/vpmaxud< /td>
destination[i] = packed_integer_operation(source1[i], source2[i]) Packed 32- and 64-bit integer arithmetic and logic using ZMM registers. Each element is processed independently, with optional per-element masking. Arithmetic forms normally wrap when their result does not fit unless the mnemonic explicitly identifies a saturating operation.
vpslld/vpsllq/vpsllvd/vpsllvq
vpsrld/vpsrlq/vpsrlvd/vpsrlvq
vpsrad/vpsraq/vpsravd/vpsravq
vprold/vprolq/vprolvd/vprolvq
vprord/vprorq/vprorvd/vprorvq
destination[i] = shift_or_rotate(source[i], count[i]) Shift or rotate packed 32- or 64-bit integer elements. Some forms use one common immediate or scalar count, while the variable forms use a separate count for every element. Bits never flow from one packed element into its neighbour.
vpcmpd/vpcmpq/vpcmpud/vpcmpuq
vcmpps/vcmppd/vcmpss/vcmpsd
vptestmd/vptestmq
vptestnmd/vptestnmq
vfpclassps/vfpclasspd/vfpclassss/vfpclasssd
k_destination[i] = comparison_or_classification(source[i]) Compare, test or classify vector elements and write Boolean results into an opmask register. Integer comparison instructions use an immediate predicate and support signed or unsigned elements. Floating-point classification can identify values such as zero, infinity, NaN, denormal or negative finite values.
vpternlogd/vpternlogq destination[i] = boolean_function(a[i], b[i], c[i], imm8) Apply any three-input Boolean function to packed 32- or 64-bit elements. The immediate byte is an eight-entry truth table covering every possible combination of the three input bits. One instruction can therefore replace many combinations of and, or, xor and not.
vmovdqa32/vmovdqa64
vmovdqu32/vmovdqu64
vbroadcastss/vbroadcastsd
vpbroadcastd/vpbroadcastq
vbroadcastf32x2/vbroadcastf32x4/vbroadcastf32x8
vbroadcastf64x2/vbroadcastf64x4
destination = load_move_or_repeat_elements(source) Move aligned or unaligned vectors and broadcast smaller memory or register values across a larger vector. Broadcast forms repeat one scalar or one smaller block of elements until the destination vector is filled. Masked loads can suppress memory access for inactive elements.
vcvt*/vcvtt*
vpmovdb/vpmovdw/vpmovdq
vpmovqb/vpmovqw/vpmovqd
vpmovs*/vpmovus*
destination[i] = convert_or_narrow(source[i]) Convert between floating-point formats, integer formats and packed element widths. vcvtt* forms truncate floating-point values toward zero. Narrowing vpmov* forms may discard high bits, use signed saturation, or use unsigned saturation.
vgatherdps/vgatherdpd/vgatherqps/vgatherqpd
vpgatherdd/vpgatherdq/vpgatherqd/vpgatherqq
vscatterdps/vscatterdpd/vscatterqps/vscatterqpd
vpscatterdd/vpscatterdq/vpscatterqd/vpscatterqq
memory[base + index[i] * scale] <-> vector[i] Load from or store to several non-contiguous addresses using vector indices. AVX-512 gather and scatter instructions use opmask registers rather than the destructive vector mask used by AVX2 gathers. Inactive elements do not access memory.
vcompressps/vcompresspd
vpcompressd/vpcompressq
vexpandps/vexpandpd
vpexpandd/vpexpandq
destination = pack_or_expand_elements_selected_by_mask(source, k) Compact selected elements together or expand compacted elements back into mask-selected positions. Compress is useful for filtering vector elements without first storing a complete vector. Expand performs the inverse arrangement.
vpermd/vpermq/vpermps/vpermpd
vpermi2d/vpermi2q/vpermi2ps/vpermi2pd
vpermt2d/vpermt2q/vpermt2ps/vpermt2pd
vshufi32x4/vshufi64x2
vshuff32x4/vshuff64x2
valignd/valignq
destination = permute_or_align_elements(source1, source2, control) Rearrange elements within one vector or select them from two vectors. vpermi2* and vpermt2* provide two-source table lookup. The shuffle instructions rearrange larger 128-bit or 256-bit blocks. valign* selects an aligned window from two concatenated vectors.
vextractf32x4/vextractf32x8
vextractf64x2/vextractf64x4
vextracti32x4/vextracti32x8
vextracti64x2/vextracti64x4
vinsertf32x4/vinsertf32x8
vinsertf64x2/vinsertf64x4
vinserti32x4/vinserti32x8
vinserti64x2/vinserti64x4
extract_or_insert_vector_block() Extract a 128- or 256-bit block from a larger vector, or insert a smaller block into a selected position in a larger vector.
vpconflictd/vpconflictq
vplzcntd/vplzcntq
destination = conflict_or_leading_zero_information(source) AVX-512 Conflict Detection instructions. vpconflict* reports which earlier vector elements contain the same value as each current element. This helps vectorize loops with possible duplicate indices. vplzcnt* counts leading zeros in every packed 32- or 64-bit element. Requires AVX512CD.
vexp2ps/vexp2pd
vrcp28ps/vrcp28pd/vrcp28ss/vrcp28sd
vrsqrt28ps/vrsqrt28pd/vrsqrt28ss/vrsqrt28sd
destination = high_accuracy_math_approximation(source) AVX512ER exponential, reciprocal and reciprocal-square-root approximations. These provide greater approximation accuracy than the corresponding 14-bit AVX-512 Foundation helpers. AVX512ER was implemented on selected Xeon Phi processors and is not a universal AVX-512 capability.
vgatherpf0dps/vgatherpf0dpd
vgatherpf0qps/vgatherpf0qpd
vgatherpf1dps/vgatherpf1dpd
vgatherpf1qps/vgatherpf1qpd
vscatterpf0dps/vscatterpf0dpd
vscatterpf0qps/vscatterpf0qpd
vscatterpf1dps/vscatterpf1dpd
vscatterpf1qps/vscatterpf1qpd
prefetch_vector_of_indexed_addresses() Prefetch several indexed addresses that will later be gathered from or scattered to. Requires AVX512PF, a specialized subset associated mainly with selected Xeon Phi processors.
vpaddb/vpaddw
vpsubb/vpsubw
vpaddsb/vpaddsw/vpaddusb/vpaddusw
vpsubsb/vpsubsw/vpsubusb/vpsubusw
vpcmpeqb/vpcmpeqw
vpcmpb/vpcmpw/vpcmpub/vpcmpuw
vpmovb2m/vpmovw2m/vpmovm2b/vpmovm2w
destination[i] = byte_or_word_operation(source1[i], source2[i]) AVX512BW adds masked packed-byte and packed-word operations. A 512-bit vector can contain 64 bytes or 32 words, so these instructions may use 64- or 32-bit masks. The family includes wrapping and saturating arithmetic, comparisons, packing, unpacking, shifts and conversion between vector elements and mask bits.
vpmullq
vpminsq/vpminuq/vpmaxsq/vpmaxuq
vpmovq2m/vpmovd2m/vpmovm2q/vpmovm2d
vandps/vandpd/vandnps/vandnpd
vorps/vorpd/vxorps/vxorpd
destination = extended_dword_or_qword_operation(sources) AVX512DQ adds or promotes operations focused on 32- and 64-bit integer and floating-point elements. It includes 64-bit integer multiplication, signed and unsigned 64-bit min/max, mask conversion and EVEX forms of floating-point bitwise operations.
AVX512VL use_AVX512_operation_with_128_or_256_bit_vector() AVX512VL is a capability rather than a separate mnemonic family. It allows many AVX-512 instructions to operate on XMM and YMM registers while retaining EVEX features such as opmasking, zero masking and access to additional registers.
vpmadd52luq
vpmadd52huq
destination[i] += selected_52_bits(source1[i] * source2[i]) Perform packed unsigned 52-bit integer multiplication and add either the low or high 52-bit portion of each product to the destination. These instructions are useful for multi-precision arithmetic and large-integer cryptography. Requires AVX512IFMA.
vpermb
vpermi2b/vpermi2w
vpermt2b/vpermt2w
vpmultishiftqb
destination = advanced_byte_or_word_permutation(sources, indices) AVX512VBMI provides variable byte and word permutation and multishift operations. It enables full-vector byte lookup and flexible extraction of overlapping 8-bit values from packed 64-bit source elements.
vpcompressb/vpcompressw
vpexpandb/vpexpandw
vpshldw/vpshldd/vpshldq
vpshrdw/vpshrdd/vpshrdq
vpshldvw/vpshldvd/vpshldvq
vpshrdvw/vpshrdvd/vpshrdvq
compress_expand_or_double_shift_packed_elements() AVX512VBMI2 adds byte/word compression and expansion plus packed double-width shifts. The double-shift instructions take bits from two source elements, resembling vector versions of shld and shrd.
vpdpbusd/vpdpbusds
vpdpwssd/vpdpwssds
destination[i] += dot_product_of_small_integer_groups() AVX512VNNI dot-product instructions for neural-network and integer matrix workloads. They multiply groups of 8- or 16-bit integers, sum the products and accumulate into packed 32-bit destination elements. Mnemonics ending in s use signed saturation on the accumulation.
vpshufbitqmb
vpopcntb/vpopcntw
vpopcntd/vpopcntq
mask_or_vector = bit_shuffle_or_population_count(source) AVX512BITALG and AVX512VPOPCNTDQ bit-processing instructions. vpshufbitqmb selects individual bits and writes them to an opmask. vpopcnt* counts set bits independently in packed byte, word, doubleword or quadword elements.
vp2intersectd
vp2intersectq
(mask_a, mask_b) = find_intersections(vector_a, vector_b) Compare every packed element in one vector with every element in another vector and return two opmasks. One mask identifies matching elements in the first source, and the other identifies matching elements in the second source. Requires AVX512VP2INTERSECT.
vcvtneps2bf16
vcvtne2ps2bf16
vdpbf16ps
destination = convert_or_dot_product_bfloat16(source) AVX512_BF16 instructions. The conversion instructions convert 32-bit floats to 16-bit bfloat16 values using round-to-nearest-even. vdpbf16ps multiplies adjacent bfloat16 values, adds each pair and accumulates into packed 32-bit floats.
vaddph/vaddsh
vsubph/vsubsh
vmulph/vmulsh
vdivph/vdivsh
vsqrtph/vsqrtsh
vfmadd*/vfmsub*/vfnmadd*/vfnmsub* ph/sh
vcvt*ph/vcvt*sh
vcmulcph/vfcmulcph
vfmaddcph/vfcmaddcph
destination = IEEE_754_binary16_operation(sources) AVX512_FP16 provides general-purpose arithmetic, comparisons, conversions, fused operations and complex-number helpers for IEEE-754 16-bit half precision. Packed forms operate on many half-precision elements at once, while scalar sh forms operate on one low element.
vaesenc/vaesenclast
vaesdec/vaesdeclast
vpclmulqdq
vgf2p8affineinvqb
vgf2p8affineqb
vgf2p8mulb
destination = parallel_cryptographic_primitive(sources) EVEX vector forms of AES, carry-less multiplication and Galois-field byte operations. VAES can process multiple independent 128-bit AES blocks inside one vector. VPCLMULQDQ performs several carry-less multiplications. GFNI instructions perform affine transformations, affine inverse transformations and multiplication in GF(28).
v4fmaddps/v4fnmaddps
vp4dpwssd/vp4dpwssds
destination += four_source_fused_or_dot_product_operation() Specialized AVX512_4FMAPS and AVX512_4VNNIW instructions. They combine data from four consecutive vector registers with a memory operand to perform fused floating-point or integer dot-product work. These subsets were implemented on selected Xeon Phi processors and are not general AVX-512 baseline features.
Intel Advanced Vector Extensions 10 (AVX10)
AVX10.1 use_versioned_EVEX_vector_instruction_set() AVX10.1 establishes a versioned, converged vector ISA based on EVEX-encoded vector operations. It retains familiar instruction names such as vaddps, vpaddd, vpermd and vfmadd*, while defining their availability through an AVX10 version rather than requiring software to reason only about many independent AVX-512 subset names. Software must still check CPUID and the operating-system-enabled extended state before using the vector registers.
AVX10.2 use_AVX10_2_vector_and_AI_media_extensions() AVX10.2 extends the converged vector ISA with additional operations for AI, numerical conversion, media processing, WebAssembly-style operations and cryptographic workloads. AVX10 is a version number, not an instruction mnemonic. Individual operations continue to use ordinary vector mnemonics and are enumerated through CPUID. In Intel's current AVX10 model, supported AVX10 implementations include 128-, 256- and 512-bit vector operation rather than defining a separate 256-bit-only AVX10 target.
AVX-IFMA
AVX-NE-CONVERT
AVX-VNNI-INT8
AVX-VNNI-INT16
perform_newer_vector_integer_and_conversion_operations() Closely related modern vector extensions commonly encountered alongside AVX10 implementations. They provide 52-bit multiply-add support at narrower vector widths, neural-network conversions and integer dot products using 8- or 16-bit input elements. Each feature has its own CPUID enumeration and should not be assumed merely because another AVX10-era feature exists.
Indexed vector loads (AVX2 gather)
vpgatherdd destination, DWORD PTR [base + dword_indices*scale], mask for each active element i:
  destination.dword[i] =
    *(int32_t *)(base + (int32_t)index[i] * scale)
Gather packed 32-bit integer values using signed 32-bit indices. Each active destination element is loaded from its own independently calculated memory address: base + (int32_t)index[i] * scale An element is active when the highest bit of its corresponding mask element is set. Inactive destination elements keep their previous values. After an element is loaded successfully, its corresponding mask element is cleared. The mask operand is therefore modified by the instruction. Requires AVX2.

AVX2 gather fault behaviour
Some earlier elements may already be loaded before a fault. AVX2 gather instructions are restartable but may complete only part of the vector before a memory fault occurs. Elements loaded before the fault remain in the destination, and their mask elements have already been cleared. Elements not yet processed remain selected by the mask. This partial-progress behaviour is why the mask register is both an input and an output. It allows the instruction to be restarted after the fault is handled.
vpgatherdq destination, QWORD PTR [base + dword_indices*scale], mask for each active element i:
  destination.qword[i] =
    *(int64_t *)(base + (int32_t)index[i] * scale)
Gather packed 64-bit integer values using signed 32-bit indices. The mnemonic ending describes the combination: the first d means the indices are 32-bit doublewords, the final q means the loaded values are 64-bit quadwords. Only mask elements with their highest bit set are loaded. Successfully processed mask elements are cleared. Requires AVX2.
vpgatherqd destination, DWORD PTR [base + qword_indices*scale], mask for each active element i:
  destination.dword[i] =
    *(int32_t *)(base + (int64_t)index[i] * scale)
Gather packed 32-bit integer values using signed 64-bit indices. Here, q identifies the 64-bit index elements, while d identifies the 32-bit values loaded from memory. Requires AVX2.
vpgatherqq destination, QWORD PTR [base + qword_indices*scale], mask for each active element i:
  destination.qword[i] =
    *(int64_t *)(base + (int64_t)index[i] * scale)
Gather packed 64-bit integer values using signed 64-bit indices. Both the indices and loaded values are quadwords. As with all AVX2 gather instructions, inactive elements preserve their old destination values, while successfully loaded mask elements are cleared. Requires AVX2.
vgatherdps destination, DWORD PTR [base + dword_indices*scale], mask for each active element i:
  destination.float[i] =
    *(float *)(base + (int32_t)index[i] * scale)
Gather packed 32-bit single-precision floating-point values using signed 32-bit indices. The instruction copies the 32-bit values from memory, it performs no numerical conversion. Active elements are selected through the sign bits of the corresponding mask elements. Requires AVX2.
vgatherdpd destination, QWORD PTR [base + dword_indices*scale], mask for each active element i:
  destination.double[i] =
    *(double *)(base + (int32_t)index[i] * scale)
Gather packed 64-bit double-precision floating-point values using signed 32-bit indices. The d before pd refers to the doubleword-sized indices. The pd suffix means the loaded data consists of packed double-precision values. Requires AVX2.
vgatherqps destination, DWORD PTR [base + qword_indices*scale], mask for each active element i:
  destination.float[i] =
    *(float *)(base + (int64_t)index[i] * scale)
Gather packed 32-bit single-precision floating-point values using signed 64-bit indices. Requires AVX2.
vgatherqpd destination, QWORD PTR [base + qword_indices*scale], mask for each active element i:
  destination.double[i] =
    *(double *)(base + (int64_t)index[i] * scale)
Gather packed 64-bit double-precision floating-point values using signed 64-bit indices. Every active lane may read from a different address. This makes gather suitable for indexed tables and structures where the required elements are not stored contiguously. Requires AVX2.
Processor feature detection and extended state
cpuid leaf = eax;
subleaf = ecx;
(eax, ebx, ecx, edx) = cpuid(leaf, subleaf);
Ask the processor for identification or feature information. Before executing cpuid, place a leaf number in eax. Some leaves also use ecx as a subleaf number to select a more specific group of information. The processor returns its answer in eax, ebx, ecx and edx, replacing the values that were previously in those registers. Common leaves include:
  • eax = 0: return the highest supported basic leaf and the CPU vendor string
  • eax = 1: return the processor family, model, stepping and common feature flags
  • eax = 7, ecx = 0: return extended feature flags such as AVX2 and other newer instruction-set features
A feature bit being present means the processor supports that feature. For some features, especially AVX and AVX-512, the program must also check that the operating system has enabled the required register state using xgetbv.
xgetbv xcr_number = ecx;
edx:eax = xgetbv(xcr_number);
Read an extended control register selected by ecx. The 64-bit result is returned in edx:eax, edx contains the high 32 bits and eax contains the low 32 bits. The most common form uses ecx = 0 to read XCR0: xor ecx, ecx; xgetbv XCR0 tells the program which extended processor states the operating system saves and restores during context switches. Important bits include: bit 0: x87 floating-point state, bit 1: SSE and XMM-register state, and bit 2: AVX and upper YMM-register state. Before using AVX instructions, a program normally checks that: CPUID reports support for AVX, CPUID reports that the operating system supports XSAVE, and bits 1 and 2 of XCR0 are both set. This prevents the program from using XMM or YMM register state that the operating system is not prepared to preserve. Executing xgetbv when operating-system XSAVE support is not enabled raises an invalid-opcode exception.
xsetbv write_xcr(ecx, edx:eax); Write a 64-bit value from edx:eax into the extended control register selected by ecx. The most common use is setting XCR0, which controls which extended processor states are enabled and managed by the operating system. The value must contain a valid combination of state bits. For example, AVX state cannot be enabled without also enabling SSE state. This is a privileged instruction intended for operating-system or hypervisor code. An ordinary user-space program should use xgetbv to inspect the configuration rather than attempting to change it.
fxsave64 [rdi]
fxsave [rdi]
save_legacy_fp_simd_state((void *)rdi); Save the older floating-point and SIMD processor state to a fixed-format, 512-byte memory area. The saved information includes x87 floating-point state, MMX state, XMM-register state, mxcsr and related control and status information. The memory address must be aligned to a 16-byte boundary. The instruction copies the state to memory but does not clear or otherwise change the live registers. In 64-bit code, fxsave64 uses the 64-bit-mode save format for instruction and data pointers. fxsave selects the older format. This is the older predecessor to the more flexible xsave family.
fxrstor64 [rdi]
fxrstor [rdi]
restore_legacy_fp_simd_state((const void *)rdi); Restore floating-point and SIMD processor state from a fixed-format, 512-byte memory area previously prepared by fxsave or fxsave64. This restores state such as the x87 registers, MMX state, XMM registers, mxcsr and associated control information. The memory address must be aligned to a 16-byte boundary. The saved data must contain valid control values. Restoring invalid or reserved values can cause an exception. In 64-bit code, use fxrstor64 for the corresponding 64-bit-mode format.
xsave [rdi] requested = edx:eax;
xsave((void *)rdi, requested & XCR0);
Save selected extended processor-state components to the XSAVE area beginning at [rdi]. The requested components are selected by the 64-bit mask in edx:eax. Only components that are also enabled in XCR0 are saved. Possible components include x87 state, XMM registers, upper YMM state and newer vector or processor state supported by the CPU. The save area must be aligned to a 64-byte boundary. The required size and layout of the save area must be obtained using cpuid leaf 0x0d. Software should not assume that every processor uses the same size.
xrstor [rdi] requested = edx:eax;
xrstor((const void *)rdi, requested & XCR0);
Restore selected extended processor-state components from the XSAVE area beginning at [rdi]. The mask in edx:eax selects which components should be restored. A component must also be enabled in XCR0. Components marked as present in the saved area's header are loaded from memory. Selected components not marked as present are returned to their architectural initial state. The save area must be aligned to a 64-byte boundary and must contain a valid XSAVE image. Invalid state information or reserved header bits can cause an exception.
xsaveopt [rdi] requested = edx:eax;
xsave_optimized((void *)rdi, requested & XCR0);
Save selected extended processor state like xsave, but allow the CPU to skip writing state components that have not changed since they were last restored or initialized. This can reduce unnecessary memory writes during context switching. Because parts of the memory area may be left unchanged, the destination should already contain a valid, initialized XSAVE image. The requested components are selected by edx:eax and limited by XCR0. The save area must be 64-byte aligned, and CPU support must first be checked with cpuid.
xsavec [rdi] requested = edx:eax;
xsave_compacted((void *)rdi, requested & XCR0);
Save selected extended processor state using the compacted XSAVE format. Instead of reserving every component's fixed position in the standard layout, enabled components are stored next to one another without gaps for unsupported or disabled components. This can make the save area smaller when only some of the processor's available state components are enabled. The XSAVE header marks the memory image as using the compacted format. The requested state mask is supplied in edx:eax. The destination must be 64-byte aligned, and support must be detected using cpuid.
xsaves [rdi] requested = edx:eax;
save_user_and_supervisor_state_compacted(
    (void *)rdi, requested
);
Save selected user and supervisor extended-state components using an optimized, compacted format. User-state components are controlled by XCR0, while supervisor-state components are controlled by the IA32_XSS model-specific register. Supervisor state belongs to operating-system facilities rather than an ordinary application. Examples can include specialized protection, tracing or hardware management state supported by a particular processor. This is a privileged instruction intended for operating-system and hypervisor context-switching code. The requested components are selected by edx:eax, and the save area must be aligned to a 64-byte boundary.
xrstors [rdi] requested = edx:eax;
restore_user_and_supervisor_state(
    (const void *)rdi, requested
);
Restore selected user and supervisor extended-state components from a compacted XSAVE image created for the supervisor-state mechanism. User components are limited by XCR0, while supervisor components are limited by IA32_XSS. Selected components present in the saved image are loaded from memory. Selected components recorded as being in their initial state are restored to their architectural initial values. This is a privileged instruction intended for operating systems and hypervisors. The source area must be 64-byte aligned and contain valid state data. Malformed headers, unsupported components or invalid control values can cause an exception.
FS and GS base access
rdfsbase rax rax = FS_BASE Read the hidden 64-bit base address used for fs:-relative memory addressing and copy it into rax. The visible FS segment selector and the hidden FS base are separate pieces of processor state. This instruction reads the base without changing either one. On x86-64 Linux, FS-relative addressing is commonly used for thread-local storage. The processor must support FSGSBASE, and the operating system must have enabled the feature.
rdgsbase rax rax = GS_BASE Read the hidden 64-bit base address used for gs:-relative memory addressing. Store the value in rax without changing the GS base, selector or status flags. Kernels often use GS-relative addressing for per-CPU data, while user-space use depends on the operating system and runtime.
wrfsbase rax FS_BASE = rax Replace the hidden FS base with the 64-bit address in rax. Later memory operands using an fs: segment override calculate their addresses relative to this new base. The address must be valid for the current mode. Changing FS base in a normal application can break thread-local storage and runtime-library assumptions, so it should only be done by code that controls the complete execution environment. The processor and operating system must enable FSGSBASE.
wrgsbase rax GS_BASE = rax Replace the hidden GS base with the 64-bit address in rax. Later gs:-relative memory accesses use this new base. This changes the current GS base, not the separate IA32_KERNEL_GS_BASE value used by swapgs. The processor and operating system must enable FSGSBASE.
Control-flow protection
endbr64 /* Valid indirect branch target */ Mark this location as a valid destination for an indirect call or jmp in 64-bit code. endbr64 is part of Intel Control-flow Enforcement Technology (CET), specifically Indirect Branch Tracking (IBT). When IBT is enabled, the instruction immediately reached through an indirect call or jump must be endbr64. Otherwise, the processor raises a control-protection exception (#CP). It is commonly placed at the beginning of functions that may be reached through a function pointer, virtual-method call, jump table or another indirect branch:
my_function:
    endbr64
    push rbp
    mov rbp, rsp
    # Function body
A direct call my_function or jmp my_function does not require endbr64, because the destination is encoded directly in the instruction. endbr64 does not change registers, memory or status flags. On processors where CET indirect-branch tracking is not active, it behaves like a no-operation instruction.
rdsspq rax if (shadow_stack_enabled) rax = SSP Copy the current Shadow Stack Pointer, or SSP, into rax. SSP points to the top of the protected shadow stack, in a similar way that rsp points to the top of the normal program stack. The shadow stack normally contains protected copies of return addresses created by call. This instruction only reads SSP; it does not change the shadow stack or the pointer itself. It also does not change the status flags. If CET shadow stacks are not enabled, rdsspq behaves like a no-operation and leaves the destination register unchanged. Code that wants zero in that case should clear the register first:
xor eax, eax
rdsspq rax
incsspq rax SSP += 8 * (rax & 0xff) Move the Shadow Stack Pointer forward, effectively discarding entries from the top of the shadow stack. Only the lowest 8 bits of rax are used. That value specifies how many 8-byte shadow-stack entries to discard: If the low byte is 1, SSP increases by 8 bytes. If the low byte is 5, SSP increases by 40 bytes. The maximum is 255 entries, or 2040 bytes. This is the shadow-stack equivalent of removing stack frames without returning through each one. It is useful for operations such as exception handling and longjmp(), where several function frames may need to be abandoned at once. Unlike simply adding to a normal pointer, the instruction also verifies access to the first and last shadow-stack entries being discarded.
rstorssp QWORD PTR [rdi] previous_ssp = SSP
SSP = restore_shadow_stack_from_token(rdi)
Switch to a previously saved shadow stack using the restore token at [rdi]. A shadow-stack restore token is a specially formatted value that identifies a valid location to which SSP may be restored. The instruction validates the token before changing SSP. An invalid token causes a control-protection exception instead of allowing an arbitrary shadow-stack pointer. After a successful switch, the restore token is replaced with a previous-SSP token containing information about the shadow stack that was active before the switch. That information can then be processed by saveprevssp. CF records alignment information about the restored shadow stack. The instruction does not restore the normal stack pointer rsp. Normal-stack and shadow-stack switching must be coordinated separately.
saveprevssp save_restore_token_for_previous_shadow_stack() Create a restore token on the previously active shadow stack. After rstorssp switches to another shadow stack, the top of the new shadow stack contains a previous-SSP token describing the stack that was left behind. saveprevssp consumes that information and writes a restore token onto the previous shadow stack. This allows software to switch back to the previous shadow stack later. The two instructions are therefore normally used together:
rstorssp QWORD PTR [rdi]
saveprevssp
They should normally remain adjacent because rstorssp provides alignment information through CF that may be needed by saveprevssp. The instruction does not change the normal stack pointer rsp.
wrssq QWORD PTR [rdi], rax shadow_stack_store64(rdi, rax) Write the 8-byte value in rax directly to a shadow-stack location at [rdi]. Shadow-stack pages are protected against ordinary writes, so an instruction such as mov [rdi], rax cannot normally modify them. wrssq provides a controlled way for CET-aware software to perform such a write. The destination must be an 8-byte-aligned shadow-stack location. The instruction does not push the value, does not change SSP and does not automatically create or validate a return address. Execution must be enabled through the appropriate CET WR_SHSTK_EN control. Depending on the current privilege level, the instruction writes to the enabled user or supervisor shadow stack. It is mainly used by operating systems, runtimes and other specialized low-level software.
notrack call rax
notrack jmp rax
indirect_call_without_ibt_tracking(rax)
indirect_jump_without_ibt_tracking(rax)
Perform a near indirect call or jump without activating the CET indirect-branch tracker for that control transfer. A normal tracked indirect branch requires its destination to begin with endbr64. When the no-track mechanism is enabled, the notrack prefix tells the processor not to require endbr64 for this particular branch. It only applies to indirect branches, such as:
notrack call rax
notrack jmp QWORD PTR [rdi]
It does not apply to a direct branch such as call function, because direct branches are not checked by IBT in the same way. The prefix is only honored when the operating system has enabled the CET NO_TRACK_EN control. Otherwise, the indirect branch remains tracked. Because this deliberately bypasses an IBT check, it should only be used by compilers, linkers and low-level runtimes in cases where the target is known to be safe.
wrussq QWORD PTR [rdi], rax kernel_write_user_shadow_stack64(rdi, rax) Write the 8-byte value in rax to a user-space shadow-stack location at [rdi]. This is a supervisor-only instruction: it may only be executed at privilege level 0, normally by the operating-system kernel. Although the instruction is executed by the kernel, the memory access is treated as an access to a user-space shadow-stack page. A typical use is constructing or updating a user's shadow stack when delivering a signal or creating a user-space execution context. The destination must be an 8-byte-aligned user shadow-stack location. The instruction does not modify SSP and does not affect the normal program stack.
setssbsy SSP = mark_supervisor_shadow_stack_busy(IA32_PL0_SSP) Activate the supervisor shadow stack recorded in the IA32_PL0_SSP model-specific register and mark its token as busy. The processor first verifies that IA32_PL0_SSP points to a correctly aligned, valid and currently non-busy supervisor shadow-stack token. It then atomically sets the token's busy bit and loads SSP from IA32_PL0_SSP. The busy bit prevents the same supervisor shadow stack from being activated simultaneously by more than one execution context. This is a privileged instruction that may only be executed at CPL 0. It is intended for operating-system or hypervisor code and does not affect the normal stack pointer rsp.
clrssbsy QWORD PTR [rdi] clear_supervisor_shadow_stack_busy(rdi)
SSP = 0
Deactivate a supervisor shadow stack by clearing the busy bit in the token at [rdi]. The processor verifies that the memory operand identifies a valid, aligned supervisor shadow-stack token whose busy bit is currently set. It then atomically clears that bit, allowing the shadow stack to be activated again later. After the busy bit is successfully cleared, the current Shadow Stack Pointer is set to 0. This is a privileged instruction that may only be executed at CPL 0. It is intended for operating-system or hypervisor code and does not modify rsp.
Privileged and operating-system instructions
cli IF = 0 Clear IF, the Interrupt Flag, preventing ordinary maskable hardware interrupts from being delivered to the current logical processor. Non-maskable interrupts and certain other events can still occur. Ordinary Linux user-space programs are not permitted to execute cli; it is intended for kernel or hypervisor code.
sti IF = 1 Set IF, allowing maskable hardware interrupts to be delivered. Interrupt recognition is delayed until after the instruction immediately following sti, allowing code such as sti followed by hlt to avoid a race. This is normally restricted to kernel or hypervisor code.
hlt wait_for_interrupt_or_processor_event() Stop executing instructions until an enabled interrupt or another qualifying processor event occurs. Operating-system idle loops use this to avoid wasting execution resources while no work is available. It is privileged, executing it from an ordinary Linux application causes a general-protection exception.
iretq rip = pop64(); cs = pop64(); rflags = pop64()
/* May also restore rsp and ss */
Return from an interrupt or exception handler in 64-bit mode. Restore rip, cs and rflags from a specially prepared stack frame. When returning across privilege levels, it also restores rsp and ss. This is much more complex than an ordinary ret and is primarily used by kernels, exception handlers and low-level runtimes.
swapgs temporary = GS_BASE
GS_BASE = IA32_KERNEL_GS_BASE
IA32_KERNEL_GS_BASE = temporary
Exchange the current GS segment base with the value stored in the IA32_KERNEL_GS_BASE model-specific register. A 64-bit kernel commonly uses this while entering or leaving the kernel so that gs-relative addresses refer to per-CPU kernel data. It is privileged and must be used carefully around speculative execution and nested kernel-entry paths.
rdmsr edx:eax = MSR[ecx] Read the model-specific register selected by ecx. The high 32 bits are returned in edx and the low 32 bits in eax. MSRs control or report processor facilities such as syscall configuration, performance monitoring and extended control state. The instruction is privileged.
wrmsr MSR[ecx] = edx:eax Write the 64-bit value in edx:eax to the model-specific register selected by ecx. Writing an unsupported MSR, a reserved value or executing the instruction without sufficient privilege causes an exception.
invlpg BYTE PTR [rdi] invalidate_translation_for_page_containing(rdi) Invalidate cached address translations for the memory page containing rdi on the current logical processor. A kernel uses this after changing a page-table entry so later accesses do not use a stale TLB translation. Other logical processors may require separate invalidation through a TLB shootdown. The instruction is privileged.
invd invalidate_caches_without_writeback() Invalidate internal processor caches without first writing modified cache lines back to memory. Unsaved modified data may therefore be lost. This is a highly specialized and dangerous privileged instruction, mainly relevant during unusual hardware or firmware operations.
wbinvd write_back_and_invalidate_caches() Write modified cache lines back toward memory and then invalidate the processor's internal caches. It affects far more data than the cache-line-specific clflush family and is a privileged, system-wide operation.
lgdt [rdi]
lidt [rdi]
GDTR = *(descriptor_pointer *)rdi
IDTR = *(descriptor_pointer *)rdi
Load a descriptor-table register from memory. lgdt loads the Global Descriptor Table Register. lidt loads the Interrupt Descriptor Table Register. In 64-bit mode, the memory structure contains a 16-bit limit followed by a 64-bit base address. These are privileged system-configuration instructions.
ltr ax TR = ax Load the Task Register with a segment selector identifying a Task State Segment descriptor in the GDT. In 64-bit systems, the TSS contains information such as privileged stack pointers and Interrupt Stack Table entries. The processor validates the descriptor and marks the available TSS descriptor as busy. The instruction is privileged.
Legacy instructions unavailable in 64-bit mode
bound eax, [rsi] if (eax < lower_bound || eax > upper_bound) raise_bound_exception() In older 16- and 32-bit modes, compare a signed array index with lower and upper bounds stored consecutively in memory. Raise the bounds-range exception (#BR) when the index is outside the inclusive range. bound is not available in 64-bit mode and causes an invalid-opcode exception there. It is included to help recognize older disassembly.
aaa, aas, aam, aad, daa, das adjust_legacy_decimal_or_ascii_arithmetic() Adjust results produced by old unpacked or packed binary-coded-decimal and ASCII arithmetic conventions. These instructions were designed for historical decimal-processing techniques involving al, ah and selected flags. They are not available in 64-bit mode and are not used for ordinary modern integer arithmetic. It is included to help recognize older disassembly.