Hey Gang
I was going through the Intel opcode reference when I came across the BT/BTS/BTC/BTR opcodes. I never was aware of these opcodes and I reading the reference just made me more confused !!
If TEST also perform test on the bits, what do we need BT for ? Could some one please explain the difference ?
Thanks in advance
TEST is more powerful because you can test for a bit pattern. On the other hand, btc can come in handy: I have a key that toggles the state of a variable that defines a toolbar zone width. It can vary between 0 and 127 bytes. However, the user can temporarily expand by 128:
btc tbw, 7 ; toggle Alt WideToolbar
If the toolbar is narrow, 128 are added. If it is wide, 128 are subtracted.
You can code the same with jumps or test but it looks less elegant ;-)
Later: Since btc tbw, 7 costs a staggering 8 bytes, I decided to have a closer look at the alternative:
.if tbw>127
sub tbw, 128
.else
add tbw, 128
.endif
Hmmmm... 31 bytes. Maybe it's faster, but I am handling a keystroke here, hardly a speed critical task, right?
Address Hex dump Command Comments
0040196C ³. 833D 60C64000 7F cmp dword ptr [ReTest.40C660], 7F
00401973 ³? 76 0C jbe short ReTest.00401981
00401975 ³? 812D 60C64000 80000000 sub dword ptr [ReTest.40C660], 80 ; ³
0040197F ³? EB 0A jmp short ReTest.0040198B
00401981 ³? 8105 60C64000 80000000 add dword ptr [ReTest.40C660], 80
terb, you're quite right - BT is pretty redundant, since you can do the same with TEST.
Although, BT alters the carry flag, whereas TEST alters the zero/equal flag - there are a few tricks you can do with adc and sbb.
And BT is a slightly shorter encoding.
The other three are useful as atomic operations.
But yes, there are quite a few instructions that could be cut without much trouble, but they're kept for compatibility.
BTx is not restricted to 32 bits as it is the case with TEST - you can easily access memory bit-fields of any size with one instruction. So IMO one cannot say that BTx is redundant.
tedd wrote. . .Quotethere are a few tricks you can do with adc and sbb.
What are some of the ways adc & sbb can be used .
Thanks
Quote from: japheth on July 17, 2008, 12:01:56 PM
BTx is not restricted to 32 bits as it is the case with TEST - you can easily access memory bit-fields of any size with one instruction.
Yes, but only for a maximum of 256 bits AFAIK
Quote
So IMO one cannot say that BTx is redundant.
They belong to a kind of instruction sets that apparently did try to make the life of ASM programmer more easy. At a certain time Intel did choose this kind of actions. Today this path is not taken anymore. The only thing that is considered are compilers.
Unfortunately from Intel's late point of view programmers should NOT use ASM for big programs.
Of course I disagree but who am I ?
On redundant instructions:
From the electronics point of view they do not matter much. It does matter for the compilers and humans's understanding and it does attack the "sense of abstract perfection" of some people (not myself) but the hardware does not care much. They could be just some left un-decoded wires that got promoted as a feature.
Also to so much claimed "simplification of instruction set" is also kind of irrelevant at silicon level. Some apparent complications for the human eye are in fact much more easy to decode at hardware level and are much better as they are than what people do suggest.
The CPU it is what it is... learn it and live with it until you are able to understand it's inner workings to such an depth that you become capable to make your own ;) (at that point you will see things differently than common sense)
I would choose TEST any time but sometimes BT/BTC/BTR/BTS can be kind of useful.
QuoteWhat are some of the ways adc & sbb can be used .
well, i'm sure you could probably write some complex logical conditional tests using these instructions..for example in C
if (a != 0)
a = b;
else
a = c;
in assembly code, you could use:
a = eax, b = ebx, c = ecx
cmp eax, 1
sbb eax, eax
and ecx, eax
xor eax, -1
and eax, ebx
or eax, ecx
another example:
a = a > b ? b : a;
sub ebx, eax
sbb ecx, ecx
and ecx, ebx
add eax, ecx
not sure if that answers your question..
Quote from: BogdanOntanu on July 17, 2008, 05:32:09 PM
Quote from: japheth on July 17, 2008, 12:01:56 PM
BTx is not restricted to 32 bits as it is the case with TEST - you can easily access memory bit-fields of any size with one instruction.
Yes, but only for a maximum of 256 bits AFAIK
I wouldn't call 256 "any size". IIRC I once successfully tested it up to 65536 bits - of course this is still not "any size", but it's "more any" :toothy. The docs are telling up to 2^32 bits can be accessed, however, the second operand is interpreted as a signed value!
Japeth,
Yes you are right, "mea culpa".
With a register operand like in:
BT [esi],ecx
You could indeed test a bit range of -2^31 upto +2^31 - 1 if ECX is loaded with the correct bit offset value.
And this feature is a huge advantage when compared with a simple TEST.
However the user should be aware that with an immediate (number) operand you can only access 15/31/63 bit offsets even if the instruction encoding allows for a 256 bit offset value.
kernel, thx for the examples
For inspiration.
AnyFlag equ 55 ; give a name to your flag variable
fset AnyFlag
.if fget(AnyFlag)
invoke MessageBox, NULL, chr$("AnyFlag is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("AnyFlag is NOT set"), addr AppName, MB_OK
.endif
fset and fget cost 7 bytes each.
EDIT: fclr, ftoggle, flgmov added.
include \masm32\include\masm32rt.inc
fset MACRO num:REQ
push num
call fsetP
ENDM
fclr MACRO num:REQ
push num
call fclrP
ENDM
flgmov MACRO num:REQ, src:REQ
.if src
fset num
.else
fclr num
.endif
ENDM
ftoggle MACRO num:REQ
push num
call ftoggleP
ENDM
fget MACRO num:REQ
push num
call fgetP
EXITM <eax>
ENDM
tmpflag equ 0
f1 equ 1
f2 equ 2
f3 equ 3
AnyFlag equ 55
f79 equ 79
.data?
MyFlags dt ?
.code
AppName db "Flags:", 0
fsetP proc
push edx
mov edx, offset MyFlags
mov eax, [esp+8]
bts [edx], eax
pop edx
ret 4
fsetP endp
fclrP proc
push edx
mov edx, offset MyFlags
mov eax, [esp+8]
btr [edx], eax
pop edx
ret 4
fclrP endp
ftoggleP proc
push edx
mov edx, offset MyFlags
mov eax, [esp+8]
btr [edx], eax
pop edx
ret 4
ftoggleP endp
fgetP proc
push edx
mov edx, offset MyFlags
mov eax, [esp+8]
bt [edx], eax
setc al
pop edx
ret 4
fgetP endp
start: fset f1 ; set flag
fset f3 ; set flag
fset f79 ; set flag
fclr f79 ; clear flag
fset AnyFlag ; set flag
ftoggle AnyFlag ; toggle flag
flgmov tmpflag, 123 ; set flag if src is non-zero
.if fget(f1)
invoke MessageBox, NULL, chr$("f1 is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("f1 is NOT set"), addr AppName, MB_OK
.endif
.if fget(f2)
invoke MessageBox, NULL, chr$("f2 is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("f2 is NOT set"), addr AppName, MB_OK
.endif
.if fget(f3)
invoke MessageBox, NULL, chr$("f3 is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("f3 is NOT set"), addr AppName, MB_OK
.endif
.if fget(AnyFlag)
invoke MessageBox, NULL, chr$("AnyFlag is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("AnyFlag is NOT set"), addr AppName, MB_OK
.endif
.if fget(f79)
invoke MessageBox, NULL, chr$("f79 is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("f79 is NOT set"), addr AppName, MB_OK
.endif
.if fget(tmpflag)
invoke MessageBox, NULL, chr$("tmpflag is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("tmpflag is NOT set"), addr AppName, MB_OK
.endif
mov eax, 123
flgmov tmpflag, eax ; set the flag if src is non-zero
.if fget(tmpflag)
invoke MessageBox, NULL, chr$("tmpflag is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("tmpflag is NOT set"), addr AppName, MB_OK
.endif
mov eax, 0
flgmov tmpflag, eax ; set the flag if src is non-zero
.if fget(tmpflag)
invoke MessageBox, NULL, chr$("tmpflag is set"), addr AppName, MB_OK
.else
invoke MessageBox, NULL, chr$("tmpflag is NOT set"), addr AppName, MB_OK
.endif
exit
end start