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
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
;)