From 29a4c0feda56eb5275cd043c978a88e65b3c2334 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Thu, 21 Oct 2021 00:24:59 +0200 Subject: [PATCH] Added test demonstrating problem with using $ff as temporary zp in fragments. --- .../cache/fragment-cache-csg65ce02.asm | 2 +- .../cache/fragment-cache-mega45gs02.asm | 2 +- .../fragment/cache/fragment-cache-mos6502.asm | 2 +- .../cache/fragment-cache-mos6502x.asm | 12 +- .../cache/fragment-cache-rom6502x.asm | 2 +- .../cache/fragment-cache-wdc65c02.asm | 2 +- .../_deref_pbum1=_inc__deref_pbum1.asm | 9 + .../kickc/test/TestProgramsFast.java | 5 + src/test/kc/tmp-zp-problem.c | 30 + src/test/ref/tmp-zp-problem.asm | 92 +++ src/test/ref/tmp-zp-problem.cfg | 45 ++ src/test/ref/tmp-zp-problem.log | 628 ++++++++++++++++++ src/test/ref/tmp-zp-problem.sym | 22 + 13 files changed, 847 insertions(+), 6 deletions(-) create mode 100644 src/main/fragment/mos6502-common/_deref_pbum1=_inc__deref_pbum1.asm create mode 100644 src/test/kc/tmp-zp-problem.c create mode 100644 src/test/ref/tmp-zp-problem.asm create mode 100644 src/test/ref/tmp-zp-problem.cfg create mode 100644 src/test/ref/tmp-zp-problem.log create mode 100644 src/test/ref/tmp-zp-problem.sym diff --git a/src/main/fragment/cache/fragment-cache-csg65ce02.asm b/src/main/fragment/cache/fragment-cache-csg65ce02.asm index f69dfd7f7..603dd3acf 100644 --- a/src/main/fragment/cache/fragment-cache-csg65ce02.asm +++ b/src/main/fragment/cache/fragment-cache-csg65ce02.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE df9b88c62 df9b8b138 +//KICKC FRAGMENT CACHE e65dd24b5 e65dd4993 //FRAGMENT vbuzz=vbuc1 ldz #{c1} //FRAGMENT vbuzz_lt_vbuc1_then_la1 diff --git a/src/main/fragment/cache/fragment-cache-mega45gs02.asm b/src/main/fragment/cache/fragment-cache-mega45gs02.asm index 61497d801..a94aeb5f9 100644 --- a/src/main/fragment/cache/fragment-cache-mega45gs02.asm +++ b/src/main/fragment/cache/fragment-cache-mega45gs02.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE df9b88c62 df9b8b138 +//KICKC FRAGMENT CACHE e65dd24b5 e65dd4993 //FRAGMENT vbuz1=vbuc1 ldz #{c1} stz {z1} diff --git a/src/main/fragment/cache/fragment-cache-mos6502.asm b/src/main/fragment/cache/fragment-cache-mos6502.asm index 28c8c70ed..6fed965f1 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE df9b88c62 df9b8b138 +//KICKC FRAGMENT CACHE e65dd24b5 e65dd4993 //FRAGMENT vbuz1=vbuc1 lda #{c1} sta {z1} diff --git a/src/main/fragment/cache/fragment-cache-mos6502x.asm b/src/main/fragment/cache/fragment-cache-mos6502x.asm index 4d555a62a..1f414618d 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502x.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502x.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE df9b88c62 df9b8b138 +//KICKC FRAGMENT CACHE e65dd24b5 e65dd4993 //FRAGMENT vbuz1=vbuc1 lda #{c1} sta {z1} @@ -8935,6 +8935,16 @@ bcc {la1} lda {c1} cmp #{c2} bcs {la1} +//FRAGMENT _deref_pbum1=_inc__deref_pbum1 +ldy {m1} +sty $fe +ldy {m1}+1 +sty $ff +ldy #0 +lda ($fe),y +clc +adc #1 +sta ($fe),y //FRAGMENT pwuz1=pwuc1 lda #<{c1} sta {z1} diff --git a/src/main/fragment/cache/fragment-cache-rom6502x.asm b/src/main/fragment/cache/fragment-cache-rom6502x.asm index e9287b1b5..449c23309 100644 --- a/src/main/fragment/cache/fragment-cache-rom6502x.asm +++ b/src/main/fragment/cache/fragment-cache-rom6502x.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE df9b88c62 df9b8b138 +//KICKC FRAGMENT CACHE e65dd24b5 e65dd4993 //FRAGMENT _deref_pbuc1=_inc__deref_pbuc1 inc {c1} //FRAGMENT isr_hardware_all_entry diff --git a/src/main/fragment/cache/fragment-cache-wdc65c02.asm b/src/main/fragment/cache/fragment-cache-wdc65c02.asm index 2b57394a2..49d87deac 100644 --- a/src/main/fragment/cache/fragment-cache-wdc65c02.asm +++ b/src/main/fragment/cache/fragment-cache-wdc65c02.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE df9b88c62 df9b8b138 +//KICKC FRAGMENT CACHE e65dd24b5 e65dd4993 //FRAGMENT vbuz1=_deref_pbuc1 lda {c1} sta {z1} diff --git a/src/main/fragment/mos6502-common/_deref_pbum1=_inc__deref_pbum1.asm b/src/main/fragment/mos6502-common/_deref_pbum1=_inc__deref_pbum1.asm new file mode 100644 index 000000000..0d4ed9ad4 --- /dev/null +++ b/src/main/fragment/mos6502-common/_deref_pbum1=_inc__deref_pbum1.asm @@ -0,0 +1,9 @@ +ldy {m1} +sty $fe +ldy {m1}+1 +sty $ff +ldy #0 +lda ($fe),y +clc +adc #1 +sta ($fe),y \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index 22c87eec6..610d8940f 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -9,6 +9,11 @@ import java.io.IOException; */ public class TestProgramsFast extends TestPrograms { + @Test + public void testTmpZpProblem() throws IOException { + compileAndCompare("tmp-zp-problem.c", log()); + } + @Test public void testConstBoolReturnProblem() throws IOException { compileAndCompare("const-bool-return-problem.c"); diff --git a/src/test/kc/tmp-zp-problem.c b/src/test/kc/tmp-zp-problem.c new file mode 100644 index 000000000..88d121a68 --- /dev/null +++ b/src/test/kc/tmp-zp-problem.c @@ -0,0 +1,30 @@ +// Demonstrates a problem where temporary zp-variables are overwrites each other between different "threads" +#include +#include <6502.h> + +// Setup the IRQ routine +void main() { + SEI(); + *KERNEL_IRQ = &irq; + CLI(); + + for(;;) { + for(char i=0;i<10;i++) + for(char j=0;j<10;j++) { + char k = i+j; + if(k>0x80) { + VICII->BORDER_COLOR++; + } + } + } +} + +__mem char * volatile ptr = (char*)0xff00; + + +// The Interrupt Handler +__interrupt(rom_sys_c64) void irq() { + *BG_COLOR = WHITE; + (*ptr)++; + *BG_COLOR = BLACK; +} \ No newline at end of file diff --git a/src/test/ref/tmp-zp-problem.asm b/src/test/ref/tmp-zp-problem.asm new file mode 100644 index 000000000..b77443db2 --- /dev/null +++ b/src/test/ref/tmp-zp-problem.asm @@ -0,0 +1,92 @@ +// Demonstrates a problem where temporary zp-variables are overwrites each other between different "threads" +/// @file +/// Commodore 64 Registers and Constants +/// @file +/// The MOS 6526 Complex Interface Adapter (CIA) +/// +/// http://archive.6502.org/datasheets/mos_6526_cia_recreated.pdf + // Commodore 64 PRG executable file +.file [name="tmp-zp-problem.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + /// The colors of the C64 + .const BLACK = 0 + .const WHITE = 1 + .const OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR = $20 + /// $D021 Background Color 0 + .label BG_COLOR = $d021 + /// The VIC-II MOS 6567/6569 + .label VICII = $d000 + /// The vector used when the KERNAL serves IRQ interrupts + .label KERNEL_IRQ = $314 +.segment Code +// The Interrupt Handler +irq: { + // *BG_COLOR = WHITE + lda #WHITE + sta BG_COLOR + // (*ptr)++; + ldy ptr + sty.z $fe + ldy ptr+1 + sty.z $ff + ldy #0 + lda ($fe),y + clc + adc #1 + sta ($fe),y + // *BG_COLOR = BLACK + lda #BLACK + sta BG_COLOR + // } + jmp $ea31 +} +// Setup the IRQ routine +main: { + // asm + sei + // *KERNEL_IRQ = &irq + lda #irq + sta KERNEL_IRQ+1 + // asm + cli + __b4: + ldx #0 + __b1: + // for(char i=0;i<10;i++) + cpx #$a + bcc __b6 + jmp __b4 + __b6: + ldy #0 + __b2: + // for(char j=0;j<10;j++) + cpy #$a + bcc __b3 + // for(char i=0;i<10;i++) + inx + jmp __b1 + __b3: + // char k = i+j + txa + sty.z $ff + clc + adc.z $ff + // if(k>0x80) + cmp #$80+1 + bcc __b5 + // VICII->BORDER_COLOR++; + inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR + __b5: + // for(char j=0;j<10;j++) + iny + jmp __b2 +} +.segment Data + ptr: .word $ff00 diff --git a/src/test/ref/tmp-zp-problem.cfg b/src/test/ref/tmp-zp-problem.cfg new file mode 100644 index 000000000..72f5a8e6e --- /dev/null +++ b/src/test/ref/tmp-zp-problem.cfg @@ -0,0 +1,45 @@ + +__interrupt(rom_sys_c64) void irq() +irq: scope:[irq] from + [0] *BG_COLOR = WHITE + [1] *ptr = ++ *ptr + [2] *BG_COLOR = BLACK + to:irq::@return +irq::@return: scope:[irq] from irq + [3] return + to:@return + +void main() +main: scope:[main] from + [4] phi() + to:main::SEI1 +main::SEI1: scope:[main] from main + asm { sei } + to:main::@7 +main::@7: scope:[main] from main::SEI1 + [6] *KERNEL_IRQ = &irq + to:main::CLI1 +main::CLI1: scope:[main] from main::@7 + asm { cli } + to:main::@1 +main::@1: scope:[main] from main::@1 main::@4 main::CLI1 + [8] main::i#2 = phi( main::@1/0, main::@4/main::i#1, main::CLI1/0 ) + [9] if(main::i#2<$a) goto main::@2 + to:main::@1 +main::@2: scope:[main] from main::@1 main::@5 + [10] main::j#2 = phi( main::@1/0, main::@5/main::j#1 ) + [11] if(main::j#2<$a) goto main::@3 + to:main::@4 +main::@4: scope:[main] from main::@2 + [12] main::i#1 = ++ main::i#2 + to:main::@1 +main::@3: scope:[main] from main::@2 + [13] main::k#0 = main::i#2 + main::j#2 + [14] if(main::k#0<$80+1) goto main::@5 + to:main::@6 +main::@6: scope:[main] from main::@3 + [15] *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) + to:main::@5 +main::@5: scope:[main] from main::@3 main::@6 + [16] main::j#1 = ++ main::j#2 + to:main::@2 diff --git a/src/test/ref/tmp-zp-problem.log b/src/test/ref/tmp-zp-problem.log new file mode 100644 index 000000000..9d656c280 --- /dev/null +++ b/src/test/ref/tmp-zp-problem.log @@ -0,0 +1,628 @@ +Resolved forward reference irq to __interrupt(rom_sys_c64) void irq() +Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx) +Inlined call call SEI +Inlined call call CLI +Eliminating unused variable with no statement main::$4 + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + to:main::SEI1 +main::SEI1: scope:[main] from main + asm { sei } + to:main::@9 +main::@9: scope:[main] from main::SEI1 + *KERNEL_IRQ = &irq + to:main::CLI1 +main::CLI1: scope:[main] from main::@9 + asm { cli } + to:main::@1 +main::@1: scope:[main] from main::@2 main::CLI1 + main::i#0 = 0 + to:main::@2 +main::@2: scope:[main] from main::@1 main::@6 + main::i#2 = phi( main::@1/main::i#0, main::@6/main::i#1 ) + main::$2 = main::i#2 < $a + if(main::$2) goto main::@3 + to:main::@1 +main::@3: scope:[main] from main::@2 + main::i#6 = phi( main::@2/main::i#2 ) + main::j#0 = 0 + to:main::@4 +main::@4: scope:[main] from main::@3 main::@7 + main::i#5 = phi( main::@3/main::i#6, main::@7/main::i#7 ) + main::j#2 = phi( main::@3/main::j#0, main::@7/main::j#1 ) + main::$3 = main::j#2 < $a + if(main::$3) goto main::@5 + to:main::@6 +main::@5: scope:[main] from main::@4 + main::j#3 = phi( main::@4/main::j#2 ) + main::i#3 = phi( main::@4/main::i#5 ) + main::k#0 = main::i#3 + main::j#3 + main::$5 = main::k#0 > $80 + main::$6 = ! main::$5 + if(main::$6) goto main::@7 + to:main::@8 +main::@6: scope:[main] from main::@4 + main::i#4 = phi( main::@4/main::i#5 ) + main::i#1 = ++ main::i#4 + to:main::@2 +main::@7: scope:[main] from main::@5 main::@8 + main::i#7 = phi( main::@5/main::i#3, main::@8/main::i#8 ) + main::j#4 = phi( main::@5/main::j#3, main::@8/main::j#5 ) + main::j#1 = ++ main::j#4 + to:main::@4 +main::@8: scope:[main] from main::@5 + main::i#8 = phi( main::@5/main::i#3 ) + main::j#5 = phi( main::@5/main::j#3 ) + *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) + to:main::@7 +main::@return: scope:[main] from + return + to:@return + +__interrupt(rom_sys_c64) void irq() +irq: scope:[irq] from + *BG_COLOR = WHITE + *ptr = ++ *ptr + *BG_COLOR = BLACK + to:irq::@return +irq::@return: scope:[irq] from irq + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +__constant char * const BG_COLOR = (char *)$d021 +__constant const char BLACK = 0 +__constant void (** const KERNEL_IRQ)() = (void (**)())$314 +__constant char OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR = $20 +__constant struct MOS6569_VICII * const VICII = (struct MOS6569_VICII *)$d000 +__constant const char WHITE = 1 +void __start() +__interrupt(rom_sys_c64) void irq() +void main() +bool main::$2 +bool main::$3 +bool main::$5 +bool main::$6 +char main::i +char main::i#0 +char main::i#1 +char main::i#2 +char main::i#3 +char main::i#4 +char main::i#5 +char main::i#6 +char main::i#7 +char main::i#8 +char main::j +char main::j#0 +char main::j#1 +char main::j#2 +char main::j#3 +char main::j#4 +char main::j#5 +char main::k +char main::k#0 +__loadstore char * volatile ptr = (char *)$ff00 + +Adding number conversion cast (unumber) $a in main::$2 = main::i#2 < $a +Adding number conversion cast (unumber) $a in main::$3 = main::j#2 < $a +Adding number conversion cast (unumber) $80 in main::$5 = main::k#0 > $80 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (char *) 53281 +Simplifying constant pointer cast (struct MOS6569_VICII *) 53248 +Simplifying constant pointer cast (void (**)()) 788 +Simplifying constant pointer cast (char *) 65280 +Simplifying constant integer cast $a +Simplifying constant integer cast $a +Simplifying constant integer cast $80 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (char) $a +Finalized unsigned number type (char) $a +Finalized unsigned number type (char) $80 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inversing boolean not [15] main::$6 = main::k#0 <= $80 from [14] main::$5 = main::k#0 > $80 +Successful SSA optimization Pass2UnaryNotSimplification +Alias main::i#2 = main::i#6 +Alias main::i#3 = main::i#5 main::i#4 main::i#8 +Alias main::j#2 = main::j#3 main::j#5 +Successful SSA optimization Pass2AliasElimination +Alias main::j#2 = main::j#4 +Alias main::i#3 = main::i#7 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values main::i#3 main::i#2 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition main::$2 [6] if(main::i#2<$a) goto main::@3 +Simple Condition main::$3 [10] if(main::j#2<$a) goto main::@5 +Simple Condition main::$6 [13] if(main::k#0<=$80) goto main::@7 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant main::i#0 = 0 +Constant main::j#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Rewriting conditional comparison [13] if(main::k#0<=$80) goto main::@7 +Removing unused block main::@return +Successful SSA optimization Pass2EliminateUnusedBlocks +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Adding number conversion cast (unumber) $80+1 in [8] if(main::k#0<$80+1) goto main::@7 +Adding number conversion cast (unumber) 1 in [8] if(main::k#0<(unumber)$80+1) goto main::@7 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant integer cast $80+(unumber)1 +Simplifying constant integer cast 1 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (char) 1 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Inlining constant with var siblings main::i#0 +Inlining constant with var siblings main::j#0 +Constant inlined main::i#0 = 0 +Constant inlined main::j#0 = 0 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@1 +Adding NOP phi() at start of main::@3 +CALL GRAPH + +Created 2 initial phi equivalence classes +Coalesced [15] main::i#9 = main::i#1 +Coalesced [20] main::j#6 = main::j#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block label main::@1 +Culled Empty Block label main::@3 +Renumbering block main::@2 to main::@1 +Renumbering block main::@4 to main::@2 +Renumbering block main::@5 to main::@3 +Renumbering block main::@6 to main::@4 +Renumbering block main::@7 to main::@5 +Renumbering block main::@8 to main::@6 +Renumbering block main::@9 to main::@7 +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH + +__interrupt(rom_sys_c64) void irq() +irq: scope:[irq] from + [0] *BG_COLOR = WHITE + [1] *ptr = ++ *ptr + [2] *BG_COLOR = BLACK + to:irq::@return +irq::@return: scope:[irq] from irq + [3] return + to:@return + +void main() +main: scope:[main] from + [4] phi() + to:main::SEI1 +main::SEI1: scope:[main] from main + asm { sei } + to:main::@7 +main::@7: scope:[main] from main::SEI1 + [6] *KERNEL_IRQ = &irq + to:main::CLI1 +main::CLI1: scope:[main] from main::@7 + asm { cli } + to:main::@1 +main::@1: scope:[main] from main::@1 main::@4 main::CLI1 + [8] main::i#2 = phi( main::@1/0, main::@4/main::i#1, main::CLI1/0 ) + [9] if(main::i#2<$a) goto main::@2 + to:main::@1 +main::@2: scope:[main] from main::@1 main::@5 + [10] main::j#2 = phi( main::@1/0, main::@5/main::j#1 ) + [11] if(main::j#2<$a) goto main::@3 + to:main::@4 +main::@4: scope:[main] from main::@2 + [12] main::i#1 = ++ main::i#2 + to:main::@1 +main::@3: scope:[main] from main::@2 + [13] main::k#0 = main::i#2 + main::j#2 + [14] if(main::k#0<$80+1) goto main::@5 + to:main::@6 +main::@6: scope:[main] from main::@3 + [15] *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) + to:main::@5 +main::@5: scope:[main] from main::@3 main::@6 + [16] main::j#1 = ++ main::j#2 + to:main::@2 + + +VARIABLE REGISTER WEIGHTS +__interrupt(rom_sys_c64) void irq() +void main() +char main::i +char main::i#1 // 22.0 +char main::i#2 // 28.0 +char main::j +char main::j#1 // 202.0 +char main::j#2 // 80.8 +char main::k +char main::k#0 // 202.0 +__loadstore char * volatile ptr = (char *) 65280 // 4.0 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ main::j#2 main::j#1 ] +Added variable main::k#0 to live range equivalence class [ main::k#0 ] +Added variable ptr to live range equivalence class [ ptr ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::j#2 main::j#1 ] +[ main::k#0 ] +[ ptr ] +Allocated zp[1]:2 [ main::j#2 main::j#1 ] +Allocated zp[1]:3 [ main::k#0 ] +Allocated zp[1]:4 [ main::i#2 main::i#1 ] +Allocated mem[2] [ ptr ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *BG_COLOR = WHITE [ ptr ] ( [ ptr ] { } ) always clobbers reg byte a +Statement [1] *ptr = ++ *ptr [ ] ( [ ] { } ) always clobbers reg byte a reg byte y +Statement [2] *BG_COLOR = BLACK [ ] ( [ ] { } ) always clobbers reg byte a +Statement [6] *KERNEL_IRQ = &irq [ ] ( [ ] { } ) always clobbers reg byte a +Statement [13] main::k#0 = main::i#2 + main::j#2 [ main::i#2 main::j#2 main::k#0 ] ( [ main::i#2 main::j#2 main::k#0 ] { } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::j#2 main::j#1 ] +Statement [0] *BG_COLOR = WHITE [ ptr ] ( [ ptr ] { } ) always clobbers reg byte a +Statement [1] *ptr = ++ *ptr [ ] ( [ ] { } ) always clobbers reg byte a reg byte y +Statement [2] *BG_COLOR = BLACK [ ] ( [ ] { } ) always clobbers reg byte a +Statement [6] *KERNEL_IRQ = &irq [ ] ( [ ] { } ) always clobbers reg byte a +Statement [13] main::k#0 = main::i#2 + main::j#2 [ main::i#2 main::j#2 main::k#0 ] ( [ main::i#2 main::j#2 main::k#0 ] { } ) always clobbers reg byte a +Potential registers zp[1]:4 [ main::i#2 main::i#1 ] : zp[1]:4 , reg byte x , reg byte y , +Potential registers zp[1]:2 [ main::j#2 main::j#1 ] : zp[1]:2 , reg byte x , reg byte y , +Potential registers zp[1]:3 [ main::k#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , +Potential registers mem[2] [ ptr ] : mem[2] , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 282.8: zp[1]:2 [ main::j#2 main::j#1 ] 202: zp[1]:3 [ main::k#0 ] 50: zp[1]:4 [ main::i#2 main::i#1 ] +Uplift Scope [] 4: mem[2] [ ptr ] +Uplift Scope [MOS6526_CIA] +Uplift Scope [MOS6569_VICII] +Uplift Scope [MOS6581_SID] +Uplift Scope [irq] + +Uplifting [main] best 6098 combination reg byte y [ main::j#2 main::j#1 ] reg byte a [ main::k#0 ] reg byte x [ main::i#2 main::i#1 ] +Uplifting [] best 6098 combination mem[2] [ ptr ] +Uplifting [MOS6526_CIA] best 6098 combination +Uplifting [MOS6569_VICII] best 6098 combination +Uplifting [MOS6581_SID] best 6098 combination +Uplifting [irq] best 6098 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Demonstrates a problem where temporary zp-variables are overwrites each other between different "threads" +/// @file +/// Commodore 64 Registers and Constants +/// @file +/// The MOS 6526 Complex Interface Adapter (CIA) +/// +/// http://archive.6502.org/datasheets/mos_6526_cia_recreated.pdf + // Upstart + // Commodore 64 PRG executable file +.file [name="tmp-zp-problem.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels + /// The colors of the C64 + .const BLACK = 0 + .const WHITE = 1 + .const OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR = $20 + /// $D021 Background Color 0 + .label BG_COLOR = $d021 + /// The VIC-II MOS 6567/6569 + .label VICII = $d000 + /// The vector used when the KERNAL serves IRQ interrupts + .label KERNEL_IRQ = $314 +.segment Code + // irq +// The Interrupt Handler +irq: { + // interrupt(isr_rom_sys_c64_entry) -- isr_rom_sys_c64_entry + // [0] *BG_COLOR = WHITE -- _deref_pbuc1=vbuc2 + lda #WHITE + sta BG_COLOR + // [1] *ptr = ++ *ptr -- _deref_pbum1=_inc__deref_pbum1 + ldy ptr + sty.z $fe + ldy ptr+1 + sty.z $ff + ldy #0 + lda ($fe),y + clc + adc #1 + sta ($fe),y + // [2] *BG_COLOR = BLACK -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BG_COLOR + jmp __breturn + // irq::@return + __breturn: + // [3] return + // interrupt(isr_rom_sys_c64_exit) -- isr_rom_sys_c64_exit + jmp $ea31 +} + // main +// Setup the IRQ routine +main: { + jmp SEI1 + // main::SEI1 + SEI1: + // asm { sei } + sei + jmp __b7 + // main::@7 + __b7: + // [6] *KERNEL_IRQ = &irq -- _deref_qprc1=pprc2 + lda #irq + sta KERNEL_IRQ+1 + jmp CLI1 + // main::CLI1 + CLI1: + // asm { cli } + cli + // [8] phi from main::@1 main::CLI1 to main::@1 [phi:main::@1/main::CLI1->main::@1] + __b1_from___b1: + __b1_from_CLI1: + // [8] phi main::i#2 = 0 [phi:main::@1/main::CLI1->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp __b1 + // main::@1 + __b1: + // [9] if(main::i#2<$a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #$a + bcc __b2_from___b1 + jmp __b1_from___b1 + // [10] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + __b2_from___b1: + // [10] phi main::j#2 = 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + jmp __b2 + // main::@2 + __b2: + // [11] if(main::j#2<$a) goto main::@3 -- vbuyy_lt_vbuc1_then_la1 + cpy #$a + bcc __b3 + jmp __b4 + // main::@4 + __b4: + // [12] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx + inx + // [8] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + __b1_from___b4: + // [8] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy + jmp __b1 + // main::@3 + __b3: + // [13] main::k#0 = main::i#2 + main::j#2 -- vbuaa=vbuxx_plus_vbuyy + txa + sty.z $ff + clc + adc.z $ff + // [14] if(main::k#0<$80+1) goto main::@5 -- vbuaa_lt_vbuc1_then_la1 + cmp #$80+1 + bcc __b5 + jmp __b6 + // main::@6 + __b6: + // [15] *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1 + inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR + jmp __b5 + // main::@5 + __b5: + // [16] main::j#1 = ++ main::j#2 -- vbuyy=_inc_vbuyy + iny + // [10] phi from main::@5 to main::@2 [phi:main::@5->main::@2] + __b2_from___b5: + // [10] phi main::j#2 = main::j#1 [phi:main::@5->main::@2#0] -- register_copy + jmp __b2 +} + // File Data +.segment Data + ptr: .word $ff00 + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __breturn +Removing instruction jmp SEI1 +Removing instruction jmp __b7 +Removing instruction jmp CLI1 +Removing instruction jmp __b1 +Removing instruction jmp __b2 +Removing instruction jmp __b4 +Removing instruction jmp __b6 +Removing instruction jmp __b5 +Succesful ASM optimization Pass5NextJumpElimination +Replacing label __b1_from___b1 with __b1_from_CLI1 +Removing instruction __b1_from___b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction __breturn: +Removing instruction SEI1: +Removing instruction __b7: +Removing instruction CLI1: +Removing instruction __b4: +Removing instruction __b1_from___b4: +Removing instruction __b6: +Removing instruction __b2_from___b5: +Succesful ASM optimization Pass5UnusedLabelElimination +Relabelling long label __b1_from_CLI1 to __b4 +Relabelling long label __b2_from___b1 to __b6 +Succesful ASM optimization Pass5RelabelLongLabels + +FINAL SYMBOL TABLE +__constant char * const BG_COLOR = (char *) 53281 +__constant const char BLACK = 0 +__constant void (** const KERNEL_IRQ)() = (void (**)()) 788 +__constant char OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR = $20 +__constant struct MOS6569_VICII * const VICII = (struct MOS6569_VICII *) 53248 +__constant const char WHITE = 1 +__interrupt(rom_sys_c64) void irq() +void main() +char main::i +char main::i#1 // reg byte x 22.0 +char main::i#2 // reg byte x 28.0 +char main::j +char main::j#1 // reg byte y 202.0 +char main::j#2 // reg byte y 80.8 +char main::k +char main::k#0 // reg byte a 202.0 +__loadstore char * volatile ptr = (char *) 65280 // mem[2] 4.0 + +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::j#2 main::j#1 ] +reg byte a [ main::k#0 ] +mem[2] [ ptr ] + + +FINAL ASSEMBLER +Score: 4559 + + // File Comments +// Demonstrates a problem where temporary zp-variables are overwrites each other between different "threads" +/// @file +/// Commodore 64 Registers and Constants +/// @file +/// The MOS 6526 Complex Interface Adapter (CIA) +/// +/// http://archive.6502.org/datasheets/mos_6526_cia_recreated.pdf + // Upstart + // Commodore 64 PRG executable file +.file [name="tmp-zp-problem.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels + /// The colors of the C64 + .const BLACK = 0 + .const WHITE = 1 + .const OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR = $20 + /// $D021 Background Color 0 + .label BG_COLOR = $d021 + /// The VIC-II MOS 6567/6569 + .label VICII = $d000 + /// The vector used when the KERNAL serves IRQ interrupts + .label KERNEL_IRQ = $314 +.segment Code + // irq +// The Interrupt Handler +irq: { + // interrupt(isr_rom_sys_c64_entry) -- isr_rom_sys_c64_entry + // *BG_COLOR = WHITE + // [0] *BG_COLOR = WHITE -- _deref_pbuc1=vbuc2 + lda #WHITE + sta BG_COLOR + // (*ptr)++; + // [1] *ptr = ++ *ptr -- _deref_pbum1=_inc__deref_pbum1 + ldy ptr + sty.z $fe + ldy ptr+1 + sty.z $ff + ldy #0 + lda ($fe),y + clc + adc #1 + sta ($fe),y + // *BG_COLOR = BLACK + // [2] *BG_COLOR = BLACK -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BG_COLOR + // irq::@return + // } + // [3] return + // interrupt(isr_rom_sys_c64_exit) -- isr_rom_sys_c64_exit + jmp $ea31 +} + // main +// Setup the IRQ routine +main: { + // main::SEI1 + // asm + // asm { sei } + sei + // main::@7 + // *KERNEL_IRQ = &irq + // [6] *KERNEL_IRQ = &irq -- _deref_qprc1=pprc2 + lda #irq + sta KERNEL_IRQ+1 + // main::CLI1 + // asm + // asm { cli } + cli + // [8] phi from main::@1 main::CLI1 to main::@1 [phi:main::@1/main::CLI1->main::@1] + __b4: + // [8] phi main::i#2 = 0 [phi:main::@1/main::CLI1->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + // main::@1 + __b1: + // for(char i=0;i<10;i++) + // [9] if(main::i#2<$a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #$a + bcc __b6 + jmp __b4 + // [10] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + __b6: + // [10] phi main::j#2 = 0 [phi:main::@1->main::@2#0] -- vbuyy=vbuc1 + ldy #0 + // main::@2 + __b2: + // for(char j=0;j<10;j++) + // [11] if(main::j#2<$a) goto main::@3 -- vbuyy_lt_vbuc1_then_la1 + cpy #$a + bcc __b3 + // main::@4 + // for(char i=0;i<10;i++) + // [12] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx + inx + // [8] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + // [8] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy + jmp __b1 + // main::@3 + __b3: + // char k = i+j + // [13] main::k#0 = main::i#2 + main::j#2 -- vbuaa=vbuxx_plus_vbuyy + txa + sty.z $ff + clc + adc.z $ff + // if(k>0x80) + // [14] if(main::k#0<$80+1) goto main::@5 -- vbuaa_lt_vbuc1_then_la1 + cmp #$80+1 + bcc __b5 + // main::@6 + // VICII->BORDER_COLOR++; + // [15] *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) = ++ *((char *)VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR) -- _deref_pbuc1=_inc__deref_pbuc1 + inc VICII+OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR + // main::@5 + __b5: + // for(char j=0;j<10;j++) + // [16] main::j#1 = ++ main::j#2 -- vbuyy=_inc_vbuyy + iny + // [10] phi from main::@5 to main::@2 [phi:main::@5->main::@2] + // [10] phi main::j#2 = main::j#1 [phi:main::@5->main::@2#0] -- register_copy + jmp __b2 +} + // File Data +.segment Data + ptr: .word $ff00 + diff --git a/src/test/ref/tmp-zp-problem.sym b/src/test/ref/tmp-zp-problem.sym new file mode 100644 index 000000000..21fb50426 --- /dev/null +++ b/src/test/ref/tmp-zp-problem.sym @@ -0,0 +1,22 @@ +__constant char * const BG_COLOR = (char *) 53281 +__constant const char BLACK = 0 +__constant void (** const KERNEL_IRQ)() = (void (**)()) 788 +__constant char OFFSET_STRUCT_MOS6569_VICII_BORDER_COLOR = $20 +__constant struct MOS6569_VICII * const VICII = (struct MOS6569_VICII *) 53248 +__constant const char WHITE = 1 +__interrupt(rom_sys_c64) void irq() +void main() +char main::i +char main::i#1 // reg byte x 22.0 +char main::i#2 // reg byte x 28.0 +char main::j +char main::j#1 // reg byte y 202.0 +char main::j#2 // reg byte y 80.8 +char main::k +char main::k#0 // reg byte a 202.0 +__loadstore char * volatile ptr = (char *) 65280 // mem[2] 4.0 + +reg byte x [ main::i#2 main::i#1 ] +reg byte y [ main::j#2 main::j#1 ] +reg byte a [ main::k#0 ] +mem[2] [ ptr ]