test
is like and
, except it only writes FLAGS, leaving both its inputs unmodified. With two different inputs, it's useful for testing if some bits are all zero, or if at least one is set. (e.g. test al, 3
sets ZF if EAX is a multiple of 4 (and thus has both of its low 2 bits zeroed).
test eax,eax
sets all flags exactly the same way that cmp eax, 0
would:
- CF and OF cleared (AND/TEST always does that; subtracting zero never produces a carry)
- ZF, SF and PF according to the value in EAX. (
a = a&a = a-0
).
(PF as usual is only set according to the low 8 bits)
Except for the obsolete AF (auxiliary-carry flag, used by ASCII/BCD instructions). TEST leaves it undefined, but CMP sets it "according to the result". Since subtracting zero can't produce a carry from the 4th to 5th bit, CMP should always clear AF.
TEST is smaller (no immediate) and sometimes faster (can macro-fuse into a compare-and-branch uop on more CPUs in more cases than CMP). That makes test
the preferred idiom for comparing a register against zero. It's a peephole optimization for cmp reg,0
that you can use regardless of the semantic meaning.
The only common reason for using CMP with an immediate 0 is when you want to compare against a memory operand. For example, cmpb $0, (%esi)
to check for a terminating zero byte at the end of an implicit-length C-style string.
AVX512F adds kortestw k1, k2
and AVX512DQ/BW (Skylake-X but not KNL) add ktestb/w/d/q k1, k2
, which operate on AVX512 mask registers (k0..k7) but still set regular FLAGS like test
does, the same way that integer OR
or AND
instructions do. (Sort of like SSE4 ptest
or SSE ucomiss
: inputs in the SIMD domain and result in integer FLAGS.)
kortestw k1,k1
is the idiomatic way to branch / cmovcc / setcc based on an AVX512 compare result, replacing SSE/AVX2 (v)pmovmskb/ps/pd
+ test
or cmp
.
Use of jz
vs. je
can be confusing.
jz
and je
are literally the same instruction, i.e. the same opcode in the machine code. They do the same thing, but have different semantic meaning for humans. Disassemblers (and typically asm output from compilers) will only ever use one, so the semantic distinction is lost.
cmp
and sub
set ZF when their two inputs are equal (i.e. the subtraction result is 0). je
(jump if equal) is the semantically relevant synonym.
test %eax,%eax
/ and %eax,%eax
again sets ZF when the result is zero, but there's no "equality" test. ZF after test doesn't tell you whether the two operands were equal. So jz
(jump if zero) is the semantically relevant synonym.