pzembrod / cc64

cc64 is a small-C compiler written in Forth, hosted on the Commodore C64, Plus4 and C16 with 64k, and on the Commander X16. It is targeting the 6502 CPU.
Other
96 stars 6 forks source link

Wrongly removed "read from memory" on inline optimization #22

Closed spotlessmind1975 closed 3 years ago

spotlessmind1975 commented 3 years ago

When activating the "Optimize code, inline standard funtions" (-Os) or the "Optimize code, inline more code" (-Oi) option, if a C source code has (in sequence) a direct write statement and a direct read statement on the same RAM memory location, the reading step is omitted.

The problem arises if the memory is accessed using the address directly. It does not occur if the address to read and write from is stored in a (temporary) pointer variable, or if the optimization is disabled.

Currently, the only workaround to avoid allocating an additional variable is to assign a value of 0 to the (destination) memory location: this prevents the optimizer from exploiting the value just written.

However, I believe there should be a way to indicate that (specific?) memory locations can be "volatile" so that the optimizer cannot make any assumptions about the reusability of their value.

Example:

unsigned char port;
[...]
(*(unsigned char*)0xff08) = 0x04;
port = (*(unsigned char*)0xff08);        `

This is the correct assembly output (without -Osir optimizations):

00042Cr 1               ;
00042Cr 1               ; (*(unsigned char*)0xff08) = 0x04;
00042Cr 1               ;
00042Cr 1  A2 00            ldx     #$00
00042Er 1  A9 04            lda     #$04
000430r 1  8D 08 FF         sta     $FF08
000433r 1               ;
000433r 1               ; port = (*(unsigned char*)0xff08);
000433r 1               ;
000433r 1  A2 00            ldx     #$00
000435r 1  AD 08 FF         lda     $FF08 ; <--- this is the step missed!
000438r 1  8D rr rr         sta     L0117
00043Br 1               ;

This is the (wrong) assembly output:

000281r 1               ; (*(unsigned char*)0xff08) = 0x04;
000281r 1               ;
000281r 1  A9 04            lda     #$04
000283r 1  8D 08 FF     L0158:  sta     $FF08
000286r 1               ;
000286r 1               ; port = (*(unsigned char*)0xff08);
000286r 1               ;
000286r 1  8D rr rr         sta     L0118
000289r 1               ;

This is the workaround:

000289r 1               ; (*(unsigned char*)0xff08) = 0x04;
000289r 1               ;
000289r 1  8D 08 FF         sta     $FF08
00028Cr 1               ;
00028Cr 1               ; port = 0;
00028Cr 1               ;
00028Cr 1  8C rr rr         sty     L0118
00028Fr 1               ;
00028Fr 1               ; port = (*(unsigned char*)0xff08);
00028Fr 1               ;
00028Fr 1  AD 08 FF         lda     $FF08 ; <--- this is the step needed
000292r 1  8D rr rr         sta     L0118

Command line used to compile:

cl65 -T -l obj/plus4/midres_plus4.asm -t plus4 -c -W -const-comparison -Osir -Cl -D__CBM__ -o obj/plus4/midres_plus4.o obj/plus4/midres_plus4.c
spotlessmind1975 commented 3 years ago

Sorry, wrong repository