EgonOlsen71 / basicv2

A Commodore (CBM) BASIC V2 interpreter/compiler written in Java
https://egonolsen71.github.io/basicv2/
The Unlicense
86 stars 15 forks source link

optimize "IF B=C THEN ..." #29

Closed nippur72 closed 5 years ago

nippur72 commented 5 years ago

This is a suggestion for improving the case

IF B=C THEN ...
IF B<>C THEN ...

when B and C are real variables or constants (no expression). It's a very specific case, but occurs quite often in BASIC programs, so optimizing it might be lead to speed and size improvement.

The rationale is that real variables can be compared directly without passing from the FAC.

Currently:

LDA #<VAR_B
LDY #>VAR_B
JSR REALFAC
LDA #<VAR_C
LDY #>VAR_C
JSR CMPFAC
BNE SKIP
; 16 bytes long

Suggested:

ldx #4
loop:
  lda VAR_B, x
  cmp VAR_C, x
  bne skip      ; beq skip for IF B<>C THEN ...
  dex
  bpl loop
equals:
...
skip:
...
; 13 bytes 

It's 3 bytes shorter and a lot faster.

The only problem could be the case when B or C are zero but with "dirty" mantissa bytes, (e.g. $80 + 4 random bytes) because of the early exit in the ROM CMPFAC routine. I have been discussing about this on the Denial Forum and it seems that this case should never occur; when the ROM returns a "0" number it's always $80,0,0,0,0, so direct byte compare for real numbers is formally correct.

EgonOlsen71 commented 5 years ago

Interesting...I'm not sure if this is applicable in all cases, though. Because Mospeed's runtime uses 0 values with a dirty mantissa in some cases. But it might not affect this...I'll take a look at it.

EgonOlsen71 commented 5 years ago

I've added it. The implementation is slightly different from your suggestion, but it's basically the same thing. I also had to modify the runtime to make three routines that were allowing for a dirty mantissa to set the whole FAC to zero instead. I hope this covers all edge cases. Performance wise, it depends if this helps or not. A special test case with 3 IFs of which 2 could be optimized improved by around 8%.

nippur72 commented 5 years ago

is this PR in the .jar?

EgonOlsen71 commented 5 years ago

It should be. There might not trigger in all cases though.

nippur72 commented 5 years ago

(ok, but I think the other PR about the addressheader is not in the JAR because I get the old command line help message).

Regarding this one, I noticed what could be an issue: the label dceloop1 is generated twice

20 A=8:A=A+1
30 IF A=8 THEN PRINT 
31 IF A<>8 THEN PRINT 

compiled:

LINE_30:
...
dceloop1:
...
BPL dceloop1
...
LINE_31:
...
dceloop1:
...
BPL dceloop1

But the label is incremented correctly if line 31 is changed into IF A=8 ...

EgonOlsen71 commented 5 years ago

Yes, you are right. That was a copy and paste issue. Should be fixed now. The JAR is new as well, I hope it includes the address bytes fix now.