What is the easiest way to determine if a register value is zero or not?

I am using x86 build with Irvine library.

What is the easiest way to check if a register value is zero or not?

I used the cmp instruction, but I am looking for an alternative way. This is my code using cmp command and the register is ebx

cmp ebx,0 je equ1 mov ebx,0 jmp cont equ1: mov ebx,1 jmp cont cont: exit 

This "booleanizes" value creating 0 or 1, like int ebx = !!ebx , will be in C.

+5
source share
3 answers

Probably the "simplest" or simplest, "not caring for details" answer, how to determine:

  ; here ebx is some value, flags are set to anything test ebx,ebx ; CF=0, ZF=0/1 according to ebx jz whereToJumpWhenZero ; "non-zero ebx" will go here ; Or you can use the inverted "jnz" jump to take ; a branch when value was not zero instead of "jz". 

Here is a detailed answer from Peter Cordes to " testl eax vs eax?" question about flags set, etc. There is also a link to another similar answer, but a discussion about why this is the best way in terms of performance. :)

How to set another register (I will choose eax ) to 1 when ebx is zero, and to 0 when ebx not zero (non-destructive way for ebx itself):

  xor eax,eax ; eax = 0 (upper 24 bits needed to complete "al" later) test ebx,ebx ; test ebx, if it is zero (ZF=0/1) setz al ; al = 1/0 when ZF=1/0 (eax = 1/0 too) 

Or how to convert ebx itself to 1/0 when ebx is zero / non-zero:

  neg ebx ; ZF=1/0 for zero/non-zero, CF=not(ZF) sbb ebx,ebx ; ebx = 0/-1 for CF=0/1 inc ebx ; 1 when ebx was 0 at start, 0 otherwise 

Or how to convert ebx itself to 1/0 when ebx is zero / non-zero, another option (faster on "P6" kernels to "Haswell"):

  test ebx,ebx ; ZF=1/0 for zero/non-zero ebx setz bl ; bl = 1/0 by ZF (SETcc can target only 8b r/m) movzx ebx,bl ; ebx = bl extended to 32 bits by zeroes 

etc. etc. It depends on what happens before your testing, as well as what you really want as a test result, there are many possible ways (optimal for different situations and optimal for another target CPU).


I will add some more extremely common situations ... Intermediate counter counter from N to zero, per cycle N times:

  mov ebx,5 ; loop 5 times exampleLoop: ; ... doing something, preserving ebx dec ebx jnz exampleLoop ; loop 5 times till ebx is zero 

How to process 5 elements of word (16b) array (access to them in array [0], array [1], ... order):

  mov ebx,-5 lea esi,[array+5*2] exampleLoop: mov ax,[esi+ebx*2] ; load value from array[i] ; process it ... and preserve esi and ebx inc ebx jnz exampleLoop ; loop 5 times till ebx is zero 

Another example, I somehow have so many:

How to set the target register ( eax in the example) to ~ 0 (-1) / 0 when ebx is zero / non-zero, and you already have the value 1 in some register ( ecx in the example):

  ; ecx = 1, ebx = some value cmp ebx,ecx ; cmp ebx,1 => CF=1/0 for ebx zero/non-zero sbb eax,eax ; eax = -1 (~0) / 0 for CF=1/0 ; ebx/ecx intact 

-1 may look as practical as 1 (for indexing purposes, at least), but -1 works just like a full bitmask for further and/xor/or operations, so sometimes it's more convenient.

+11
source

Use the flags, Luke
You check if the register is zero by checking the zero flag.
If the register got its value with some operation that affected the flags (or rather, the zero flag), you do not need to do anything, because the zero flag already reflects the value stored in this register.

Check only if necessary
If you cannot guarantee that the flags are set, you will have to use a test operation.
These operations come in two versions: destructive and non-destructive.

You can see the list of instructions and flags that it changes: http://ref.x86asm.net - more specifically, at: http://ref.x86asm.net/coder32-abc.html

The mov and lea instructions do not change the flags and therefore need help. Most other instructions have at least one flag set.

Do not create false dependencies
If you need to check the case for zero, but do not want to change its value, you use the test statement.
You should not use the or or and statement to check the case, because the CPU may not know that or/and can be used non-destructively and may not use some optimizations. The technical term for this is "false addiction." The register needs ebx and β€œthinks” that it has been changed recently, so that it is waiting for the result to complete.

 test ebx, ebx ; <-- CPU knows ebx was not altered, no stalls on subsequent reads. or ebx, ebx ; <-- CPU 'thinks' ebx was changed, stall on subsequent read. 

If you want the null state to be reflected in another register, you can simply mov ebx in another register.

Decrease the value to logical
If you want to reduce the case to logical (True, if not zero, False otherwise), you use one of the following sequences:

 ; ebx holds the value to reduce to a boolean. ; eax is an unused register. 
 xor eax, eax ; eax = 0 sub eax, ebx ; eax = 0 - ebx; CF (carry flag) = 1 if ebx <> 0 sbb ebx, ebx ; ebx = ebx - ebx - CF ; <<-- ebx = -1 if non zero, 0 if zero 
 xor eax, eax ; eax = 0 sub eax, ebx ; eax = - ebx; CF = 1 if ebx <> 0 adc ebx, eax ; ebx = (ebx + -ebx) aka 0 + CF ; <<== ebx = 1 if non zero, 0 if zero 
 test ebx, ebx ; force ZF to be correct setnz al ; Store 1 if non-zero, 0 otherwise in byte register AL. 

Please note that using byte registers can be problematic due to the kiosks associated with the "partial register entry".

+2
source

You can use:

 or ebx, 0 ;This does nothing, just triggers the zero flag if ebx is zero jnz notZero or ebx, 1 ;ebx was zero, then ebx is 1 notZero: 
-3
source

Source: https://habr.com/ru/post/1261358/


All Articles