The x64 processors can execute a wide range of instructions. As processors have evolved, the instruction set has expanded from the initial 117 in the 8086 processor to over 1000 in modern 64-bit designs. In this chapter, we present the instruction groups and describe the essential general-purpose instructions.
In the processor documentation, we can find several ways to group all instructions. The most general division, according to AMD, defines five groups of instructions:
Intel defines the following groups of instructions.
There is also a long list of extensions defined, including SSE4.1, SSE4.2, Intel AVX, AMD 3DNow! and many others. For a detailed description of instruction groups, please refer to:
Details of every instruction can be found in the description of the instruction set:
There are also specialised websites with detailed instructions that you can use to find a lot of additional information. Among others, you can visit:
In this book, we will present most of the general-purpose instructions and provide general ideas on the chosen extensions, including FPU, MMX, SSE, and AVX.
General-purpose instructions can be divided into some subgroups.
Before describing instructions, let's present the condition codes. The condition code is a suffix to the instruction and influences its behaviour: if the condition is met, the instruction is executed; otherwise, the processor proceeds to the next instruction in the program. The condition that is checked during the execution of the conditional instruction is based on the current state of the flags in the EFLAGS register. The flags in the EFLAGS register are modified by instructions, mainly arithmetic, logical, shift, or special flag manipulation instructions. It is important to note that flags are not modified when copying data, so to check whether the value just read is zero, you should perform, for example, a comparison. Condition codes, together with checked flags, are presented in table 1.
| Condition code cc | Flags checked | Comment |
|---|---|---|
| E | ZF = 1 | Equal |
| Z | ZF = 1 | Zero |
| NE | ZF = 0 | Not equal |
| NZ | ZF = 0 | Not zero |
| A | CF=0 and ZF=0 | Above |
| NBE | CF=0 and ZF=0 | Not below or equal |
| AE | CF=0 | Above or equal |
| NB | CF=0 | Not below |
| B | CF=1 | Below |
| NAE | CF=1 | Not above or equal |
| BE | CF=1 or ZF=1 | Below or equal |
| NA | CF=1 or ZF=1 | Not above |
| G | ZF=0 and SF=OF | Greater |
| NLE | ZF=0 and SF=OF | Not less or equal |
| GE | SF=OF | Greater or equal |
| NL | SF=OF | Not less |
| L | SF<>OF | Less |
| NGE | SF<>OF | Not greater or equal |
| LE | ZF=1 or SF<>OF | Less or equal |
| NG | ZF=1 or SF<>OF | Not greater |
| C | CF=1 | Carry |
| NC | CF=0 | Not carry |
| O | OF=1 | Overflow |
| NO | OF=0 | Not ovrflow |
| S | SF=1 | Sign (negative) |
| NS | SF=0 | Not sign (non-negative) |
| P | PF=1 | Parity |
| PE | PF=1 | Parity even |
| NP | PF=0 | Not parity |
| PO | PF=0 | Parity odd |
Almost all assembler tutorials start with the presentation of the mov instruction, which is used to copy data from the source operand to the destination operand. Our book is no exception, and we've already shown this instruction in the examples presented in previous sections.
Let's look at some additional variants.
mov AL, BL ;copy one byte from BL to AL mov AX, BX ;copy word (two bytes) from BX to AX mov EAX, EBX ;copy doublweword (four bytes) from EBX to EAX mov RAX, RBX ;copy quadword (eight bytes) from RBX to RAX
In the mov instruction, the size of the source argument must be the same as the size of the destination argument. Arguments can be stored in registers or in memory, addressed directly or indirectly. One of them can be constant (immediate). Only one memory argument is allowed. This comes from the instructions encoding. In instructions, there is only one possible direct or indirect argument to be encoded. That's why most instructions, not only mov, can operate on a single memory argument. There are some exceptions, for example, string instructions, but such instructions use specific indirect addressing.
mov AL, 100 ;0xB0, 0x64 ;copy constant (immediate) of the value 100 (0x64) to AL mov AL, [BX] ;0x67, 0x8A, 0x07 ;copy byte from the memory at address stored in BX to AL ;(indirect addressing) ;Notice the difference between two following instructions mov EAX, 100 ;0xB8, 0x64, 0x00, 0x00, 0x00 ;copy constant 100 to EAX mov EAX, [100] ;0xA1, 0x64, 0x00, 0x00, 0x00 ;copy value from memory at address 100 ;It is possible to copy a constant to memory addressed directly or indirectly ;operand size specifier dword ptr is required ;to inform the processor about the size of the argument mov dword ptr DS:[200], 100 ;0xC7, 0x05, 0xC8, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00 ;copy value of 100, encoded as dword (four bytes), 0x64 = 100 ;to memory at address 200, encoded as four bytes, 0xC8 = 200 mov dword ptr [EBX], 100 ;0xC7, 0x03, 0x64, 0x00, 0x00, 0x00 ;copy value of 100, encoded as dword (four bytes), 0x64 = 100 ;to memory addressed by EBX
Starting from the P6 machines, the conditional move instruction was introduced.
This works similarly to mov, but copies data if the specified condition is true. The condition code is one of the codes listed in the “Condition Codes” section. If the condition is false, the instruction passes through without modifying the arguments. Conditional move instructions can be used to avoid conditional jumps. For example, if we need to copy data from EBX to ECX, if the result of the previous operation is negative, we can write the following instruction.
cmovs ECX, EBX
In the situation of copying data of a smaller size (expressed in number of bits) to a bigger destination argument, the question arises as to what to do with the remaining bits. Let us consider copying an 8-bit value from BL to the 16-bit AX register. If the value copied is unsigned or positive (let it be 5), the remaining bits should be cleared.
; AH AL mov AL, BL ; 00000101 = 5 in AL mov AH, 0 ;00000000 ;0000000000000101 = 5 in AX
If the value is negative (e.g. -5) the situation changes.
; AH AL mov AL, BL ; 11111011 = -5 in AL mov AH, 0 ;00000000 ;0000000011111011 = 251 in AX
It is clear that, to preserve the original value, the upper bits must be set to ones, not zeros.
; AH AL mov AL, BL ; 11111011 = -5 in AL mov AH, 0xFF ;11111111 ;1111111111111011 = -5 in AX
There are special instructions which perform automatic sign extension, copying the sign bit to all higher bit positions. They can be considered as type conversion instructions. These instructions have no arguments, as they operate only on the accumulator.
Sign-extension instructions operate solely on the accumulator. Fortunately, there are also more general instructions that copy and extend data simultaneously.
The exchange instruction swaps the values of the operands. A single exchange instruction can replace three mov instructions while swapping the contents of two arguments, so they can be useful in optimising some algorithms. They help implement semaphores, even in multiprocessor systems.
The cmpxchg has three arguments: source, destination and accumulator. It compares the destination argument with the accumulator; if they are equal, the destination argument value is replaced with the value from the source operand. It is used to test and modify semaphores. Its operation is presented in figure 1. In newer machines, the eight- and sixteen-byte versions were added cmpxchg8b and cmpxchg16b. They always use ECX:EBX or RCX:RBX as the source register pair and EDX:EAX or RDX:RAX as the accumulator pair. The destination argument is in the memory.
A stack is a special structure in the memory that automatically stores the return address (address of the next instruction) while procedure calling (it is described in detail in the section about the call instruction). It is also possible to use the stack for local variables in functions, for passing arguments to procedures, and for storing temporary data. In the x86 architecture, the stack is supported by hardware with the special stack pointer register. Instructions that operate on the stack automatically modify the stack pointer so that it always points to the top of the stack.
Some instructions push or pop all eight general-purpose registers (including the stack pointer).
The order of registers on the stack for these instructions is shown in figure 5. These instructions are not supported in 64-bit mode.
Arithmetic instructions perform calculations on binary encoded data. It is worth noting that the processor does not distinguish between unsigned and signed values; it is the responsibility of the programming engineer to provide correct input values and to interpret the results properly.
There are two adding instructions.
Similarly, there are two subtraction instructions.
The argument can be incremented or decremented. The argument is treated as an unsigned integer.
Two multiply instructions are implemented.
The mul is a one-argument instruction. It multiplies the argument and the accumulator, treating them as unsigned numbers. The size of the accumulator corresponds to the size of the argument. The result is stored in the accumulator. Since multiplication can produce results twice as large as the input values, it is stored in a larger accumulator size, as shown in the table 2.
| Argument | Accumulator | Result |
|---|---|---|
| 8 bits | AL | AX |
| 16 bits | AX | DX:AX |
| 32 bits | EAX | EDX:EAX |
| 64 bits | RAX | RDX:RAX |
The imul instruction performs signed multiplication. It can have one, two or three arguments. The single-argument version behaves the same way as the mul instruction. The two-argument version multiplies the 16-, 32-, or 64-bit register as the destination operand by the argument of the same size. The three-argument version multiplies the source argument by the immediate and stores the result in the destination, which is the same size as the arguments. The destination must be the register.
Two divide instructions are implemented.
The div is a one-argument instruction. It divides the accumulator's contents by the argument, treating both as unsigned numbers. The size of the accumulator is twice the size of the argument. The result is stored as two integer values of the same size as the argument. The quotient is placed in the lower half of the accumulator, and the remainder in the higher half of the accumulator. Depending on the size of the argument, the accumulator is understood as a pair of registers DX:AX, EDX:EAX or RDX:RAX, as shown in the table 3.
| Argument | Accumulator | Quotient | Remainder |
|---|---|---|---|
| 8 bits | AX | AL | AH |
| 16 bits | DX:AX | AX | DX |
| 32 bits | EDX:EAX | EAX | EDX |
| 64 bits | RDX:RAX | RAX | RDX |
The idiv instruction performs signed division. It behaves the same way as the div instruction except for the type of numbers.
The set of logical instructions contains:
All of them perform bitwise Boolean operations corresponding to their names. The not is a single-argument instruction; others have two arguments.
Shift and rotate instructions treat the argument as the shift register. Each bit of the argument is moved to the neighbouring position on the left or right, depending on the direction of the shift. The number of bit positions for the shift can be specified as a constant or in the CX register. Shift instructions can be used to multiply (shift left) and divide (shift right) by powers of two.
Shift instructions have two versions: logical and arithmetical.
The shl and sal behave the same, filling the empty bits (at the LSB position) with zeros. Logical shift right shr fills the empty bits (at the MSB position) with zeros, while the arithmetical shift right sar makes a copy of the most significant bit, preserving the sign of a value. It is shown in figure 6.
Two double-shift instructions move bits from the source argument to the destination argument. The number of bits is specified as the third argument.
The operation of shift double instructions is presented in figure 7.
For all shift instructions, the last bit shifted out is placed in the carry flag.
Rotate instructions move bits shifted out of one side of an argument into the opposite side.
Rotate instructions shift bits left rol or right ror in the argument, and additionally move bits around from the lowest to the highest or from the highest to the lowest position. Behaviour of rotate instructions is shown in figure 8.
Rotate with carry left rcl and right rcr, treat the carry flag as the additional bit during rotation. They can be used to collect bits to form multi-bit data. Behaviour of rotate with carry instructions is shown in figure 9.
Bit test instruction makes a copy of the selected bit into the carry flag.
A combination of two arguments specifies the bit for testing. The first argument, called the bit-base operand, holds the bit. It can be a register or a memory location. The second operand is the bit offset, which specifies the position of the bit operand. It can be a register or an immediate value. It starts counting from 0, so the least significant bit has the position 0. An example of the behaviour of the bt instruction is shown in figure 10.
Bit test and modify instructions first make a copy of the selected bit, and next modify the original bit value with the one specified by the instruction.
The bit scan instructions search for the first occurrence of a bit set to 1.
The bsf scans from the least significant bit towards higher bits, and the bit scan reverse bsr scans from the most significant bit towards lower bits. Both instructions return the index of the found bit in the destination register. If there is no bit of the value 1, the zero flag is set, and the destination register value is undefined.
Byte instructions are used to test the content of an argument, set the argument based on the condition, count the number of bits equal to “1” and compute CRC.
The condition can be freely chosen from the set of conditions available for other instructions, for example, cmovcc. This instruction is useful for converting the result of the operation into a Boolean representation.
Before describing the instructions used for control transfer, we will discuss how to calculate the destination address. The destination address is the address the processor jumps to.
While segmentation is enabled, the destination address can be specified either as an offset or in full logical form.
If there is an offset only, the instruction modifies the instruction pointer solely, the jump is performed within the current segment and is called near.
If the address is provided in full logical form, containing segment and offset parts, the CS and IP registers are modified. Such an instruction can perform a jump between segments and is called far.
An absolute address is given as a value specifying the destination address as the number of the byte counted from the beginning of the memory, or, if segmentation is enabled, as the offset from the beginning of the segment.
A relative address is calculated as the difference between the current value of the instruction pointer and the absolute destination address. It is provided in the instructions as the signed number representing the distance between the current and destination addresses.
If it is possible to encode the difference as an 8-bit signed value, the jump is called short.
Usually, an assembler automatically chooses the shortest possible encoding.
Conditional transfer instructions check the state of the selected flags in the Flags register and jump to the specified address if the condition evaluates to true. If the condition evaluates to false, the processor proceeds to the next instruction in the instruction stream.
Conditions are specified the same way as in the cmovcc instruction as the suffix to the main mnemonic. Unconditional transfer instructions are always executed the same way. They jump to the specified address without any condition checking.
Unconditional control-transfer instructions perform a jump to a new address, changing the program flow.
The process of calling a procedure and returning to the main program is shown in figure 11.
An interrupt mechanism in x86 works with hardware-signalled interrupts or with special interrupt instructions. Return from an interrupt handler is performed by executing the interrupt return instruction.\\
In 32 and 64-bit architectures, the mnemonic for this instruction is iretd.
The iret instruction differs from the ret instruction in that it pops not only the return address but also the contents of the Flags register from the stack. This keeps the content of this register unmodified upon return and prevents unintentional blocking after interrupts.
The process of an interrupt handler being called and returning to the main program is shown in figure 12.
Software interrupts can be generated as an exception or with a special instruction. They are handled the same way as hardware-signalled interrupts.
The last two instructions are not valid in 64-bit mode.
Conditional control transfer instructions are used to test the state of the flags and to perform a jump to the destination address if the condition is met. They are formed as a jump instruction with the mnemonic expanded by a condition code.
In modern pipelined processors, it is recommended to avoid conditional jumps whenever possible to ensure the program flows continuously without invalidating the pipeline. It is important to remember that flags are modified as a result of executing the arithmetic or logic instruction, but not the mov instruction. For example, if we need to test if some variable is zero, we can write such code:
cmp var1, 0 ;compare variable jz is_zero ;conditional jump to address is_zero mov RAX, "1" ;if not zero, put ASCII code of "1" in RAX jmp not_zero ;jump unconditionally over the next instruction is_zero: ;label to jump to if var1 is zero mov RAX, "0" ;if zero, put ASCII code of "0" in RAX not_zero: ;label to jump to if var1 is not zero
The instructions are used to implement a software loop. It can be executed a known number of times or finished prematurely. The number of iterations should be set before a loop in the counter register (CX/ECX/RCX).
The loop instruction automatically decrements the counter register, checks if it reaches zero and if not jumps to the address, which is the argument of the instruction and is assumed as the beginning address of a loop. If the counter reaches zero, the loop instruction goes further to the next instruction in a stream.
There are also conditional versions of the loop instruction that allow the iteration to finish before the counter reaches zero.
The loope or loopz instructions continue the iteration if the counter is above zero and the zero flag (ZF) is set.
The loopne or loopnz continue the iteration if the counter is greater than zero and the zero flag (ZF) is cleared.
The loop instruction can cause the system to iterate many times if the counter register is zero before entering the loop. Since the first step is to decrement the counter, the result will be a value composed entirely of “1s”. For CX, the loop will be executed 65536 times; for ECX, more than 4 billion times; and for RCX, 184 quintillion 466 quadrillion 744 trillion 73 billion 709 million 551 thousand and 616 times!
Understandably, we should avoid such a situation. We have three instructions to jump over the loop if the counter is zero.
These instructions can help to jump over the entire loop if the counter register is zero at the beginning, as in the following code.
lea RBX, table ;pointer to table with values to sum mov RCX, size ;size of a table - we can't ensure it's not zero xor RDX, RDX ;zero RDX - it will be the sum af elements jrcxz end_loop ;jump over the loop if rcx is zero begin_loop: add RDX, [RBX] ;add the item to the resulting value inc RBX ;point to another item in a table loop begin_loop ;loop end_loop:
String instructions are developed to perform operations on elements of data tables, including text strings. These instructions can access two memory locations: the source and the destination. If segmentation is enabled, the source operand is identified with SI/ESI.
It is always placed in the data segment (DS), while the destination operand is identified with DI/EDI and is stored in the extended data segment (ES).
In 64-bit mode, the source operand is identified with RSI, and the destination operand is identified with RDI.
They can operate on bytes, words, double words, or quad words.
The size of the element is specified as the suffix of the instruction or derived from the size of the arguments specified in the instruction.
These instructions store the accumulator's contents into the destination operand.
These instructions load the content of the source string to the accumulator.
Strings can be compared, which means that the element of the destination string is compared with the element of the source string. These instructions set the status flags in the flags register according to the result of the comparison. The elements of both strings remain unchanged.
Strings can be scanned, which means that the element of the destination string is compared with the accumulator. These instructions set the status flags in the flags register according to the result of the comparison. The accumulator and string element remain unchanged.
The repetition prefix can precede all string instructions to automate the processing of multiple-element tables. Use of the prefix enables the instruction to automatically repeat execution based on the counter register's contents and to modify the source and destination addresses in the index registers according to the element size.
Index registers can be incremented or decremented depending on the direction flag (DF) state. If DF is “0”, the addresses are incremented; if DF is “1”, the addresses are decremented. While the string element's size is a byte, the addresses are modified by 1. For words, the addresses are modified by 2, for doublewords by 4, and for quadwords by 8.
The use of repeated string instructions enables copying an entire string from one place in memory to another or filling memory regions with a pattern.
The conditional prefixes are intended to be used with scas or cmps instructions.
The use of repeated-string instructions with conditional prefixes enables string comparisons for equality or difference, or for finding an element in a string.
To properly use the repeated string instructions, follow these steps:
These instructions allow the processor to transfer data between the accumulator register and a peripheral device.
A peripheral device can be addressed directly or indirectly. Direct addressing uses an 8-bit constant as the peripheral address (also called an I/O port in x86), and it accesses only the first 256 port addresses. Indirect addressing uses the DX register as the address register, enabling access to the entire I/O address space of 65536 addresses.
The I/O instructions also have string versions.
Instructions to read the port to a string are:
Instructions to write a string to a port are
In all string I/O instructions, the port is addressed with the DX register. Rules for addressing the memory are the same as in string instructions.
Enter instruction creates the stack frame for the function. The stack frame is a region of the stack reserved for a function to store arguments and local variables. Traditionally, we access the stack frame using the RBP register, but we need to preserve its contents before use.
The enter instruction can be nested or non-nested. Not-nested saves the RBP on the stack, copies the stack pointer value to RBP, and adjusts the stack pointer with the constant value, which is the first operand of the instruction. After these steps, the RSP points to the top of the stack frame, and the RBP points to the stack base. The nested version creates the path to the higher-level functions' stack frames by adding their momentary value of RBP.
The leave instruction reverses what enter did at the end of the function. The enter should be placed at the very beginning of the function, while the leave just before ret.
Flag control instructions are typically used to set or clear the chosen flag in the RFLAGS register. We can only control three flags directly.
The carry (CF) flag can be used in conjunction with the rotate-with-carry instructions to convert the series of bits into a binary-encoded value.
The direction (DF) flag determines whether the index registers RSI and RDI are modified when executing string instructions. If the DF flag is clear, the index registers are incremented; if the DF flag is set, the registers are decremented after each iteration of a string instruction.
The interrupt (IF) flag controls whether hardware interrupts are enabled. If the IF flag is set, the hardware interrupts are enabled; if the IF flag is clear, hardware interrupts are masked.
The summary of instructions is shown in the table 4.
| Instruction | Behavoiur | flag affected |
|---|---|---|
| stc | set carry flag | CF=1 |
| clc | clear carry flag | CF=0 |
| cmc | complement carry flag | CF=not CF |
| std | set direction flag | DF=1 |
| cld | clear direction flag | DF=0 |
| sti | set interrupt flag | IF=1 |
| cli | clear interrupt flag | IF=0 |
The flags register can be pushed onto the stack and popped afterwards. This can be done inside the procedure, but also to test or manipulate bits in the flags register, for which a special instruction does not support modifications.
Segment register instructions load a far pointer into a pair of registers. One of the pair is the segment, which is determined by the instruction; the other is the offset, which appears as the destination argument. The source argument is the far pointer stored in the memory. These instructions include:
The following example shows how to load a far pointer in 16-bit mode.
; Load far pointer to DS:BX ; Variable Far_point holds the 32-bit address lds BX,Far_point ; Instruction above is equal to: mov AX,WORD PTR Far_point+2 ; Take higher word of far pointer mov DS,AX ; Store it in DS mov BX,WORD PTR Far_point ; Store lower word of far pointer in BX
In 64-bit mode, lds and les instructions are not supported.
Multiple other instructions fall outside the classification presented above. A brief review is presented below.
The no-operation instruction results in an incrementation of the instruction pointer only.
In reality, it is an alias to the instruction xchg EAX, EAX.
nop ;encoded as 0x90 xchg EAX, EAX ;encoded as 0x90
The load effective address instruction calculates the effective address as the result of the proper address expression and stores the result in a destination operand.
We can store the effective address in a single register to avoid complex address calculations within a loop, as in the following example.
; Load effective address to BX ; Table is the beginning of the table in the memory lea BX,Table[SI] ; Now we can use BX only to make the program run faster: hoop: mov AX,[BX] ; Take value from table inc BX ; Next element in the table cmp AX,0 ; Check if element is 0 jne hoop ; Jump to „hoop" if AX isn't 0
The undefined instructions can be used to test the behaviour of the system software in the event of an unknown opcode appearing in the instruction stream.
The first two instructions can have a source operand (a register or memory address) and a destination operand (a register). Operands are not used. The ud2 instruction has no operand.
Table lookup instructions load the element of a table pointed to by a base address and the index of an element.
The xlatb instruction copies the byte from a table into the AL register. The byte is addressed as the sum of the BX/EX/RBX and AL registers. There is also an xlat version, which allows specifying the memory address as the argument. It can be somewhat misleading because the processor never uses the argument. This instruction can be used to convert a 4-digit binary value to a hexadecimal digit, as shown in the following code.
.DATA conv_table DB "0123456789ABCDEF" .CODE ; Load base address of table to BX lea RBX, conv_table and AL, 0Fh ; Limit AL to 4 bits xlatb ; Take element from the table mov char, AL ; Resulting char is in AL
The processor identification instruction provides detailed information about the processor's hardware features.
It operates similarly to the function, with the input value sent via an accumulator (EAX). Depending on the EAX value, the processor provides different information. The requested information is returned in processor registers. For example, if EAX is zero, it returns the vendor information string “GenuineIntel” for Intel processors and “AuthenticAMD” for AMD models in the ECX, EDX, and EBX registers. It is shown in figure 13.
This instruction moves data after swapping data bytes. It operates on words, doublewords or quadwords and is usually used to change the endianness of the data.
The processor manages cache memory, and its decisions usually maintain good software execution performance. However, the processor offers instructions that allow the programmer to send hints to the cache management mechanism and prefetch data in advance of using it and to synchronise the cache and memory and flush the cache line to make it available for other data.
There are also additional instructions for cache management, introduced together with the multimedia and vector extensions.
Some instructions allow saving and restoring the state of several processor units. They are intended to help processors with fast context switching between processes and to replace the practice of saving each register separately at the beginning of a subroutine and restoring it at the end. The content of registers is stored in memory pointed to by the EDX:EAX registers.
Instructions for saving the state are:
Instructions for restoring the state are:
In the x64 architecture, there are two instructions for generating a random number.
A specially designed hardware unit generates a random number. The difference between instructions is that rdseed gets random bits generated from entropy gathered from a sensor on the chip. It is slower but offers better randomness of the number.
The rdrand gets bits from a pseudorandom number generator. It is faster, offering output that is sufficiently secure for most cryptographic applications.
The abbreviation BMI comes from Bit Manipulation Instructions. These instructions are designed for specific bit manipulation in the arguments, enabling programmers to use a single instruction instead of several.
There are additional shift and rotate instructions that do not affect flags, allowing for more predictable execution without relying on flag changes from previous operations.
Also, unsigned multiplication without affecting flags, mulx, was introduced.
Other instructions manipulate bits as the group name stays.
For an argument that is not zero, lzcnt returns the number of zeros before the first 1 from the left, and tzcnt gives the number of zeros before the first 1 from the right.
The bextr instruction copies the number of bits from source to destination arguments starting at the chosen position. The third argument specifies the number of bits and the starting bit position. Bits 7:0 of the third operand specify the starting bit position, while bits 15:8 specify the maximum number of bits to extract, as shown in figure 14.
The blsi instruction extracts the single, lowest bit set to one, as shown in figure 15.
The blsmsk instruction sets all lower bits below a first bit set to 1. It is shown in figure 16.
The blsr instruction resets (clears the bit to zero value) the lowest set bit. It is shown in figure 17.
The bzhi instruction resets high bits starting from the specified bit position, as shown in figure 18.
The pdep instruction performs a parallel deposit of bits using a mask. Its behaviour is shown in figure 19.
The pext instruction performs parallel bit extraction using a mask. Its behaviour is shown in figure 20.