I need to EFFICIENTLY test if 4 bits are either set or cleared.

Ok, let's take an example.
Suppose I need to test bit 31, bit 2, bit 1 and bit 0.
For the moment, I do something like that:



mov eax, [memory]
and eax, 080000000h + 4 + 2 + 1
je ok
xor eax, 080000000h + 4 + 2 + 1
jne bad
ok:
; the 4 bits are either set or cleared
bad:



My question is: can this be done with only one branch ?
Can you extend your method to an array of dwords (not only EAX) ?
Posted on 2003-10-20 02:49:01 by MCoder
If I need to test several bits at a time I reset all the bits I'm not interested in and then do a compare:


mov esi,GDTbase
add edx,08h
mov eax,dword ptr ; EDX = Selector
mov Typefield,eax
and eax,00001F00h
cmp eax,00000B00h
loopnz $-016h
Posted on 2003-10-20 16:51:44 by mrgone
If you have another register available, maybe this would work (using edx just as example):



mov eax,[memory]
and eax,BITMASK
setz dl
xor eax,BITMASK
setz dh
and dh,dl
jnz bad
ok:
bad:


/Edit - I came up with a better idea (again assuming an extra register):



; BITMASK - DWORD with bits to test set to 1, others 0
; IBITMASK - Inversion of BITMASK: bits to test set to 0, others 1
mov eax,[memory]
mov edx,eax
or eax,BITMASK2
not eax
and edx,BITMASK
and eax,edx
jnz bad
ok:
bad:
Posted on 2003-10-20 18:51:22 by sirchess2
I'm afraid the last one won't work.
How about this?


mov eax,[memory]
and eax,BITMASK
cmp eax,1
sbb edx,edx
cmp eax,BITMASK
adc edx,0
jnz notright
Posted on 2003-10-21 12:37:05 by Sephiroth3


mov eax,[memory]
and eax,BITMASK
cmp eax,1
sbb edx,edx
cmp eax,BITMASK
adc edx,0
jnz notright


Nice, but can you do it only with or/xor/and (or MMX) ?
Posted on 2003-10-21 13:44:30 by MCoder
MCoder,

Did you want to determine if ALL the bits are set, or if ANY of the bits are set? It makes a difference. Ratch
Posted on 2003-10-21 15:54:05 by Ratch
Thanks for the correction, Sephiroth3. I should check my work more carefully before posting :o
Posted on 2003-10-21 17:08:33 by sirchess2
...and in the creative category we have...

bitRAKE with his piece of code entitled Don't Lahf (laugh) at My Pop Bit Test:
mov eax, [memory]

and eax, BITMASK
pushfd
cmp eax, BITMASK
lahf
popfd
bt eax, Z_FLAG
jna ok ; jump Z or C
:grin:
Posted on 2003-10-21 21:01:39 by bitRAKE
Hehe, nice, you beat me by 1 byte :P
Posted on 2003-10-22 15:11:49 by Sephiroth3
MMX code would be something like:
mov eax, BITMASK

pxor mm7, mm7
movd mm7, eax

; inside loop

movd mm0, [memory]
pand mm0, mm7 ; clear bits not tested
unpack mm0, mm0 ; duplicate dword top and bottom
pcmpeqd mm0, mm7 ; test for zero in the top dword and all set in the bottom dword
pack mm0, mm0 ; merge result into lower dword
movd eax, mm0
test eax, eax
jne ok
Also, might be the fastest? The same MMX register can be used for the compare and the mask due to unpacking after masking (ie top dword of constant MMX register is zero, and the bottom dword would be the BITMASK).
Posted on 2003-10-22 20:33:49 by bitRAKE
Nice implementation Bitrake !
I'll try to use this technique for my problem.

mov eax, BITMASK

pxor mm7, mm7
movd mm7, eax

; inside loop

movd mm0, [memory]
pand mm0, mm7 ; clear bits not tested
unpack mm0, mm0 ; duplicate dword top and bottom
pcmpeqd mm0, mm7 ; test for zero in the top dword and all set in the bottom dword
pack mm0, mm0 ; merge result into lower dword
movd eax, mm0
test eax, eax
jne ok
Posted on 2003-10-24 06:13:41 by MCoder