flat assembler
Message board for the users of flat assembler.

Index > Compiler Internals > "short" TEST instruction

Goto page 1, 2, 3, 4, 5  Next
Author
Thread Post new topic Reply to topic
S.T.A.S.



Joined: 09 Jan 2004
Posts: 173
Location: Ru#27
S.T.A.S. 14 Mar 2004, 05:51
Hi!

FASM is well known as size optimizing Assembler.
I.e. it generates short variants of jmp/push & sign extended and/add/or/xor/etc.. when it is possible (by default).

Wouldn't it be also logical to generate "short" variant of TEST CPU comand?
I mean, when 2nd operand is below 100h, use opcode F6h instead of F7h.

These instruction are equivalent in result (because they only affects on flags, but not on memory operand) & execution latency (AFAIK), but are different in size.

Of cource, it could be done with macro (not always I think)
But in this concrete case the same arguments could be used, as with other short instruction.

What do you think about this....? (May be I'm wrong somewhere)
Thanks.
Post 14 Mar 2004, 05:51
View user's profile Send private message Reply with quote
aaro



Joined: 21 Jun 2003
Posts: 107
Location: hel.fi
aaro 14 Mar 2004, 11:50
Code:
F6 /0 ib    TEST r/m8,imm8  AND imm8 with r/m8; set SF, ZF, PF according to result
    

F6 works only for 8 bit registers and memory
Post 14 Mar 2004, 11:50
View user's profile Send private message Reply with quote
S.T.A.S.



Joined: 09 Jan 2004
Posts: 173
Location: Ru#27
S.T.A.S. 14 Mar 2004, 15:34
aaro wrote:
Code:
F6 /0 ib TEST r/m8,imm8  AND imm8 with r/m8; set SF, ZF, PF according to result
    

F6 works only for 8 bit registers and memory

What is the difference between 8 bit operand and 32 bit one, where most significant 24 bits are zeros?
With TEST result is not saved back to memory, just flags are actual:
Code:
 byte 0    byte 1   byte 2   byte 3  
01234567 01234567 01234567 01234567 

XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX  --  memory operand (1st)

01100000 00000000 00000000 00000000  --  32 bit mask (2nd - immediate operand)

0XX00000 00000000 00000000 00000000  --  temporary result



XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX  --  memory operand (1st)

01100000        "virtual zeros"          --  8 bit mask (2nd - immediate operand)

0XX00000                                         --  temporary result
    

Z flag depends on bits marked X in result - so it's equal in both cases
P flag depends on the least significant byte - bits 0..7 are equal in both cases

S flag is ALWAYS clear when we use 2nd operand < 80000000h with 32 bit operands, so it would be clear if..
The ONLY incompatibility I see - when 7th bits of 1st & 2nd opersnds are set. In this case, with 8 bit operangs we'll get SF=1, but with 32 bit operand SF=0.

So the question is: who would do such thing:
Code:
test dword [foo], 80h
js foo_proc    

This code seems rather strange to me.
If my logic is right, no one will write such incompatible stuff..
Post 14 Mar 2004, 15:34
View user's profile Send private message Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3499
Location: Bulgaria
JohnFound 14 Mar 2004, 16:31
In other words, you want to force the programmer that write:
"test eax, imm8" to actually write "test al, imm8".
Why not in this case to substitute "add eax, 1" with "inc eax" and "mov eax, 0" with "xor eax, eax" -> they are smaller in size too.

IMHO, it is not very good.
At least you can get mentioned opcode, simply using 8bit register instead of 32bit register - it is programmer choice, not assembler choise.

Regards
Post 14 Mar 2004, 16:31
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
aaro



Joined: 21 Jun 2003
Posts: 107
Location: hel.fi
aaro 14 Mar 2004, 18:28
I agree with JohnFound here, but in case someone wants that kind of behavior here's macro for that:
Code:
macro test arg1, arg2 {
   if arg2 eqtype 1
            if arg2 < 80h
                            test byte arg1, arg2
                else
                        test arg1, arg2
             end if
      else
                test arg1, arg2
     end if
}
    

Works only with memory
Post 14 Mar 2004, 18:28
View user's profile Send private message Reply with quote
S.T.A.S.



Joined: 09 Jan 2004
Posts: 173
Location: Ru#27
S.T.A.S. 15 Mar 2004, 01:36
JohnFound wrote:
In other words, you want to force the programmer that write:
"test eax, imm8" to actually write "test al, imm8".

Hm.. I don't see test eax, imm8 inctruction in my reference.
Though and mreg16/32, imm8 (sign extended) is available, of cource.

Quote:
Why not in this case to substitute "add eax, 1" with "inc eax" and "mov eax, 0" with "xor eax, eax" -> they are smaller in size too.

Yes, I see your point and fully agree here.
These instruction are NOT equivalent - they affects flags by different ways.

aaro wrote:
here's macro for that ..
Works only with memory
That's the matter. At the moment I can't see any elegant way to work arround this and forse register ussage (may be future directive "store" will help). BTW, why 80h? Wouldn't 100h be better?


Also, I'd like to give you the real example from Fresh project (just a result of quick searh)
file Controls.asm -> ;-- WM_WINDOWPOSCHANGED
Code:
        test    eax, SWP_NOSIZE
;;  SWP_NOSIZE         = 0001h
    
Of cource, it's choice of programmer which register to use (8bit or 32bit). But when we use some *huge* .inc file do we often look inside of it? I think purpose of compiler - is to help programmer when it's possible.. not changing RESULT of operation


My point is: with TEST instruction, there's NO matter what is actual size of operang. Since there NO 8 or 32 bit result at all. Only some FLAGS, and how many of these flags are actually used?

We can calculate the results for affected flags in both variants of TEST instruction using bitwise logic. And see when they are equal or not. Some cases with SF are the weak side of my theory, but restricting size of 2nd operand to 7bit could be workaround to FULL compatibility.


PS
Sorry, my English isn't good, may be I just can't give good explanation of my idea?
Post 15 Mar 2004, 01:36
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 15 Mar 2004, 05:46
I agree with S.T.A.S.

by the way, same optimization is done with cmp instruction (cmp rm32,imm8) and nobody had problems with it, as it is functionally equivalent. If you need to rely on size of instruction, you can force operand size with size operator.
Post 15 Mar 2004, 05:46
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
comrade



Joined: 16 Jun 2003
Posts: 1150
Location: Russian Federation
comrade 15 Mar 2004, 07:57
I agree with JohnFound rather. Programmer would know that "xor eax,eax" is shorter than "mov eax,0", and that is something he/she learns. Similarly he/she would learn to use "test al, mask" as opposed to "test eax, mask".

The assembler should do what the programmer asks from it, and if programmer asks for "test eax,mask", so be it with the longer opcode.

_________________
comrade (comrade64@live.com; http://comrade.ownz.com/)
Post 15 Mar 2004, 07:57
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3499
Location: Bulgaria
JohnFound 15 Mar 2004, 08:23
Well, that example from Fresh, almost convinced me. Wink
Maybe such optimization will be appropriate for imm8 below $80 to avoid problems with Sign flag.
Actually I whould like to read Privalov's opinion on this subject too. You may be sure that I am fully agree with him on such subjects. Very Happy

Regards.
Post 15 Mar 2004, 08:23
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
S.T.A.S.



Joined: 09 Jan 2004
Posts: 173
Location: Ru#27
S.T.A.S. 15 Mar 2004, 08:33
vid wrote:
same optimization is done with cmp instruction (cmp rm32,imm8)

To be absolutely correct there is the difference - cmp & other sign extended instructions are documented ones.
But this case with test is NOT. Intels docs tell us, that there is difference between 8bit & 32bit variants..
Of cource, this is right, if we need to STORE the result of operation..
This is like some kind of trick - based on bitwise logic. It works, but it isn't officially recommended for use..

At the other side there's another example of other 2 "different" instructions
Code:
83E0 08       and     eax, 8
25 08000000   and     eax, 8    
They heve absolutely different opcodes, but result is the same.. And FASM gives us the best possible of them
Though it's well docummented in manuals
Post 15 Mar 2004, 08:33
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8363
Location: Kraków, Poland
Tomasz Grysztar 15 Mar 2004, 08:55
I agree that in case of immediate values in range 0-7Fh these two TEST instructions are exactly equivalent, so I could make such optimization - however it would confuse some people when they get disassembly a bit different from the source... In the case of immediate values in range 80h-0FFh I cannot agree at all.
Post 15 Mar 2004, 08:55
View user's profile Send private message Visit poster's website Reply with quote
aaro



Joined: 21 Jun 2003
Posts: 107
Location: hel.fi
aaro 15 Mar 2004, 09:31
Quote:

BTW, why 80h? Wouldn't 100h be better?

Because of the sign flag.
Here's new version that works with registers too:
Code:
macro test arg1, arg2 {
    if arg2 eqtype 1
            if arg2 < 80h
                    if arg1 eq eax
                              test al, arg2
                       else if arg1 eq ebx
                         test bl, arg2
                       else if arg1 eq ecx
                         test cl, arg2
                       else if arg1 eq edx
                         test dl, arg2
                       else
                                test byte arg1, arg2
                        end if
              else
                        test arg1, arg2
             end if
      else
                test arg1, arg2
     end if
}
    
Post 15 Mar 2004, 09:31
View user's profile Send private message Reply with quote
S.T.A.S.



Joined: 09 Jan 2004
Posts: 173
Location: Ru#27
S.T.A.S. 15 Mar 2004, 10:40
aaro wrote:
new version that works with registers
Hmm.. It should be modifyed a bit.
Otherwise "test EPB, 70h" will fail.. Anyway it would be a solution

Privalov wrote:
it would confuse some people when they get disassembly a bit different from the source..
Woudn't it enforce them to study some more things about math and boolean algebra?
I suppose it is always a good idea Smile

Of cource, S flag is restricting to 7bit operands, if it will be done at compiler level.
It is also logical, bacouse other short instruction do use 00..7Fh positive numbers, other are interpreted as negative.
Post 15 Mar 2004, 10:40
View user's profile Send private message Reply with quote
aaro



Joined: 21 Jun 2003
Posts: 107
Location: hel.fi
aaro 15 Mar 2004, 10:50
Code:
macro test arg1, arg2 {
     if arg2 eqtype 1
            if arg2 < 80h
                    if arg1 eq eax
                              test al, arg2
                       else if arg1 eq ebx
                         test bl, arg2
                       else if arg1 eq ecx
                         test cl, arg2
                       else if arg1 eq edx
                         test dl, arg2
                       else if arg1 eqtype eax
                             test arg1, arg2
                     else
                                test byte arg1, arg2
                        end if
              else
                        test arg1, arg2
             end if
      else
                test arg1, arg2
     end if
}
    
Post 15 Mar 2004, 10:50
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8363
Location: Kraków, Poland
Tomasz Grysztar 15 Mar 2004, 13:26
S.T.A.S. wrote:
Woudn't it enforce them to study some more things about math and boolean algebra?
I suppose it is always a good idea Smile

It's not always so good when you're receiving tons of "bug reports" from people that haven't yet studied it enough. Wink

Anyway I am convinced - this is a good feature.
Post 15 Mar 2004, 13:26
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8363
Location: Kraków, Poland
Tomasz Grysztar 20 Mar 2004, 13:22
Hmm, and what about LEA->MOV substitution? Both don't affect any flags, so the same reasoning could be applied to this case. Only it would be harder to allow programmer to force the LEA instruction when he really wants it (with optimized TEST I have made for fasm 1.52 you can always write TEST EAX,DWORD 1 to avoid optimization).
Post 20 Mar 2004, 13:22
View user's profile Send private message Visit poster's website Reply with quote
Dryobates



Joined: 13 Jul 2003
Posts: 46
Location: Poland
Dryobates 20 Mar 2004, 19:36
I think that you should only inform programmer that something could be change in order to make better code. Just write the line where it is and how it can be changed. It would be nice to still leave decision for programmer. You don't want make macro assembler (TASM, MASM, HLA etc.), do you?
Post 20 Mar 2004, 19:36
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger ICQ Number Reply with quote
S.T.A.S.



Joined: 09 Jan 2004
Posts: 173
Location: Ru#27
S.T.A.S. 23 Mar 2004, 11:02
Privalov wrote:
what about LEA->MOV substitution?

Do you mean this case?
(as to me, I simply do not know where LEA can be used in such context)
Code:
8D05 21436587 lea     eax, dword [ds:87654321]
B8 21436587   mov     eax, 87654321    
Post 23 Mar 2004, 11:02
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8363
Location: Kraków, Poland
Tomasz Grysztar 23 Mar 2004, 11:34
And what about converting "test eax,100h" to "test ah,1"?
And if we decide to do it, what about "test dword [0],100h" to "test byte [1],1"?
Post 23 Mar 2004, 11:34
View user's profile Send private message Visit poster's website Reply with quote
Frank



Joined: 17 Jun 2003
Posts: 100
Frank 23 Mar 2004, 12:45
Why not "pushf / xor eax,eax / popf" as an automatic replacement for "mov eax, 0"? Plus more special-case syntax for those who don't want the feature?

It is such a pity -- FASM used to be a logical, straightforward, consistent, predictable, easy-to-use assembler, and now everyone wants to turn it into a compiler.
Post 23 Mar 2004, 12:45
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2, 3, 4, 5  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.