The group of logical instructions includes:
- The Boolean operation instructions - Bit test and modify instructions - Bit scan instructions - Rotate and shift instructions - Byte set on condition
The logical operations are AND, OR, XOR, and NOT.
NOT (Not) inverts the bits in the specified operand to form a one's complement of the operand. The NOT instruction is a unary operation that uses a single operand in a register or memory. NOT has no effect on the flags.
The AND, OR, and XOR instructions perform the standard logical operations "and", "(inclusive) or", and "exclusive or". These instructions can use the following combinations of operands:
- Two register operands - A general register operand with a memory operand - An immediate operand with either a general register operand or a memory operand.AND, OR, and XOR clear OF and CF, leave AF undefined, and update SF, ZF, and PF.
This group of instructions operates on a single bit which can be in memory or in a general register. The location of the bit is specified as an offset from the low-order end of the operand. The value of the offset either may be given by an immediate byte in the instruction or may be contained in a general register.
These instructions first assign the value of the selected bit to CF, the carry flag. Then a new value is assigned to the selected bit, as determined by the operation. OF, SF, ZF, AF, PF are left in an undefined state. Table 3-1 defines these instructions.
Instruction Effect on CF Effect on Selected BitBit (Bit Test) CF <- BIT (none) BTS (Bit Test and Set) CF <- BIT BIT <- 1 BTR (Bit Test and Reset) CF <- BIT BIT <- 0 BTC (Bit Test and Complement) CF <- BIT BIT <- NOT(BIT)
These instructions scan a word or doubleword for a one-bit and store the index of the first set bit into a register. The bit string being scanned may be either in a register or in memory. The ZF flag is set if the entire word is zero (no set bits are found); ZF is cleared if a one-bit is found. If no set bit is found, the value of the destination register is undefined.
BSF (Bit Scan Forward) scans from low-order to high-order (starting from bit index zero).
BSR (Bit Scan Reverse) scans from high-order to low-order (starting from bit index 15 of a word or index 31 of a doubleword).
The shift and rotate instructions reposition the bits within the specified operand.
These instructions fall into the following classes:
- Shift instructions - Double shift instructions - Rotate instructions
The bits in bytes, words, and doublewords may be shifted arithmetically or logically. Depending on the value of a specified count, bits can be shifted up to 31 places.
A shift instruction can specify the count in one of three ways. One form of shift instruction implicitly specifies the count as a single shift. The second form specifies the count as an immediate value. The third form specifies the count as the value contained in CL. This last form allows the shift count to be a variable that the program supplies during execution. Only the low order 5 bits of CL are used.
CF always contains the value of the last bit shifted out of the destination operand. In a single-bit shift, OF is set if the value of the high-order (sign) bit was changed by the operation. Otherwise, OF is cleared. Following a multibit shift, however, the content of OF is always undefined.
The shift instructions provide a convenient way to accomplish division or multiplication by binary power. Note however that division of signed numbers by shifting right is not the same kind of division performed by the IDIV instruction.
SAL (Shift Arithmetic Left) shifts the destination byte, word, or doubleword operand left by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL). The processor shifts zeros in from the right (low-order) side of the operand as bits exit from the left (high-order) side. See Figure 3-6.
SHL (Shift Logical Left) is a synonym for SAL (refer to SAL).
SHR (Shift Logical Right) shifts the destination byte, word, or doubleword operand right by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL). The processor shifts zeros in from the left side of the operand as bits exit from the right side. See Figure 3-7.
SAR (Shift Arithmetic Right) shifts the destination byte, word, or doubleword operand to the right by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL). The processor preserves the sign of the operand by shifting in zeros on the left (high-order) side if the value is positive or by shifting by ones if the value is negative. See Figure 3-8.
Even though this instruction can be used to divide integers by a power of two, the type of division is not the same as that produced by the IDIV instruction. The quotient of IDIV is rounded toward zero, whereas the "quotient" of SAR is rounded toward negative infinity. This difference is apparent only for negative numbers. For example, when IDIV is used to divide -9 by 4, the result is -2 with a remainder of -1. If SAR is used to shift -9 right by two bits, the result is -3. The "remainder" of this kind of division is +3; however, the SAR instruction stores only the high-order bit of the remainder (in CF).
The code sequence in Figure 3-9 produces the same result as IDIV for any M = 2^(N), where 0 < N < 32. This sequence takes about 12 to 18 clocks, depending on whether the jump is taken; if ECX contains M, the corresponding IDIV ECX instruction will take about 43 clocks.
OF CF OPERAND BEFORE SHL X X 10001000100010001000100010001111 OR SAL AFTER SHL 1 1 <-- 00010001000100010001000100011110 <-- 0 OR SAL BY 1 AFTER SHL X 0 <-- 00100010001000100011110000000000 <-- 0 OR SAL BY 10SHL (WHICH HAS THE SYNONYM SAL) SHIFTS THE BITS IN THE REGISTER OR MEMORY OPERAND TO THE LEFT BY THE SPECIFIED NUMBER OF BIT POSITIONS. CF RECEIVES THE LAST BIT SHIFTED OUT OF THE LEFT OF THE OPERAND. SHL SHIFTS IN ZEROS TO FILL THE VACATED BIT LOCATIONS. THESE INSTRUCTIONS OPERATE ON BYTE, WORD, AND DOUBLEWORD OPERANDS.
OPERAND CF BEFORE SHR 10001000100010001000100010001111 X AFTER SHR 0---->01000100010001000100010001000111---->1 BY 1 AFTER SHR 0---->00000000001000100010001000100010---->O BY 10SHR SHIFTS THE BITS OF THE REGISTER OR MEMORY OPERAND TO THE RIGHT BY THE SPECIFIED NUMBER OF BIT POSITIONS. CF RECEIVES THE LAST BIT SHIFTED OUT OF THE RIGHT OF THE OPERAND. SHR SHIFTS IN ZEROS TO FILL THE VACATED BIT LOCATIONS.
POSITIVE OPERAND CF BEFORE SAR 01000100010001000100010001000111 X AFTER SAR 0---->00100010001000100010001000100011---->1 BY 1 NEGATIVE OPERAND CF BEFORE SAR 11000100010001000100010001000111 X AFTER SAR 0---->11100010001000100010001000100011---->1 BY 1SAR PRESERVES THE SIGN OF THE REGISTER OR MEMORY OPERAND AS IT SHIFTS THE OPERAND TO THE RIGHT BY THE SPECIFIED NUMBER OF BIT POSITIONS. CF RECIEVES THE LAST BIT SHIFTED OUT OF THE RIGHT OF THE OPERAND.
; assuming N is in ECX, and the dividend is in EAX ; CLOCKS CMP EAX, 0 ; to set sign flag 2 JGE NoAdjust ; jump if sign is zero 3 or 9 ADD EAX, ECX ; 2 DEC EAX ; EAX := EAX + (N-1) 2 NoAdjust: SAR EAX, CL ; 3 ; TOTAL CLOCKS 12 or 18]
These instructions provide the basic operations needed to implement operations on long unaligned bit strings. The double shifts operate either on word or doubleword operands, as follows:
1. Taking two word operands as input and producing a one-word output. 2. Taking two doubleword operands as input and producing a doubleword output.Of the two input operands, one may either be in a general register or in memory, while the other may only be in a general register. The results replace the memory or register operand. The number of bits to be shifted is specified either in the CL register or in an immediate byte of the instruction.
Bits are shifted from the register operand into the memory or register operand. CF is set to the value of the last bit shifted out of the destination operand. SF, ZF, and PF are set according to the value of the result. OF and AF are left undefined.
SHLD (Shift Left Double) shifts bits of the R/M field to the left, while shifting high-order bits from the Reg field into the R/M field on the right (see Figure 3-10). The result is stored back into the R/M operand. The Reg field is not modified.
SHRD (Shift Right Double) shifts bits of the R/M field to the right, while shifting low-order bits from the Reg field into the R/M field on the left (see Figure 3-11). The result is stored back into the R/M operand. The Reg field is not modified.
Rotate instructions allow bits in bytes, words, and doublewords to be rotated. Bits rotated out of an operand are not lost as in a shift, but are "circled" back into the other "end" of the operand.
Rotates affect only the carry and overflow flags. CF may act as an extension of the operand in two of the rotate instructions, allowing a bit to be isolated and then tested by a conditional jump instruction (JC or JNC). CF always contains the value of the last bit rotated out, even if the instruction does not use this bit as an extension of the rotated operand.
In single-bit rotates, OF is set if the operation changes the high-order (sign) bit of the destination operand. If the sign bit retains its original value, OF is cleared. On multibit rotates, the value of OF is always undefined.
ROL (Rotate Left) rotates the byte, word, or doubleword destination operand left by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL). For each rotation specified, the high-order bit that exits from the left of the operand returns at the right to become the new low-order bit of the operand. See Figure 3-12.
ROR (Rotate Right) rotates the byte, word, or doubleword destination operand right by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL). For each rotation specified, the low-order bit that exits from the right of the operand returns at the left to become the new high-order bit of the operand. See Figure 3-13.
RCL (Rotate Through Carry Left) rotates bits in the byte, word, or doubleword destination operand left by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL).
This instruction differs from ROL in that it treats CF as a high-order one-bit extension of the destination operand. Each high-order bit that exits from the left side of the operand moves to CF before it returns to the operand as the low-order bit on the next rotation cycle. See Figure 3-14.
RCR (Rotate Through Carry Right) rotates bits in the byte, word, or doubleword destination operand right by one or by the number of bits specified in the count operand (an immediate value or the value contained in CL).
This instruction differs from ROR in that it treats CF as a low-order one-bit extension of the destination operand. Each low-order bit that exits from the right side of the operand moves to CF before it returns to the operand as the high-order bit on the next rotation cycle. See Figure 3-15.
31 DESTINATION 0 +----+ +--------------------------------------------------+ | CF |<------| MEMORY OF REGISTER |<---+ +----+ +--------------------------------------------------+ | +-----------------------------------------------------------+ | 31 SOURCE 0 | +--------------------------------------------------+ +---| REGISTER | +--------------------------------------------------+
31 SOURCE 0 +--------------------------------------------------+ | REGISTER |---+ +--------------------------------------------------+ | +----------------------------------------------------------+ | 31 DESTINATION 0 | +--------------------------------------------------+ +----+ +-->| MEMORY OF REGISTER |------->| CF | +--------------------------------------------------+ +----+
31 DESTINATION 0 +----+ +--------------------------------------------------+ | CF |<---+--| MEMORY OF REGISTER |<--+ +----+ | +--------------------------------------------------+ | +---------------------------------------------------------+
+----------------------------------------------------------+ | 31 DESTINATION 0 | | +--------------------------------------------------+ | +----+ +-->| MEMORY OF REGISTER |---+--->| CF | +--------------------------------------------------+ +----+
31 DESTINATION 0 +----+ +--------------------------------------------------+ +-| CF |<------| MEMORY OF REGISTER |<--+ | +----+ +--------------------------------------------------+ | +---------------------------------------------------------------------+
+----------------------------------------------------------------------+ | 31 DESTINATION 0 | | +--------------------------------------------------+ +----+ | +-->| MEMORY OF REGISTER |------->| CF |-+ +--------------------------------------------------+ +----+
One purpose of the double shifts is to implement a bit string move, with arbitrary misalignment of the bit strings. This is called a "bit blt" (BIT BLock Transfer.) A simple example is to move a bit string from an arbitrary offset into a doubleword-aligned byte string. A left-to-right string is moved 32 bits at a time if a double shift is used inside the move loop.
MOV ESI,ScrAddr MOV EDI,DestAddr MOV EBX,WordCnt MOV CL,RelOffset ; relative offset Dest-Src MOV EDX,[ESI] ; load first word of source ADD ESI,4 ; bump source address BltLoop: LODS ; new low order part SHLD EDX,EAX,CL ; EDX overwritten with aligned stuff XCHG EDX,EAS ; Swap high/low order parts STOS ; Write out next aligned chunk DEC EBX JA BltLoopThis loop is simple yet allows the data to be moved in 32-bit pieces for the highest possible performance. Without a double shift, the best that can be achieved is 16 bits per loop iteration by using a 32-bit shift and replacing the XCHG with a ROR by 16 to swap high and low order parts of registers. A more general loop than shown above would require some extra masking on the first doubleword moved (before the main loop), and on the last doubleword moved (after the main loop), but would have the same basic 32-bits per loop iteration as the code above.
The double shift instructions also enable:
- Fast insertion of a bit string from a register into an arbitrary bit location in a larger bit string in memory without disturbing the bits on either side of the inserted bits. - Fast extraction of a bits string into a register from an arbitrary bit location in a larger bit string in memory without disturbing the bits on either side of the extracted bits.The following coded examples illustrate bit insertion and extraction under variousconditions:
1. Bit String Insert into Memory (when bit string is 1-25 bits long, i.e., spans four bytes or less): ; Insert a right-justified bit string from register into ; memory bit string. ; ; Assumptions: ; 1) The base of the string array is dword aligned, and ; 2) the length of the bit string is an immediate value ; but the bit offset is held in a register. ; ; Register ESI holds the right-justified bit string ; to be inserted. ; Register EDI holds the bit offset of the start of the ; substring. ; Registers EAX and ECX are also used by this ; "insert" operation. ; MOV ECX,EDI ; preserve original offset for later use SHR EDI,3 ; signed divide offset by 8 (byte address) AND CL,7H ; isolate low three bits of offset in CL MOV EAX,[EDI]strg_base ; move string dword into EAX ROR EAX,CL ; right justify old bit field SHRD EAX,ESI,length ; bring in new bits ROL EAX,length ; right justify new bit field ROL EAX,CL ; bring to final position MOV [EDI]strg_base,EAX ; replace dword in memory 2. Bit String Insert into Memory (when bit string is 1-31 bits long, i.e. spans five bytes or less): ; Insert a right-justified bit string from register into ; memory bit string. ; ; Assumptions: ; 1) The base of the string array is dword aligned, and ; 2) the length of the bit string is an immediate value ; but the bit offset is held in a register. ; ; Register ESI holds the right-justified bit string ; to be inserted. ; Register EDI holds the bit offset of the start of the ; substring. ; Registers EAX, EBX, ECX, and EDI are also used by ; this "insert" operation. ; MOV ECX,EDI ; temp storage for offset SHR EDI,5 ; signed divide offset by 32 (dword address) SHL EDI,2 ; multiply by 4 (in byte address format) AND CL,1FH ; isolate low five bits of offset in CL MOV EAX,[EDI]strg_base ; move low string dword into EAX MOV EDX,[EDI]strg_base+4 ; other string dword into EDX MOV EBX,EAX ; temp storage for part of string + rotate SHRD EAX,EDX,CL ; double shift by offset within dword | EDX:EAX SHRD EAX,EBX,CL ; double shift by offset within dword + right SHRD EAX,ESI,length ; bring in new bits ROL EAX,length ; right justify new bit field MOV EBX,EAX ; temp storage for part of string + rotate SHLD EAX,EDX,CL ; double shift back by offset within word | EDX:EAX SHLD EDX,EBX,CL ; double shift back by offset within word + left MOV [EDI]strg_base,EAX ; replace dword in memory MOV [EDI]strg_base+4,EDX ; replace dword in memory 3. Bit String Insert into Memory (when bit string is exactly 32 bits long, i.e., spans five or four types of memory): ; Insert right-justified bit string from register into ; memory bit string. ; ; Assumptions: ; 1) The base of the string array is dword aligned, and ; 2) the length of the bit string is 32 ; but the bit offset is held in a register. ; ; Register ESI holds the 32-bit string to be inserted. ; Register EDI holds the bit offset of the start of the ; substring. ; Registers EAX, EBX, ECX, and EDI are also used by ; this "insert" operation. ; MOV EDX,EDI ; preserve original offset for later use SHR EDI,5 ; signed divide offset by 32 (dword address) SHL EDI,2 ; multiply by 4 (in byte address format) AND CL,1FH ; isolate low five bits of offset in CL MOV EAX,[EDI]strg_base ; move low string dword into EAX MOV EDX,[EDI]strg_base+4 ; other string dword into EDX MOV EBX,EAX ; temp storage for part of string + rotate SHRD EAX,EDX ; double shift by offset within dword | EDX:EAX SHRD EDX,EBX ; double shift by offset within dword + right MOV EAX,ESI ; move 32-bit bit field into position MOV EBX,EAX ; temp storage for part of string + rotate SHLD EAX,EDX ; double shift back by offset within word | EDX:EAX SHLD EDX,EBX ; double shift back by offset within word + left MOV [EDI]strg_base,EAX ; replace dword in memory MOV [EDI]strg_base,+4,EDX ; replace dword in memory 4. Bit String Extract from Memory (when bit string is 1-25 bits long, i.e., spans four bytes or less): ; Extract a right-justified bit string from memory bit ; string into register ; ; Assumptions: ; 1) The base of the string array is dword aligned, and ; 2) the length of the bit string is an immediate value ; but the bit offset is held in a register. ; ; Register EAX holds the right-justified, zero-padded ; bit string that was extracted. ; Register EDI holds the bit offset of the start of the ; substring. ; Registers EDI, and ECX are also used by this "extract." ; MOV ECX,EDI ; temp storage for offset SHR EDI,3 ; signed divide offset by 8 (byte address) AND CL,7H ; isolate low three bits of offset MOV EAX,[EDI]strg_base ; move string dword into EAX SHR EAX,CL ; shift by offset within dword AND EAX,mask ; extracted bit field in EAX 5. Bit String Extract from Memory (when bit string is 1-32 bits long, i.e., spans five bytes or less): ; Extract a right-justified bit string from memory bit ; string into register. ; ; Assumptions: ; 1) The base of the string array is dword aligned, and ; 2) the length of the bit string is an immediate ; value but the bit offset is held in a register. ; ; Register EAX holds the right-justified, zero-padded ; bit string that was extracted. ; Register EDI holds the bit offset of the start of the ; substring. ; Registers EAX, EBX, and ECX are also used by this "extract." MOV ECX,EDI ; temp storage for offset SHR EDI,5 ; signed divide offset by 32 (dword address) SHL EDI,2 ; multiply by 4 (in byte address format) AND CL,1FH ; isolate low five bits of offset in CL MOV EAX,[EDI]strg_base ; move low string dword into EAX MOV EDX,[EDI]strg_base+4 ; other string dword into EDX SHRD EAX,EDX,CL ; double shift right by offset within dword AND EAX,mask ; extracted bit field in EAX
This group of instructions sets a byte to zero or one depending on any of the 16 conditions defined by the status flags. The byte may be in memory or may be a one-byte general register. These instructions are especially useful for implementing Boolean expressions in high-level languages such as Pascal.
SETcc (Set Byte on Condition cc) set a byte to one if condition cc is true; sets the byte to zero otherwise. Refer to Appendix D for a definition of the possible conditions.
TEST (Test) performs the logical "and" of the two operands, clears OF and CF, leaves AF undefined, and updates SF, ZF, and PF. The flags can be tested by conditional control transfer instructions or by the byte-set-on-condition instructions. The operands may be doublewords, words, or bytes.
The difference between TEST and AND is that TEST does not alter the destination operand. TEST differs from BT in that TEST is useful for testing the value of multiple bits in one operations, whereas BT tests a single bit.