• Welcome to Jose's Read Only Forum 2023.
 

PB 9: Preference for LONG etc. same as with PB 8

Started by Theo Gottwald, August 16, 2008, 11:17:10 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Theo Gottwald

We'll just take a look on this Code under the "Microscope" (DisASM):

SUB TestfuncA()
REGISTER R01 AS DWORD,R02 AS DWORD
! NOP
'#ALIGN 32
FOR R01=0 TO 1000
   FOR R02=0 TO 1000
    GOSUB Laba
! NOP
! NOP
! NOP
! NOP
R02=ISFALSE R01
! NOP
! NOP
! NOP
   NEXT R02
NEXT R01
EXIT SUB
Laba:
GOSUB Labb
RETURN
Labb:
! NOP
! NOP
RETURN
END SUB


We're using #OPTIMIZE SIZE here for cosmetical reasons.
What we get under DisASM is this:


4024EF   NOP
4024F0   NOP
4024F1   NOP
4024F2   NOP ' From here starts the ISFALSE
4024F3   MOV DWORD PTR [EBP-6C], ESI
4024F6   MOV DWORD PTR [EBP-68], DWORD 00000000
4024FD   FILD QUAD PTR [EBP-6C]
402500   FTST
402502   FNSTSW AX
402504   SAHF
402505   FSTPST, ST(0)
402507   MOV EAX, DWORD FFFFFFFF
40250C   JZ  SHORT L40250F
40250E   INC  EAX
40250F   CALL L40499F
402514   FISTP QUAD PTR [EBP-6C]
402517   MOV EDI, DWORD PTR [EBP-6C]
40251A   NOP ' Until here
40251B   NOP
40251C   NOP
40251D   INC EDI
40251F   CMP EDI, DWORD 000003E8
402525   JBE SHORT L4024EA
402527   INC ESI
402529   CMP ESI, DWORD 000003E8
40252F   JBE SHORT L4024E4
402531   JMP L40253F
402536   CALL L40253C
40253B   RET NEAR
40253C   NOP
40253D   NOP
40253E   RET NEAR



This way, we see that the single Line:

R02=ISFALSE R01


was compiled to all the code between the two blocks of NOP's.
This is partly because we are using DWORDS here instead of LONG.

If we just change this line:

REGISTER R01 AS DWORD,R02 AS DWORD

to

REGISTER R01 AS LONG,R02 AS LONG

the result looks like this:

4024EF   NOP
4024F0   NOP
4024F1   NOP
4024F2   NOP ' From here starts the ISFALSE
4024F3   MOV EAX, ESI
4024F5   TEST EAX, EAX
4024F7   MOV EAX, DWORD FFFFFFFF
4024FC   JZ  SHORT L4024FF
4024FE   INC  EAX
4024FF   MOV EDI, EAX
402501   NOP ' Until here
402502   NOP
402503   NOP
402504   INC EDI
402506   CMP EDI, DWORD 000003E8
40250C   JLE SHORT L4024EA
40250E   INC ESI
402510   CMP ESI, DWORD 000003E8
402516   JLE SHORT L4024E4
402518   JMP L402526
40251D   CALL L402523
402522   RET NEAR



We see that now we get much more efficient code.

Just to show one of the reasons, we compile the same using QUADS.
What we do is:

LOCAL R01 AS QUAD,R02 AS QUAD



Leaving away the other part, just taking a look on the ISFALSE part:


402520   NOP
402521   NOP
402522   NOP
402523   NOP
402524   FILD QUAD PTR [EBP+FFFFFF64]
40252A   FTST
40252C   FNSTSW AX
40252E   SAHF
40252F   FSTPST, ST(0)
402531   MOV EAX, DWORD FFFFFFFF
402536   JZ  SHORT L402539
402538   INC  EAX
402539   CALL L4049FF
40253E   FISTP QUAD PTR [EBP+FFFFFF5C]
402544   NOP
402545   NOP
402546   NOP


We see, that the functional part is nearly identical to the part for DWORDS.
PowerBASIC seems to treat DWORDS like QUADS in some cases, rather then like LONGS as we might have expected.
We can assume there are good reasons for this, maybe because of Overflow-Handling.

Just to show, that we get the best code if we do not use ISFALSE where its not needed, we try a simple

R02=(R01=0)   

and we get this as expected, and as we knew it from PB 8.0x:


4024EF NOP
4024F0 NOP
4024F1 NOP
4024F2 NOP
4024F3 XOR EAX, EAX
4024F5 MOV ECX, ESI
4024F7 CMP ECX, EAX
4024F9 MOV EAX, DWORD FFFFFFFF ' The result would be -1
4024FE JZ  SHORT L402501
402500 INC  EAX ' -1 increased by 1 is zero - result would be zero.
402501 MOV EDI, EAX
402503 NOP
402504 NOP
402505 NOP



Conclusion:
Nothing unexpected at this place. The old suggestions for PB 8 stay:
For highly timecritical code

  • Avoid ISFALSE and ISTRUE when not needed and Use simple LONG-Comparison instead.
  • use LONG as Datatype whenever possible
  • and use the REGISTER Variables for Loops and where they fit

Patrice Terrier

QuoteISFALSE and ISTRUE

This one has been raised up already several times, but it looks like old practice are hard to get rid off ;)

LOCAL MyBoolean AS LONG

MyBoolean = -1

IF MyBoolean THEN '// IF ISTRUE(MyBoolean) THEN
    DoWhateverYouWant
ELSE              '// IF ISFALSE(MyBoolean)
    DoSomethingElse
END IF


;)
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Theo Gottwald

#2
Exactly, the difference is big, lets see your Example under the "Microscope" (DisASM):


4024F3   MOV EAX, ESI
4024F5   TEST EAX, EAX
4024F7   JZ  L402503
4024FD   NOP
4024FE   JMP L402504


Alternative this:

IF (R01<>0) THEN
    !NOP
  ELSE
     !NOP
  END IF   


will become quite different code:


4024F3   CMP ESI, BYTE 00
4024F6   JZ  L402502
4024FC   NOP
4024FD   JMP L402503
402502   NOP
402503   NOP



Which doesn't look worse to me. Both is much better then:

IF ISTRUE(R01) THEN
    !NOP
  ELSE
     !NOP
  END IF 



Because then we get this:


4024F3   MOV EAX, ESI
4024F5   TEST EAX, EAX
4024F7   MOV EAX, DWORD FFFFFFFF
4024FC   JNZ SHORT L4024FF
4024FE   INC  EAX
4024FF   TEST EAX, EAX
402501   JZ  L40250D
402507   NOP
402508   JMP L40250E
40250D   NOP


Which however is much longer, but also not that bad
compared to if we had been using DWORD instead of LONG (see post before).