TEST performs the same bit-by-bit AND as the AND instruction, but throws the result away. Neither operand changes; only the flags are set from what the result would have been. It is the instruction for asking "is this bit on?" before a conditional jump.
Reading the flags
| After | Means | Jump |
|---|---|---|
| ZF = 1 | none of the tested bits is set | JZ / JE |
| ZF = 0 | at least one tested bit is set | JNZ / JNE |
| SF = 1 | the top bit of the result is set | JS |
| CF = OF = 0 | always |
AF is undefined. PF reflects only the low 8 bits of the result, as with every instruction that sets it.
Idioms
TEST AL, 1 then JNZ branches when AL is odd. TEST AL, 80h (or TEST AX, 8000h) looks at the sign bit. TEST AX, AX sets ZF if AX is zero and SF if it is negative, without changing AX; it is the usual way to check a register that was just loaded with MOV, since MOV does not set flags.
Pitfall: several bits
With a mask of more than one bit, ZF=0 means "any of them", not "all of them". TEST AL, 0Ch is non-zero when bit 2 or bit 3 is set. To require both, copy the value, AND it with the mask and compare with the mask:
MOV AH, ALAND AH, 0ChCMP AH, 0Ch ; ZF = 1 only if bits 2 and 3 are both set
A memory operand with an immediate needs a size: TEST BYTE PTR [BX], 1. The example below counts the 1 bits of a byte by testing each bit with a mask that moves left.
MOV AL, 0B5h ; 1011 0101: five 1 bitsMOV BL, 1 ; mask, bit 0 firstXOR BH, BH ; the countMOV CX, 8COUNT1:TEST AL, BL ; AL itself does not changeJZ ZERO1INC BHZERO1:SHL BL, 1 ; next bitLOOP COUNT1MOV AL, BHADD AL, "0"MOV DL, ALMOV AH, 02hINT 21h