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.
|
cbwcwdecdqe
|
ax = (int16_t)(int8_t)aleax = (int32_t)(int16_t)axrax = (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.
|
cwdcdqcqo
|
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:
idiv instruction.
|
div ecx |
eax = edx:eax / ecxedx = 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 / rcxrdx = (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 + CFrax = (uint64_t)sumCF = 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 + OFrax = (uint64_t)sumOF = 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)) & 1rax |= 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)) & 1rax &= ~(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)) & 1rax ^= 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 & 0xfflength = (rcx >> 8) & 0xffrax = 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 *)rsprsp += 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, sourcecmove 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 destinationsete 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 *)rsprsp += 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 = rbprbp = *(uint64_t *)rsprsp += 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 = rsprsp -= 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 = rcxrflags = r11return_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_CSinstruction_pointer = IA32_SYSENTER_EIPstack_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 = edxuser_stack_pointer = ecxreturn_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 labelloopz 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 labelloopnz 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 labeljecxz label
|
if (rcx == 0) goto labelif (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 labeljz 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 labeljnz 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 labeljnle 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 labeljnl 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 labeljnge 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 labeljng 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 labeljnbe 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 labeljnb labeljnc 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 labeljnae labeljc 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 labeljna 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 = raxrax = 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 += raxrax = 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 cmpsbrepz 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 scasbrepnz 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:
|
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:
|
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], xmm0vmovntdq XMMWORD PTR [rdi], xmm0vmovntdq 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], xmm0vmovntps XMMWORD PTR [rdi], xmm0vmovntps 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], xmm0vmovntpd XMMWORD PTR [rdi], xmm0vmovntpd 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 *)rsixmm0.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, xmm1addsd 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, xmm1subsd 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, xmm1mulsd 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, xmm1divsd 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, xmm1sqrtsd 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, xmm1minsd 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, xmm1maxsd 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, xmm1ucomisd 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, raxcvtsi2sd xmm0, rax
|
xmm0.f32[0] = (float)(int64_t)raxxmm0.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, xmm0cvtsd2si 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, xmm0cvttsd2si 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, xmm1cvtsd2ss 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, ymm2vfmadd132pd ymm0, ymm1, ymm2vfmadd132ss xmm0, xmm1, xmm2vfmadd132sd 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, ymm2vfmadd213pd ymm0, ymm1, ymm2vfmadd213ss xmm0, xmm1, xmm2vfmadd213sd 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, ymm2vfmadd231pd ymm0, ymm1, ymm2vfmadd231ss xmm0, xmm1, xmm2vfmadd231sd 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:
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.
|
fninitfinit |
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, eaxmovq xmm0, rax
|
xmm0.low32 = eaxxmm0.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, xmm1paddw xmm0, xmm1paddd xmm0, xmm1paddq 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, xmm1vpsubb/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, xmm1pmulld xmm0, xmm1vpmullw/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, xmm1vsubps/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, xmm1vmulps/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, xmm1vdivps/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, xmm1vsqrtps/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, xmm1vpcmpeqb/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, xmm1vpcmpgtb/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, imm8cmppd xmm0, xmm1, imm8vcmpps/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, xmm0vmovmskps 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, xmm0vmovmskpd 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, xmm0vpmovmskb 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, imm8vpshufd 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, xmm1vpshufb 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/punpckhbwpunpcklwd/punpckhwdpunpckldq/punpckhdqpunpcklqdq/punpckhqdqvpunpck* 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/packssdwpackuswb/packusdwvpack* 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, 8vpalignr 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, countvpsllw/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, countvpsrlw/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, countvpsraw/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, xmm2vpxor 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, xmm2vpaddw xmm0, xmm1, xmm2vpaddd xmm0, xmm1, xmm2vpaddq xmm0, xmm1, xmm2vpaddb ymm0, ymm1, ymm2vpaddw ymm0, ymm1, ymm2vpaddd ymm0, ymm1, ymm2vpaddq 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, xmm2vaddps 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/kaddqkandb/kandw/kandd/kandqkandnb/kandnw/kandnd/kandnqkorb/korw/kord/korqkxorb/kxorw/kxord/kxorqkxnorb/kxnorw/kxnord/kxnorqknotb/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/kmovqkshiftlb/kshiftlw/kshiftld/kshiftlqkshiftrb/kshiftrw/kshiftrd/kshiftrqkunpckbw/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/ktestqkortestb/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/vaddsdvsubps/vsubpd/vsubss/vsubsdvmulps/vmulpd/vmulss/vmulsdvdivps/vdivpd/vdivss/vdivsdvsqrtps/vsqrtpd/vsqrtss/vsqrtsdvminps/vminpd/vminss/vminsdvmaxps/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/vrcp14sdvrsqrt14ps/vrsqrt14pd/vrsqrt14ss/vrsqrt14sdvscalefps/vscalefpd/vscalefss/vscalefsdvgetexpps/vgetexppd/vgetexpss/vgetexpsdvgetmantps/vgetmantpd/vgetmantss/vgetmantsdvrndscaleps/vrndscalepd/vrndscaless/vrndscalesdvreduceps/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/vpaddqvpsubd/vpsubqvpmulld/vpmuldq/vpmuludqvpandd/vpandqvpandnd/vpandnqvpord/vporqvpxord/vpxorqvpminsd/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/vpsllvqvpsrld/vpsrlq/vpsrlvd/vpsrlvqvpsrad/vpsraq/vpsravd/vpsravqvprold/vprolq/vprolvd/vprolvqvprord/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/vpcmpuqvcmpps/vcmppd/vcmpss/vcmpsdvptestmd/vptestmqvptestnmd/vptestnmqvfpclassps/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/vmovdqa64vmovdqu32/vmovdqu64vbroadcastss/vbroadcastsdvpbroadcastd/vpbroadcastqvbroadcastf32x2/vbroadcastf32x4/vbroadcastf32x8vbroadcastf64x2/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/vpmovdqvpmovqb/vpmovqw/vpmovqdvpmovs*/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/vgatherqpdvpgatherdd/vpgatherdq/vpgatherqd/vpgatherqqvscatterdps/vscatterdpd/vscatterqps/vscatterqpdvpscatterdd/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/vcompresspdvpcompressd/vpcompressqvexpandps/vexpandpdvpexpandd/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/vpermpdvpermi2d/vpermi2q/vpermi2ps/vpermi2pdvpermt2d/vpermt2q/vpermt2ps/vpermt2pdvshufi32x4/vshufi64x2vshuff32x4/vshuff64x2valignd/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/vextractf32x8vextractf64x2/vextractf64x4vextracti32x4/vextracti32x8vextracti64x2/vextracti64x4vinsertf32x4/vinsertf32x8vinsertf64x2/vinsertf64x4vinserti32x4/vinserti32x8vinserti64x2/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/vpconflictqvplzcntd/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/vexp2pdvrcp28ps/vrcp28pd/vrcp28ss/vrcp28sdvrsqrt28ps/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/vgatherpf0dpdvgatherpf0qps/vgatherpf0qpdvgatherpf1dps/vgatherpf1dpdvgatherpf1qps/vgatherpf1qpdvscatterpf0dps/vscatterpf0dpdvscatterpf0qps/vscatterpf0qpdvscatterpf1dps/vscatterpf1dpdvscatterpf1qps/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/vpaddwvpsubb/vpsubwvpaddsb/vpaddsw/vpaddusb/vpadduswvpsubsb/vpsubsw/vpsubusb/vpsubuswvpcmpeqb/vpcmpeqwvpcmpb/vpcmpw/vpcmpub/vpcmpuwvpmovb2m/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. |
vpmullqvpminsq/vpminuq/vpmaxsq/vpmaxuqvpmovq2m/vpmovd2m/vpmovm2q/vpmovm2dvandps/vandpd/vandnps/vandnpdvorps/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. |
vpmadd52luqvpmadd52huq
|
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. |
vpermbvpermi2b/vpermi2wvpermt2b/vpermt2wvpmultishiftqb
|
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/vpcompresswvpexpandb/vpexpandwvpshldw/vpshldd/vpshldqvpshrdw/vpshrdd/vpshrdqvpshldvw/vpshldvd/vpshldvqvpshrdvw/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/vpdpbusdsvpdpwssd/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.
|
vpshufbitqmbvpopcntb/vpopcntwvpopcntd/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.
|
vp2intersectdvp2intersectq
|
(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. |
vcvtneps2bf16vcvtne2ps2bf16vdpbf16ps
|
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/vaddshvsubph/vsubshvmulph/vmulshvdivph/vdivshvsqrtph/vsqrtshvfmadd*/vfmsub*/vfnmadd*/vfnmsub* ph/shvcvt*ph/vcvt*shvcmulcph/vfcmulcphvfmaddcph/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/vaesenclastvaesdec/vaesdeclastvpclmulqdqvgf2p8affineinvqbvgf2p8affineqbvgf2p8mulb
|
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/v4fnmaddpsvp4dpwssd/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-IFMAAVX-NE-CONVERTAVX-VNNI-INT8AVX-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:
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:
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:
|
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 = SSPSSP = 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:
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 raxnotrack 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:
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_BASEGS_BASE = IA32_KERNEL_GS_BASEIA32_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 *)rdiIDTR = *(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.
|