diff --git a/src/main/fragment/vwuz1=vbuaa_plus_vbuz2.asm b/src/main/fragment/vwuz1=vbuaa_plus_vbuz2.asm new file mode 100644 index 000000000..c6d2bea39 --- /dev/null +++ b/src/main/fragment/vwuz1=vbuaa_plus_vbuz2.asm @@ -0,0 +1,6 @@ +clc +adc {z2} +sta {z1} +lda #0 +adc #0 +sta {z1}+1 \ No newline at end of file diff --git a/src/main/java/dk/camelot64/kickc/KickC.java b/src/main/java/dk/camelot64/kickc/KickC.java index a9ff4fc40..60c3336b0 100644 --- a/src/main/java/dk/camelot64/kickc/KickC.java +++ b/src/main/java/dk/camelot64/kickc/KickC.java @@ -172,7 +172,7 @@ public class KickC implements Callable { program = compiler.compile(kcFile.toString()); } catch(CompileError e) { // Print the error and exit with compile error - System.err.print(e.getMessage()); + System.err.println(e.getMessage()); System.exit(COMPILE_ERROR); } diff --git a/src/main/kc/stdlib/string.kc b/src/main/kc/stdlib/string.kc new file mode 100644 index 000000000..9e4480917 --- /dev/null +++ b/src/main/kc/stdlib/string.kc @@ -0,0 +1,36 @@ +// Standard C strings.h - functions to manipulate C strings and arrays. + +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +byte* memcpy( byte* destination, byte* source, word num ) { + byte* src = source; + byte* dst = destination; + for( word i=0;iSCREEN + sta memcpy.dst+1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + lda #COLS + sta memcpy.dst+1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + b1: + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + lda #0 + sta i + sta i+1 + b1: + ldy #0 + lda (src),y + sta (dst),y + inc dst + bne !+ + inc dst+1 + !: + inc src + bne !+ + inc src+1 + !: + inc i + bne !+ + inc i+1 + !: + lda i+1 + cmp #>$3e8 + bcc b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1 + !: + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + diff --git a/src/test/ref/complex/medusa/medusa.cfg b/src/test/ref/complex/medusa/medusa.cfg new file mode 100644 index 000000000..4fad14769 --- /dev/null +++ b/src/test/ref/complex/medusa/medusa.cfg @@ -0,0 +1,45 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + }} + kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + }} + to:@2 +@2: scope:[] from @1 + [3] phi() + [4] call main + to:@end +@end: scope:[] from @2 + [5] phi() +main: scope:[main] from @2 + [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 + [7] call memcpy + to:main::@2 +main::@2: scope:[main] from main + [8] phi() + [9] call memcpy + to:main::@1 +main::@1: scope:[main] from main::@1 main::@2 + [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e + to:main::@1 +memcpy: scope:[memcpy] from main main::@2 + [11] (byte*) memcpy::dst#0 ← phi( main/(const byte*) SCREEN#0 main::@2/(const byte*) COLS#0 ) + [11] (byte*) memcpy::src#0 ← phi( main/(const byte*) MEDUSA_SCREEN#0 main::@2/(const byte*) MEDUSA_COLORS#0 ) + to:memcpy::@1 +memcpy::@1: scope:[memcpy] from memcpy memcpy::@1 + [12] (word) memcpy::i#2 ← phi( memcpy/(byte) 0 memcpy::@1/(word) memcpy::i#1 ) + [12] (byte*) memcpy::dst#2 ← phi( memcpy/(byte*) memcpy::dst#0 memcpy::@1/(byte*) memcpy::dst#1 ) + [12] (byte*) memcpy::src#2 ← phi( memcpy/(byte*) memcpy::src#0 memcpy::@1/(byte*) memcpy::src#1 ) + [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) + [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 + [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 + [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 + [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 + to:memcpy::@return +memcpy::@return: scope:[memcpy] from memcpy::@1 + [18] return + to:@return diff --git a/src/test/ref/complex/medusa/medusa.log b/src/test/ref/complex/medusa/medusa.log new file mode 100644 index 000000000..1fc152fab --- /dev/null +++ b/src/test/ref/complex/medusa/medusa.log @@ -0,0 +1,948 @@ +Warning! Adding boolean cast to non-boolean condition *((byte*) strcpy::src) +Adding pointer type conversion cast (byte*) PROCPORT_DDR in (byte*) PROCPORT_DDR ← (number) 0 +Adding pointer type conversion cast (byte*) PROCPORT in (byte*) PROCPORT ← (number) 1 +Adding pointer type conversion cast (byte*) CHARGEN in (byte*) CHARGEN ← (number) $d000 +Adding pointer type conversion cast (byte*) SPRITES_XPOS in (byte*) SPRITES_XPOS ← (number) $d000 +Adding pointer type conversion cast (byte*) SPRITES_YPOS in (byte*) SPRITES_YPOS ← (number) $d001 +Adding pointer type conversion cast (byte*) SPRITES_XMSB in (byte*) SPRITES_XMSB ← (number) $d010 +Adding pointer type conversion cast (byte*) RASTER in (byte*) RASTER ← (number) $d012 +Adding pointer type conversion cast (byte*) SPRITES_ENABLE in (byte*) SPRITES_ENABLE ← (number) $d015 +Adding pointer type conversion cast (byte*) SPRITES_EXPAND_Y in (byte*) SPRITES_EXPAND_Y ← (number) $d017 +Adding pointer type conversion cast (byte*) SPRITES_PRIORITY in (byte*) SPRITES_PRIORITY ← (number) $d01b +Adding pointer type conversion cast (byte*) SPRITES_MC in (byte*) SPRITES_MC ← (number) $d01c +Adding pointer type conversion cast (byte*) SPRITES_EXPAND_X in (byte*) SPRITES_EXPAND_X ← (number) $d01d +Adding pointer type conversion cast (byte*) BORDERCOL in (byte*) BORDERCOL ← (number) $d020 +Adding pointer type conversion cast (byte*) BGCOL in (byte*) BGCOL ← (number) $d021 +Adding pointer type conversion cast (byte*) BGCOL1 in (byte*) BGCOL1 ← (number) $d021 +Adding pointer type conversion cast (byte*) BGCOL2 in (byte*) BGCOL2 ← (number) $d022 +Adding pointer type conversion cast (byte*) BGCOL3 in (byte*) BGCOL3 ← (number) $d023 +Adding pointer type conversion cast (byte*) BGCOL4 in (byte*) BGCOL4 ← (number) $d024 +Adding pointer type conversion cast (byte*) SPRITES_MC1 in (byte*) SPRITES_MC1 ← (number) $d025 +Adding pointer type conversion cast (byte*) SPRITES_MC2 in (byte*) SPRITES_MC2 ← (number) $d026 +Adding pointer type conversion cast (byte*) SPRITES_COLS in (byte*) SPRITES_COLS ← (number) $d027 +Adding pointer type conversion cast (byte*) VIC_CONTROL in (byte*) VIC_CONTROL ← (number) $d011 +Adding pointer type conversion cast (byte*) D011 in (byte*) D011 ← (number) $d011 +Adding pointer type conversion cast (byte*) VIC_CONTROL2 in (byte*) VIC_CONTROL2 ← (number) $d016 +Adding pointer type conversion cast (byte*) D016 in (byte*) D016 ← (number) $d016 +Adding pointer type conversion cast (byte*) D018 in (byte*) D018 ← (number) $d018 +Adding pointer type conversion cast (byte*) VIC_MEMORY in (byte*) VIC_MEMORY ← (number) $d018 +Adding pointer type conversion cast (byte*) LIGHTPEN_X in (byte*) LIGHTPEN_X ← (number) $d013 +Adding pointer type conversion cast (byte*) LIGHTPEN_Y in (byte*) LIGHTPEN_Y ← (number) $d014 +Adding pointer type conversion cast (byte*) IRQ_STATUS in (byte*) IRQ_STATUS ← (number) $d019 +Adding pointer type conversion cast (byte*) IRQ_ENABLE in (byte*) IRQ_ENABLE ← (number) $d01a +Adding pointer type conversion cast (byte*) COLS in (byte*) COLS ← (number) $d800 +Adding pointer type conversion cast (byte*) CIA1_PORT_A in (byte*) CIA1_PORT_A ← (number) $dc00 +Adding pointer type conversion cast (byte*) CIA1_PORT_B in (byte*) CIA1_PORT_B ← (number) $dc01 +Adding pointer type conversion cast (byte*) CIA1_PORT_A_DDR in (byte*) CIA1_PORT_A_DDR ← (number) $dc02 +Adding pointer type conversion cast (byte*) CIA1_PORT_B_DDR in (byte*) CIA1_PORT_B_DDR ← (number) $dc03 +Adding pointer type conversion cast (byte*) CIA1_INTERRUPT in (byte*) CIA1_INTERRUPT ← (number) $dc0d +Adding pointer type conversion cast (byte*) CIA2_PORT_A in (byte*) CIA2_PORT_A ← (number) $dd00 +Adding pointer type conversion cast (byte*) CIA2_PORT_B in (byte*) CIA2_PORT_B ← (number) $dd01 +Adding pointer type conversion cast (byte*) CIA2_PORT_A_DDR in (byte*) CIA2_PORT_A_DDR ← (number) $dd02 +Adding pointer type conversion cast (byte*) CIA2_PORT_B_DDR in (byte*) CIA2_PORT_B_DDR ← (number) $dd03 +Adding pointer type conversion cast (byte*) CIA2_INTERRUPT in (byte*) CIA2_INTERRUPT ← (number) $dd0d +Adding pointer type conversion cast (void()**) KERNEL_IRQ in (void()**) KERNEL_IRQ ← (number) $314 +Adding pointer type conversion cast (void()**) HARDWARE_IRQ in (void()**) HARDWARE_IRQ ← (number) $fffe +Adding pointer type conversion cast (byte*) MEDUSA_SCREEN in (byte*) MEDUSA_SCREEN ← (number) $1000 +Adding pointer type conversion cast (byte*) MEDUSA_COLORS in (byte*) MEDUSA_COLORS ← (number) $1400 +Adding pointer type conversion cast (byte*) SCREEN in (byte*) SCREEN ← (number) $400 +Identified constant variable (byte*) MEDUSA_SCREEN +Identified constant variable (byte*) MEDUSA_COLORS +Identified constant variable (byte*) SCREEN +Inlined call (byte~) vicSelectGfxBank::$0 ← call toDd00 (byte*) vicSelectGfxBank::gfx +Culled Empty Block (label) @1 +Culled Empty Block (label) @2 +Culled Empty Block (label) @3 +Culled Empty Block (label) @4 +Culled Empty Block (label) memcpy::@3 +Culled Empty Block (label) @5 +Culled Empty Block (label) @6 +Culled Empty Block (label) main::@4 +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@5 +Culled Empty Block (label) main::@6 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (number) $d021 + (byte*) COLS#0 ← ((byte*)) (number) $d800 + (byte) BLACK#0 ← (number) 0 + to:@7 +memcpy: scope:[memcpy] from main main::@7 + (word) memcpy::num#3 ← phi( main/(word) memcpy::num#0 main::@7/(word) memcpy::num#1 ) + (byte*) memcpy::destination#2 ← phi( main/(byte*) memcpy::destination#0 main::@7/(byte*) memcpy::destination#1 ) + (byte*) memcpy::source#2 ← phi( main/(byte*) memcpy::source#0 main::@7/(byte*) memcpy::source#1 ) + (byte*) memcpy::src#0 ← (byte*) memcpy::source#2 + (byte*) memcpy::dst#0 ← (byte*) memcpy::destination#2 + (word) memcpy::i#0 ← (number) 0 + to:memcpy::@1 +memcpy::@1: scope:[memcpy] from memcpy memcpy::@1 + (byte*) memcpy::destination#4 ← phi( memcpy/(byte*) memcpy::destination#2 memcpy::@1/(byte*) memcpy::destination#4 ) + (word) memcpy::num#2 ← phi( memcpy/(word) memcpy::num#3 memcpy::@1/(word) memcpy::num#2 ) + (word) memcpy::i#2 ← phi( memcpy/(word) memcpy::i#0 memcpy::@1/(word) memcpy::i#1 ) + (byte*) memcpy::dst#2 ← phi( memcpy/(byte*) memcpy::dst#0 memcpy::@1/(byte*) memcpy::dst#1 ) + (byte*) memcpy::src#2 ← phi( memcpy/(byte*) memcpy::src#0 memcpy::@1/(byte*) memcpy::src#1 ) + *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) + (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 + (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 + (word) memcpy::i#1 ← ++ (word) memcpy::i#2 + (bool~) memcpy::$0 ← (word) memcpy::i#1 < (word) memcpy::num#2 + if((bool~) memcpy::$0) goto memcpy::@1 + to:memcpy::@2 +memcpy::@2: scope:[memcpy] from memcpy::@1 + (byte*) memcpy::destination#3 ← phi( memcpy::@1/(byte*) memcpy::destination#4 ) + (byte*) memcpy::return#0 ← (byte*) memcpy::destination#3 + to:memcpy::@return +memcpy::@return: scope:[memcpy] from memcpy::@2 + (byte*) memcpy::return#4 ← phi( memcpy::@2/(byte*) memcpy::return#0 ) + (byte*) memcpy::return#1 ← (byte*) memcpy::return#4 + return + to:@return +@7: scope:[] from @begin + (byte*) MEDUSA_SCREEN#0 ← ((byte*)) (number) $1000 + (byte*) MEDUSA_COLORS#0 ← ((byte*)) (number) $1400 + (byte*) SCREEN#0 ← ((byte*)) (number) $400 + kickasm(location (byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + }} + kickasm(location (byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + }} + to:@8 +main: scope:[main] from @8 + *((byte*) BGCOL#0) ← (byte) BLACK#0 + (byte*) memcpy::destination#0 ← (byte*) SCREEN#0 + (byte*) memcpy::source#0 ← (byte*) MEDUSA_SCREEN#0 + (word) memcpy::num#0 ← (number) $3e8 + call memcpy + (byte*) memcpy::return#2 ← (byte*) memcpy::return#1 + to:main::@7 +main::@7: scope:[main] from main + (byte*) memcpy::destination#1 ← (byte*) COLS#0 + (byte*) memcpy::source#1 ← (byte*) MEDUSA_COLORS#0 + (word) memcpy::num#1 ← (number) $3e8 + call memcpy + (byte*) memcpy::return#3 ← (byte*) memcpy::return#1 + to:main::@8 +main::@8: scope:[main] from main::@7 + to:main::@1 +main::@1: scope:[main] from main::@2 main::@8 + if(true) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (byte*~) main::$2 ← (byte*) SCREEN#0 + (number) $3e7 + *((byte*~) main::$2) ← *((byte*~) main::$2) ^ (number) $e + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return +@8: scope:[] from @7 + call main + to:@9 +@9: scope:[] from @8 + to:@end +@end: scope:[] from @9 + +SYMBOL TABLE SSA +(label) @7 +(label) @8 +(label) @9 +(label) @begin +(label) @end +(byte*) BGCOL +(byte*) BGCOL#0 +(byte) BLACK +(byte) BLACK#0 +(byte*) COLS +(byte*) COLS#0 +(byte*) MEDUSA_COLORS +(byte*) MEDUSA_COLORS#0 +(byte*) MEDUSA_SCREEN +(byte*) MEDUSA_SCREEN#0 +(byte*) SCREEN +(byte*) SCREEN#0 +(void()) main() +(byte*~) main::$2 +(label) main::@1 +(label) main::@2 +(label) main::@7 +(label) main::@8 +(label) main::@return +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(bool~) memcpy::$0 +(label) memcpy::@1 +(label) memcpy::@2 +(label) memcpy::@return +(byte*) memcpy::destination +(byte*) memcpy::destination#0 +(byte*) memcpy::destination#1 +(byte*) memcpy::destination#2 +(byte*) memcpy::destination#3 +(byte*) memcpy::destination#4 +(byte*) memcpy::dst +(byte*) memcpy::dst#0 +(byte*) memcpy::dst#1 +(byte*) memcpy::dst#2 +(word) memcpy::i +(word) memcpy::i#0 +(word) memcpy::i#1 +(word) memcpy::i#2 +(word) memcpy::num +(word) memcpy::num#0 +(word) memcpy::num#1 +(word) memcpy::num#2 +(word) memcpy::num#3 +(byte*) memcpy::return +(byte*) memcpy::return#0 +(byte*) memcpy::return#1 +(byte*) memcpy::return#2 +(byte*) memcpy::return#3 +(byte*) memcpy::return#4 +(byte*) memcpy::source +(byte*) memcpy::source#0 +(byte*) memcpy::source#1 +(byte*) memcpy::source#2 +(byte*) memcpy::src +(byte*) memcpy::src#0 +(byte*) memcpy::src#1 +(byte*) memcpy::src#2 + +Adding number conversion cast (unumber) 0 in (byte) BLACK#0 ← (number) 0 +Adding number conversion cast (unumber) 0 in (word) memcpy::i#0 ← (number) 0 +Adding number conversion cast (unumber) $3e8 in (word) memcpy::num#0 ← (number) $3e8 +Adding number conversion cast (unumber) $3e8 in (word) memcpy::num#1 ← (number) $3e8 +Adding number conversion cast (unumber) $3e7 in (byte*~) main::$2 ← (byte*) SCREEN#0 + (number) $3e7 +Adding number conversion cast (unumber) $e in *((byte*~) main::$2) ← *((byte*~) main::$2) ^ (number) $e +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) BGCOL#0 ← (byte*)(number) $d021 +Inlining cast (byte*) COLS#0 ← (byte*)(number) $d800 +Inlining cast (byte) BLACK#0 ← (unumber)(number) 0 +Inlining cast (word) memcpy::i#0 ← (unumber)(number) 0 +Inlining cast (byte*) MEDUSA_SCREEN#0 ← (byte*)(number) $1000 +Inlining cast (byte*) MEDUSA_COLORS#0 ← (byte*)(number) $1400 +Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 +Inlining cast (word) memcpy::num#0 ← (unumber)(number) $3e8 +Inlining cast (word) memcpy::num#1 ← (unumber)(number) $3e8 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 53281 +Simplifying constant pointer cast (byte*) 55296 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant pointer cast (byte*) 4096 +Simplifying constant pointer cast (byte*) 5120 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $3e8 +Simplifying constant integer cast $3e8 +Simplifying constant integer cast $3e7 +Simplifying constant integer cast $e +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (word) $3e8 +Finalized unsigned number type (word) $3e8 +Finalized unsigned number type (word) $3e7 +Finalized unsigned number type (byte) $e +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*) memcpy::src#0 = (byte*) memcpy::source#2 +Alias (byte*) memcpy::dst#0 = (byte*) memcpy::destination#2 +Alias (byte*) memcpy::return#0 = (byte*) memcpy::destination#3 (byte*) memcpy::destination#4 (byte*) memcpy::return#4 (byte*) memcpy::return#1 +Successful SSA optimization Pass2AliasElimination +Self Phi Eliminated (word) memcpy::num#2 +Self Phi Eliminated (byte*) memcpy::return#0 +Successful SSA optimization Pass2SelfPhiElimination +Identical Phi Values (word) memcpy::num#2 (word) memcpy::num#3 +Identical Phi Values (byte*) memcpy::return#0 (byte*) memcpy::dst#0 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) memcpy::$0 [13] if((word) memcpy::i#1<(word) memcpy::num#3) goto memcpy::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) BGCOL#0 = (byte*) 53281 +Constant (const byte*) COLS#0 = (byte*) 55296 +Constant (const byte) BLACK#0 = 0 +Constant (const word) memcpy::i#0 = 0 +Constant (const byte*) MEDUSA_SCREEN#0 = (byte*) 4096 +Constant (const byte*) MEDUSA_COLORS#0 = (byte*) 5120 +Constant (const byte*) SCREEN#0 = (byte*) 1024 +Constant (const word) memcpy::num#0 = $3e8 +Constant (const word) memcpy::num#1 = $3e8 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) memcpy::destination#0 = SCREEN#0 +Constant (const byte*) memcpy::source#0 = MEDUSA_SCREEN#0 +Constant (const byte*) memcpy::destination#1 = COLS#0 +Constant (const byte*) memcpy::source#1 = MEDUSA_COLORS#0 +Successful SSA optimization Pass2ConstantIdentification +if() condition always true - replacing block destination [35] if(true) goto main::@2 +Successful SSA optimization Pass2ConstantIfs +Eliminating unused variable (byte*) memcpy::return#2 and assignment [12] (byte*) memcpy::return#2 ← (byte*) memcpy::dst#0 +Eliminating unused variable (byte*) memcpy::return#3 and assignment [14] (byte*) memcpy::return#3 ← (byte*) memcpy::dst#0 +Successful SSA optimization PassNEliminateUnusedVars +Removing unused block main::@return +Successful SSA optimization Pass2EliminateUnusedBlocks +Constant right-side identified [13] (byte*~) main::$2 ← (const byte*) SCREEN#0 + (word) $3e7 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$2 = SCREEN#0+$3e7 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with var siblings (const word) memcpy::i#0 +Inlining constant with var siblings (const word) memcpy::num#0 +Inlining constant with var siblings (const word) memcpy::num#1 +Constant inlined memcpy::num#1 = (word) $3e8 +Constant inlined memcpy::num#0 = (word) $3e8 +Constant inlined memcpy::source#1 = (const byte*) MEDUSA_COLORS#0 +Constant inlined main::$2 = (const byte*) SCREEN#0+(word) $3e7 +Constant inlined memcpy::destination#0 = (const byte*) SCREEN#0 +Constant inlined memcpy::destination#1 = (const byte*) COLS#0 +Constant inlined memcpy::source#0 = (const byte*) MEDUSA_SCREEN#0 +Constant inlined memcpy::i#0 = (byte) 0 +Successful SSA optimization Pass2ConstantInlining +Identical Phi Values (word) memcpy::num#3 (word) $3e8 +Successful SSA optimization Pass2IdenticalPhiElimination +Added new block during phi lifting memcpy::@4(between memcpy::@1 and memcpy::@1) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @8 +Adding NOP phi() at start of @9 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main::@7 +Adding NOP phi() at start of main::@8 +Adding NOP phi() at start of main::@1 +Adding NOP phi() at start of memcpy::@2 +CALL GRAPH +Calls in [] to main:4 +Calls in [main] to memcpy:8 memcpy:10 + +Created 5 initial phi equivalence classes +Coalesced [15] memcpy::src#3 ← memcpy::src#0 +Coalesced [16] memcpy::dst#3 ← memcpy::dst#0 +Coalesced [25] memcpy::src#4 ← memcpy::src#1 +Coalesced [26] memcpy::dst#4 ← memcpy::dst#1 +Coalesced [27] memcpy::i#3 ← memcpy::i#1 +Coalesced down to 3 phi equivalence classes +Culled Empty Block (label) @9 +Culled Empty Block (label) main::@8 +Culled Empty Block (label) main::@1 +Culled Empty Block (label) memcpy::@2 +Culled Empty Block (label) memcpy::@4 +Renumbering block @7 to @1 +Renumbering block @8 to @2 +Renumbering block main::@2 to main::@1 +Renumbering block main::@7 to main::@2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main::@2 + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + }} + kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + }} + to:@2 +@2: scope:[] from @1 + [3] phi() + [4] call main + to:@end +@end: scope:[] from @2 + [5] phi() +main: scope:[main] from @2 + [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 + [7] call memcpy + to:main::@2 +main::@2: scope:[main] from main + [8] phi() + [9] call memcpy + to:main::@1 +main::@1: scope:[main] from main::@1 main::@2 + [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e + to:main::@1 +memcpy: scope:[memcpy] from main main::@2 + [11] (byte*) memcpy::dst#0 ← phi( main/(const byte*) SCREEN#0 main::@2/(const byte*) COLS#0 ) + [11] (byte*) memcpy::src#0 ← phi( main/(const byte*) MEDUSA_SCREEN#0 main::@2/(const byte*) MEDUSA_COLORS#0 ) + to:memcpy::@1 +memcpy::@1: scope:[memcpy] from memcpy memcpy::@1 + [12] (word) memcpy::i#2 ← phi( memcpy/(byte) 0 memcpy::@1/(word) memcpy::i#1 ) + [12] (byte*) memcpy::dst#2 ← phi( memcpy/(byte*) memcpy::dst#0 memcpy::@1/(byte*) memcpy::dst#1 ) + [12] (byte*) memcpy::src#2 ← phi( memcpy/(byte*) memcpy::src#0 memcpy::@1/(byte*) memcpy::src#1 ) + [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) + [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 + [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 + [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 + [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 + to:memcpy::@return +memcpy::@return: scope:[memcpy] from memcpy::@1 + [18] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte*) BGCOL +(byte) BLACK +(byte*) COLS +(byte*) MEDUSA_COLORS +(byte*) MEDUSA_SCREEN +(byte*) SCREEN +(void()) main() +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(byte*) memcpy::destination +(byte*) memcpy::dst +(byte*) memcpy::dst#0 2.0 +(byte*) memcpy::dst#1 5.5 +(byte*) memcpy::dst#2 17.5 +(word) memcpy::i +(word) memcpy::i#1 16.5 +(word) memcpy::i#2 5.5 +(word) memcpy::num +(byte*) memcpy::return +(byte*) memcpy::source +(byte*) memcpy::src +(byte*) memcpy::src#0 2.0 +(byte*) memcpy::src#1 7.333333333333333 +(byte*) memcpy::src#2 11.666666666666666 + +Initial phi equivalence classes +[ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +[ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +[ memcpy::i#2 memcpy::i#1 ] +Complete equivalence classes +[ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +[ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +[ memcpy::i#2 memcpy::i#1 ] +Allocated zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +Allocated zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +Allocated zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] + +INITIAL ASM +//SEG0 File Comments +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +//SEG3 @begin +bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) .fill fileScreen.getSize(), fileScreen.get(i) }} +//SEG6 kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) .fill fileCols.getSize(), fileCols.get(i) }} +//SEG7 [3] phi from @1 to @2 [phi:@1->@2] +b2_from_b1: + jmp b2 +//SEG8 @2 +b2: +//SEG9 [4] call main + jsr main +//SEG10 [5] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG11 @end +bend: +//SEG12 main +main: { + //SEG13 [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG14 [7] call memcpy + //SEG15 [11] phi from main to memcpy [phi:main->memcpy] + memcpy_from_main: + //SEG16 [11] phi (byte*) memcpy::dst#0 = (const byte*) SCREEN#0 [phi:main->memcpy#0] -- pbuz1=pbuc1 + lda #SCREEN + sta memcpy.dst+1 + //SEG17 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_SCREEN#0 [phi:main->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + //SEG18 [8] phi from main to main::@2 [phi:main->main::@2] + b2_from_main: + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [9] call memcpy + //SEG21 [11] phi from main::@2 to memcpy [phi:main::@2->memcpy] + memcpy_from_b2: + //SEG22 [11] phi (byte*) memcpy::dst#0 = (const byte*) COLS#0 [phi:main::@2->memcpy#0] -- pbuz1=pbuc1 + lda #COLS + sta memcpy.dst+1 + //SEG23 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_COLORS#0 [phi:main::@2->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + jmp b1 + //SEG24 main::@1 + b1: + //SEG25 [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e -- _deref_pbuc1=_deref_pbuc1_bxor_vbuc2 + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +//SEG26 memcpy +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + //SEG27 [12] phi from memcpy to memcpy::@1 [phi:memcpy->memcpy::@1] + b1_from_memcpy: + //SEG28 [12] phi (word) memcpy::i#2 = (byte) 0 [phi:memcpy->memcpy::@1#0] -- vwuz1=vbuc1 + lda #0 + sta i + lda #0 + sta i+1 + //SEG29 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#0 [phi:memcpy->memcpy::@1#1] -- register_copy + //SEG30 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#0 [phi:memcpy->memcpy::@1#2] -- register_copy + jmp b1 + //SEG31 [12] phi from memcpy::@1 to memcpy::@1 [phi:memcpy::@1->memcpy::@1] + b1_from_b1: + //SEG32 [12] phi (word) memcpy::i#2 = (word) memcpy::i#1 [phi:memcpy::@1->memcpy::@1#0] -- register_copy + //SEG33 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#1 [phi:memcpy::@1->memcpy::@1#1] -- register_copy + //SEG34 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#1 [phi:memcpy::@1->memcpy::@1#2] -- register_copy + jmp b1 + //SEG35 memcpy::@1 + b1: + //SEG36 [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (src),y + ldy #0 + sta (dst),y + //SEG37 [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 -- pbuz1=_inc_pbuz1 + inc dst + bne !+ + inc dst+1 + !: + //SEG38 [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 -- pbuz1=_inc_pbuz1 + inc src + bne !+ + inc src+1 + !: + //SEG39 [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 -- vwuz1=_inc_vwuz1 + inc i + bne !+ + inc i+1 + !: + //SEG40 [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 -- vwuz1_lt_vwuc1_then_la1 + lda i+1 + cmp #>$3e8 + bcc b1_from_b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1_from_b1 + !: + jmp breturn + //SEG41 memcpy::@return + breturn: + //SEG42 [18] return + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( main:4 [ ] ) always clobbers reg byte a +Statement [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e [ ] ( main:4 [ ] ) always clobbers reg byte a +Statement [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) [ memcpy::src#2 memcpy::dst#2 memcpy::i#2 ] ( main:4::memcpy:7 [ memcpy::src#2 memcpy::dst#2 memcpy::i#2 ] main:4::memcpy:9 [ memcpy::src#2 memcpy::dst#2 memcpy::i#2 ] ) always clobbers reg byte a reg byte y +Statement [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 [ memcpy::src#1 memcpy::dst#1 memcpy::i#1 ] ( main:4::memcpy:7 [ memcpy::src#1 memcpy::dst#1 memcpy::i#1 ] main:4::memcpy:9 [ memcpy::src#1 memcpy::dst#1 memcpy::i#1 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] : zp ZP_WORD:4 , +Potential registers zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] : zp ZP_WORD:6 , + +REGISTER UPLIFT SCOPES +Uplift Scope [memcpy] 25: zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] 22: zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] 21: zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [memcpy] best 1649 combination zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +Uplifting [main] best 1649 combination +Uplifting [] best 1649 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +//SEG3 @begin +bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) .fill fileScreen.getSize(), fileScreen.get(i) }} +//SEG6 kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) .fill fileCols.getSize(), fileCols.get(i) }} +//SEG7 [3] phi from @1 to @2 [phi:@1->@2] +b2_from_b1: + jmp b2 +//SEG8 @2 +b2: +//SEG9 [4] call main + jsr main +//SEG10 [5] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG11 @end +bend: +//SEG12 main +main: { + //SEG13 [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG14 [7] call memcpy + //SEG15 [11] phi from main to memcpy [phi:main->memcpy] + memcpy_from_main: + //SEG16 [11] phi (byte*) memcpy::dst#0 = (const byte*) SCREEN#0 [phi:main->memcpy#0] -- pbuz1=pbuc1 + lda #SCREEN + sta memcpy.dst+1 + //SEG17 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_SCREEN#0 [phi:main->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + //SEG18 [8] phi from main to main::@2 [phi:main->main::@2] + b2_from_main: + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [9] call memcpy + //SEG21 [11] phi from main::@2 to memcpy [phi:main::@2->memcpy] + memcpy_from_b2: + //SEG22 [11] phi (byte*) memcpy::dst#0 = (const byte*) COLS#0 [phi:main::@2->memcpy#0] -- pbuz1=pbuc1 + lda #COLS + sta memcpy.dst+1 + //SEG23 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_COLORS#0 [phi:main::@2->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + jmp b1 + //SEG24 main::@1 + b1: + //SEG25 [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e -- _deref_pbuc1=_deref_pbuc1_bxor_vbuc2 + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +//SEG26 memcpy +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + //SEG27 [12] phi from memcpy to memcpy::@1 [phi:memcpy->memcpy::@1] + b1_from_memcpy: + //SEG28 [12] phi (word) memcpy::i#2 = (byte) 0 [phi:memcpy->memcpy::@1#0] -- vwuz1=vbuc1 + lda #0 + sta i + lda #0 + sta i+1 + //SEG29 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#0 [phi:memcpy->memcpy::@1#1] -- register_copy + //SEG30 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#0 [phi:memcpy->memcpy::@1#2] -- register_copy + jmp b1 + //SEG31 [12] phi from memcpy::@1 to memcpy::@1 [phi:memcpy::@1->memcpy::@1] + b1_from_b1: + //SEG32 [12] phi (word) memcpy::i#2 = (word) memcpy::i#1 [phi:memcpy::@1->memcpy::@1#0] -- register_copy + //SEG33 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#1 [phi:memcpy::@1->memcpy::@1#1] -- register_copy + //SEG34 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#1 [phi:memcpy::@1->memcpy::@1#2] -- register_copy + jmp b1 + //SEG35 memcpy::@1 + b1: + //SEG36 [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (src),y + ldy #0 + sta (dst),y + //SEG37 [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 -- pbuz1=_inc_pbuz1 + inc dst + bne !+ + inc dst+1 + !: + //SEG38 [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 -- pbuz1=_inc_pbuz1 + inc src + bne !+ + inc src+1 + !: + //SEG39 [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 -- vwuz1=_inc_vwuz1 + inc i + bne !+ + inc i+1 + !: + //SEG40 [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 -- vwuz1_lt_vwuc1_then_la1 + lda i+1 + cmp #>$3e8 + bcc b1_from_b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1_from_b1 + !: + jmp breturn + //SEG41 memcpy::@return + breturn: + //SEG42 [18] return + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp b2 +Removing instruction jmp b1 +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #0 +Removing instruction ldy #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Replacing label b1_from_b1 with b1 +Replacing label b1_from_b1 with b1 +Removing instruction b1: +Removing instruction b2_from_b1: +Removing instruction b2: +Removing instruction bend_from_b2: +Removing instruction b2_from_main: +Removing instruction memcpy_from_b2: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction memcpy_from_main: +Removing instruction b2: +Removing instruction b1_from_memcpy: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = (byte*) 53281 +(byte) BLACK +(const byte) BLACK#0 BLACK = (byte) 0 +(byte*) COLS +(const byte*) COLS#0 COLS = (byte*) 55296 +(byte*) MEDUSA_COLORS +(const byte*) MEDUSA_COLORS#0 MEDUSA_COLORS = (byte*) 5120 +(byte*) MEDUSA_SCREEN +(const byte*) MEDUSA_SCREEN#0 MEDUSA_SCREEN = (byte*) 4096 +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(void()) main() +(label) main::@1 +(label) main::@2 +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(label) memcpy::@1 +(label) memcpy::@return +(byte*) memcpy::destination +(byte*) memcpy::dst +(byte*) memcpy::dst#0 dst zp ZP_WORD:4 2.0 +(byte*) memcpy::dst#1 dst zp ZP_WORD:4 5.5 +(byte*) memcpy::dst#2 dst zp ZP_WORD:4 17.5 +(word) memcpy::i +(word) memcpy::i#1 i zp ZP_WORD:6 16.5 +(word) memcpy::i#2 i zp ZP_WORD:6 5.5 +(word) memcpy::num +(byte*) memcpy::return +(byte*) memcpy::source +(byte*) memcpy::src +(byte*) memcpy::src#0 src zp ZP_WORD:2 2.0 +(byte*) memcpy::src#1 src zp ZP_WORD:2 7.333333333333333 +(byte*) memcpy::src#2 src zp ZP_WORD:2 11.666666666666666 + +zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] + + +FINAL ASSEMBLER +Score: 1471 + +//SEG0 File Comments +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +//SEG3 @begin +//SEG4 @1 +//SEG5 kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) .fill fileScreen.getSize(), fileScreen.get(i) }} +//SEG6 kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) .fill fileCols.getSize(), fileCols.get(i) }} +//SEG7 [3] phi from @1 to @2 [phi:@1->@2] +//SEG8 @2 +//SEG9 [4] call main +//SEG10 [5] phi from @2 to @end [phi:@2->@end] +//SEG11 @end +//SEG12 main +main: { + //SEG13 [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG14 [7] call memcpy + //SEG15 [11] phi from main to memcpy [phi:main->memcpy] + //SEG16 [11] phi (byte*) memcpy::dst#0 = (const byte*) SCREEN#0 [phi:main->memcpy#0] -- pbuz1=pbuc1 + lda #SCREEN + sta memcpy.dst+1 + //SEG17 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_SCREEN#0 [phi:main->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + //SEG18 [8] phi from main to main::@2 [phi:main->main::@2] + //SEG19 main::@2 + //SEG20 [9] call memcpy + //SEG21 [11] phi from main::@2 to memcpy [phi:main::@2->memcpy] + //SEG22 [11] phi (byte*) memcpy::dst#0 = (const byte*) COLS#0 [phi:main::@2->memcpy#0] -- pbuz1=pbuc1 + lda #COLS + sta memcpy.dst+1 + //SEG23 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_COLORS#0 [phi:main::@2->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + //SEG24 main::@1 + b1: + //SEG25 [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e -- _deref_pbuc1=_deref_pbuc1_bxor_vbuc2 + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +//SEG26 memcpy +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + //SEG27 [12] phi from memcpy to memcpy::@1 [phi:memcpy->memcpy::@1] + //SEG28 [12] phi (word) memcpy::i#2 = (byte) 0 [phi:memcpy->memcpy::@1#0] -- vwuz1=vbuc1 + lda #0 + sta i + sta i+1 + //SEG29 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#0 [phi:memcpy->memcpy::@1#1] -- register_copy + //SEG30 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#0 [phi:memcpy->memcpy::@1#2] -- register_copy + //SEG31 [12] phi from memcpy::@1 to memcpy::@1 [phi:memcpy::@1->memcpy::@1] + //SEG32 [12] phi (word) memcpy::i#2 = (word) memcpy::i#1 [phi:memcpy::@1->memcpy::@1#0] -- register_copy + //SEG33 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#1 [phi:memcpy::@1->memcpy::@1#1] -- register_copy + //SEG34 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#1 [phi:memcpy::@1->memcpy::@1#2] -- register_copy + //SEG35 memcpy::@1 + b1: + //SEG36 [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (src),y + sta (dst),y + //SEG37 [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 -- pbuz1=_inc_pbuz1 + inc dst + bne !+ + inc dst+1 + !: + //SEG38 [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 -- pbuz1=_inc_pbuz1 + inc src + bne !+ + inc src+1 + !: + //SEG39 [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 -- vwuz1=_inc_vwuz1 + inc i + bne !+ + inc i+1 + !: + //SEG40 [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 -- vwuz1_lt_vwuc1_then_la1 + lda i+1 + cmp #>$3e8 + bcc b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1 + !: + //SEG41 memcpy::@return + //SEG42 [18] return + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + + diff --git a/src/test/ref/complex/medusa/medusa.sym b/src/test/ref/complex/medusa/medusa.sym new file mode 100644 index 000000000..aecc6c6fd --- /dev/null +++ b/src/test/ref/complex/medusa/medusa.sym @@ -0,0 +1,41 @@ +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = (byte*) 53281 +(byte) BLACK +(const byte) BLACK#0 BLACK = (byte) 0 +(byte*) COLS +(const byte*) COLS#0 COLS = (byte*) 55296 +(byte*) MEDUSA_COLORS +(const byte*) MEDUSA_COLORS#0 MEDUSA_COLORS = (byte*) 5120 +(byte*) MEDUSA_SCREEN +(const byte*) MEDUSA_SCREEN#0 MEDUSA_SCREEN = (byte*) 4096 +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(void()) main() +(label) main::@1 +(label) main::@2 +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(label) memcpy::@1 +(label) memcpy::@return +(byte*) memcpy::destination +(byte*) memcpy::dst +(byte*) memcpy::dst#0 dst zp ZP_WORD:4 2.0 +(byte*) memcpy::dst#1 dst zp ZP_WORD:4 5.5 +(byte*) memcpy::dst#2 dst zp ZP_WORD:4 17.5 +(word) memcpy::i +(word) memcpy::i#1 i zp ZP_WORD:6 16.5 +(word) memcpy::i#2 i zp ZP_WORD:6 5.5 +(word) memcpy::num +(byte*) memcpy::return +(byte*) memcpy::source +(byte*) memcpy::src +(byte*) memcpy::src#0 src zp ZP_WORD:2 2.0 +(byte*) memcpy::src#1 src zp ZP_WORD:2 7.333333333333333 +(byte*) memcpy::src#2 src zp ZP_WORD:2 11.666666666666666 + +zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] diff --git a/src/test/ref/medusa.asm b/src/test/ref/medusa.asm new file mode 100644 index 000000000..80f177080 --- /dev/null +++ b/src/test/ref/medusa.asm @@ -0,0 +1,83 @@ +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +main: { + lda #BLACK + sta BGCOL + lda #SCREEN + sta memcpy.dst+1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + lda #COLS + sta memcpy.dst+1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + b1: + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + lda #0 + sta i + sta i+1 + b1: + ldy #0 + lda (src),y + sta (dst),y + inc dst + bne !+ + inc dst+1 + !: + inc src + bne !+ + inc src+1 + !: + inc i + bne !+ + inc i+1 + !: + lda i+1 + cmp #>$3e8 + bcc b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1 + !: + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + diff --git a/src/test/ref/medusa.cfg b/src/test/ref/medusa.cfg new file mode 100644 index 000000000..4fad14769 --- /dev/null +++ b/src/test/ref/medusa.cfg @@ -0,0 +1,45 @@ +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + }} + kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + }} + to:@2 +@2: scope:[] from @1 + [3] phi() + [4] call main + to:@end +@end: scope:[] from @2 + [5] phi() +main: scope:[main] from @2 + [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 + [7] call memcpy + to:main::@2 +main::@2: scope:[main] from main + [8] phi() + [9] call memcpy + to:main::@1 +main::@1: scope:[main] from main::@1 main::@2 + [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e + to:main::@1 +memcpy: scope:[memcpy] from main main::@2 + [11] (byte*) memcpy::dst#0 ← phi( main/(const byte*) SCREEN#0 main::@2/(const byte*) COLS#0 ) + [11] (byte*) memcpy::src#0 ← phi( main/(const byte*) MEDUSA_SCREEN#0 main::@2/(const byte*) MEDUSA_COLORS#0 ) + to:memcpy::@1 +memcpy::@1: scope:[memcpy] from memcpy memcpy::@1 + [12] (word) memcpy::i#2 ← phi( memcpy/(byte) 0 memcpy::@1/(word) memcpy::i#1 ) + [12] (byte*) memcpy::dst#2 ← phi( memcpy/(byte*) memcpy::dst#0 memcpy::@1/(byte*) memcpy::dst#1 ) + [12] (byte*) memcpy::src#2 ← phi( memcpy/(byte*) memcpy::src#0 memcpy::@1/(byte*) memcpy::src#1 ) + [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) + [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 + [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 + [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 + [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 + to:memcpy::@return +memcpy::@return: scope:[memcpy] from memcpy::@1 + [18] return + to:@return diff --git a/src/test/ref/medusa.log b/src/test/ref/medusa.log new file mode 100644 index 000000000..1fc152fab --- /dev/null +++ b/src/test/ref/medusa.log @@ -0,0 +1,948 @@ +Warning! Adding boolean cast to non-boolean condition *((byte*) strcpy::src) +Adding pointer type conversion cast (byte*) PROCPORT_DDR in (byte*) PROCPORT_DDR ← (number) 0 +Adding pointer type conversion cast (byte*) PROCPORT in (byte*) PROCPORT ← (number) 1 +Adding pointer type conversion cast (byte*) CHARGEN in (byte*) CHARGEN ← (number) $d000 +Adding pointer type conversion cast (byte*) SPRITES_XPOS in (byte*) SPRITES_XPOS ← (number) $d000 +Adding pointer type conversion cast (byte*) SPRITES_YPOS in (byte*) SPRITES_YPOS ← (number) $d001 +Adding pointer type conversion cast (byte*) SPRITES_XMSB in (byte*) SPRITES_XMSB ← (number) $d010 +Adding pointer type conversion cast (byte*) RASTER in (byte*) RASTER ← (number) $d012 +Adding pointer type conversion cast (byte*) SPRITES_ENABLE in (byte*) SPRITES_ENABLE ← (number) $d015 +Adding pointer type conversion cast (byte*) SPRITES_EXPAND_Y in (byte*) SPRITES_EXPAND_Y ← (number) $d017 +Adding pointer type conversion cast (byte*) SPRITES_PRIORITY in (byte*) SPRITES_PRIORITY ← (number) $d01b +Adding pointer type conversion cast (byte*) SPRITES_MC in (byte*) SPRITES_MC ← (number) $d01c +Adding pointer type conversion cast (byte*) SPRITES_EXPAND_X in (byte*) SPRITES_EXPAND_X ← (number) $d01d +Adding pointer type conversion cast (byte*) BORDERCOL in (byte*) BORDERCOL ← (number) $d020 +Adding pointer type conversion cast (byte*) BGCOL in (byte*) BGCOL ← (number) $d021 +Adding pointer type conversion cast (byte*) BGCOL1 in (byte*) BGCOL1 ← (number) $d021 +Adding pointer type conversion cast (byte*) BGCOL2 in (byte*) BGCOL2 ← (number) $d022 +Adding pointer type conversion cast (byte*) BGCOL3 in (byte*) BGCOL3 ← (number) $d023 +Adding pointer type conversion cast (byte*) BGCOL4 in (byte*) BGCOL4 ← (number) $d024 +Adding pointer type conversion cast (byte*) SPRITES_MC1 in (byte*) SPRITES_MC1 ← (number) $d025 +Adding pointer type conversion cast (byte*) SPRITES_MC2 in (byte*) SPRITES_MC2 ← (number) $d026 +Adding pointer type conversion cast (byte*) SPRITES_COLS in (byte*) SPRITES_COLS ← (number) $d027 +Adding pointer type conversion cast (byte*) VIC_CONTROL in (byte*) VIC_CONTROL ← (number) $d011 +Adding pointer type conversion cast (byte*) D011 in (byte*) D011 ← (number) $d011 +Adding pointer type conversion cast (byte*) VIC_CONTROL2 in (byte*) VIC_CONTROL2 ← (number) $d016 +Adding pointer type conversion cast (byte*) D016 in (byte*) D016 ← (number) $d016 +Adding pointer type conversion cast (byte*) D018 in (byte*) D018 ← (number) $d018 +Adding pointer type conversion cast (byte*) VIC_MEMORY in (byte*) VIC_MEMORY ← (number) $d018 +Adding pointer type conversion cast (byte*) LIGHTPEN_X in (byte*) LIGHTPEN_X ← (number) $d013 +Adding pointer type conversion cast (byte*) LIGHTPEN_Y in (byte*) LIGHTPEN_Y ← (number) $d014 +Adding pointer type conversion cast (byte*) IRQ_STATUS in (byte*) IRQ_STATUS ← (number) $d019 +Adding pointer type conversion cast (byte*) IRQ_ENABLE in (byte*) IRQ_ENABLE ← (number) $d01a +Adding pointer type conversion cast (byte*) COLS in (byte*) COLS ← (number) $d800 +Adding pointer type conversion cast (byte*) CIA1_PORT_A in (byte*) CIA1_PORT_A ← (number) $dc00 +Adding pointer type conversion cast (byte*) CIA1_PORT_B in (byte*) CIA1_PORT_B ← (number) $dc01 +Adding pointer type conversion cast (byte*) CIA1_PORT_A_DDR in (byte*) CIA1_PORT_A_DDR ← (number) $dc02 +Adding pointer type conversion cast (byte*) CIA1_PORT_B_DDR in (byte*) CIA1_PORT_B_DDR ← (number) $dc03 +Adding pointer type conversion cast (byte*) CIA1_INTERRUPT in (byte*) CIA1_INTERRUPT ← (number) $dc0d +Adding pointer type conversion cast (byte*) CIA2_PORT_A in (byte*) CIA2_PORT_A ← (number) $dd00 +Adding pointer type conversion cast (byte*) CIA2_PORT_B in (byte*) CIA2_PORT_B ← (number) $dd01 +Adding pointer type conversion cast (byte*) CIA2_PORT_A_DDR in (byte*) CIA2_PORT_A_DDR ← (number) $dd02 +Adding pointer type conversion cast (byte*) CIA2_PORT_B_DDR in (byte*) CIA2_PORT_B_DDR ← (number) $dd03 +Adding pointer type conversion cast (byte*) CIA2_INTERRUPT in (byte*) CIA2_INTERRUPT ← (number) $dd0d +Adding pointer type conversion cast (void()**) KERNEL_IRQ in (void()**) KERNEL_IRQ ← (number) $314 +Adding pointer type conversion cast (void()**) HARDWARE_IRQ in (void()**) HARDWARE_IRQ ← (number) $fffe +Adding pointer type conversion cast (byte*) MEDUSA_SCREEN in (byte*) MEDUSA_SCREEN ← (number) $1000 +Adding pointer type conversion cast (byte*) MEDUSA_COLORS in (byte*) MEDUSA_COLORS ← (number) $1400 +Adding pointer type conversion cast (byte*) SCREEN in (byte*) SCREEN ← (number) $400 +Identified constant variable (byte*) MEDUSA_SCREEN +Identified constant variable (byte*) MEDUSA_COLORS +Identified constant variable (byte*) SCREEN +Inlined call (byte~) vicSelectGfxBank::$0 ← call toDd00 (byte*) vicSelectGfxBank::gfx +Culled Empty Block (label) @1 +Culled Empty Block (label) @2 +Culled Empty Block (label) @3 +Culled Empty Block (label) @4 +Culled Empty Block (label) memcpy::@3 +Culled Empty Block (label) @5 +Culled Empty Block (label) @6 +Culled Empty Block (label) main::@4 +Culled Empty Block (label) main::@3 +Culled Empty Block (label) main::@5 +Culled Empty Block (label) main::@6 + +CONTROL FLOW GRAPH SSA +@begin: scope:[] from + (byte*) BGCOL#0 ← ((byte*)) (number) $d021 + (byte*) COLS#0 ← ((byte*)) (number) $d800 + (byte) BLACK#0 ← (number) 0 + to:@7 +memcpy: scope:[memcpy] from main main::@7 + (word) memcpy::num#3 ← phi( main/(word) memcpy::num#0 main::@7/(word) memcpy::num#1 ) + (byte*) memcpy::destination#2 ← phi( main/(byte*) memcpy::destination#0 main::@7/(byte*) memcpy::destination#1 ) + (byte*) memcpy::source#2 ← phi( main/(byte*) memcpy::source#0 main::@7/(byte*) memcpy::source#1 ) + (byte*) memcpy::src#0 ← (byte*) memcpy::source#2 + (byte*) memcpy::dst#0 ← (byte*) memcpy::destination#2 + (word) memcpy::i#0 ← (number) 0 + to:memcpy::@1 +memcpy::@1: scope:[memcpy] from memcpy memcpy::@1 + (byte*) memcpy::destination#4 ← phi( memcpy/(byte*) memcpy::destination#2 memcpy::@1/(byte*) memcpy::destination#4 ) + (word) memcpy::num#2 ← phi( memcpy/(word) memcpy::num#3 memcpy::@1/(word) memcpy::num#2 ) + (word) memcpy::i#2 ← phi( memcpy/(word) memcpy::i#0 memcpy::@1/(word) memcpy::i#1 ) + (byte*) memcpy::dst#2 ← phi( memcpy/(byte*) memcpy::dst#0 memcpy::@1/(byte*) memcpy::dst#1 ) + (byte*) memcpy::src#2 ← phi( memcpy/(byte*) memcpy::src#0 memcpy::@1/(byte*) memcpy::src#1 ) + *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) + (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 + (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 + (word) memcpy::i#1 ← ++ (word) memcpy::i#2 + (bool~) memcpy::$0 ← (word) memcpy::i#1 < (word) memcpy::num#2 + if((bool~) memcpy::$0) goto memcpy::@1 + to:memcpy::@2 +memcpy::@2: scope:[memcpy] from memcpy::@1 + (byte*) memcpy::destination#3 ← phi( memcpy::@1/(byte*) memcpy::destination#4 ) + (byte*) memcpy::return#0 ← (byte*) memcpy::destination#3 + to:memcpy::@return +memcpy::@return: scope:[memcpy] from memcpy::@2 + (byte*) memcpy::return#4 ← phi( memcpy::@2/(byte*) memcpy::return#0 ) + (byte*) memcpy::return#1 ← (byte*) memcpy::return#4 + return + to:@return +@7: scope:[] from @begin + (byte*) MEDUSA_SCREEN#0 ← ((byte*)) (number) $1000 + (byte*) MEDUSA_COLORS#0 ← ((byte*)) (number) $1400 + (byte*) SCREEN#0 ← ((byte*)) (number) $400 + kickasm(location (byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + }} + kickasm(location (byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + }} + to:@8 +main: scope:[main] from @8 + *((byte*) BGCOL#0) ← (byte) BLACK#0 + (byte*) memcpy::destination#0 ← (byte*) SCREEN#0 + (byte*) memcpy::source#0 ← (byte*) MEDUSA_SCREEN#0 + (word) memcpy::num#0 ← (number) $3e8 + call memcpy + (byte*) memcpy::return#2 ← (byte*) memcpy::return#1 + to:main::@7 +main::@7: scope:[main] from main + (byte*) memcpy::destination#1 ← (byte*) COLS#0 + (byte*) memcpy::source#1 ← (byte*) MEDUSA_COLORS#0 + (word) memcpy::num#1 ← (number) $3e8 + call memcpy + (byte*) memcpy::return#3 ← (byte*) memcpy::return#1 + to:main::@8 +main::@8: scope:[main] from main::@7 + to:main::@1 +main::@1: scope:[main] from main::@2 main::@8 + if(true) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + (byte*~) main::$2 ← (byte*) SCREEN#0 + (number) $3e7 + *((byte*~) main::$2) ← *((byte*~) main::$2) ^ (number) $e + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return +@8: scope:[] from @7 + call main + to:@9 +@9: scope:[] from @8 + to:@end +@end: scope:[] from @9 + +SYMBOL TABLE SSA +(label) @7 +(label) @8 +(label) @9 +(label) @begin +(label) @end +(byte*) BGCOL +(byte*) BGCOL#0 +(byte) BLACK +(byte) BLACK#0 +(byte*) COLS +(byte*) COLS#0 +(byte*) MEDUSA_COLORS +(byte*) MEDUSA_COLORS#0 +(byte*) MEDUSA_SCREEN +(byte*) MEDUSA_SCREEN#0 +(byte*) SCREEN +(byte*) SCREEN#0 +(void()) main() +(byte*~) main::$2 +(label) main::@1 +(label) main::@2 +(label) main::@7 +(label) main::@8 +(label) main::@return +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(bool~) memcpy::$0 +(label) memcpy::@1 +(label) memcpy::@2 +(label) memcpy::@return +(byte*) memcpy::destination +(byte*) memcpy::destination#0 +(byte*) memcpy::destination#1 +(byte*) memcpy::destination#2 +(byte*) memcpy::destination#3 +(byte*) memcpy::destination#4 +(byte*) memcpy::dst +(byte*) memcpy::dst#0 +(byte*) memcpy::dst#1 +(byte*) memcpy::dst#2 +(word) memcpy::i +(word) memcpy::i#0 +(word) memcpy::i#1 +(word) memcpy::i#2 +(word) memcpy::num +(word) memcpy::num#0 +(word) memcpy::num#1 +(word) memcpy::num#2 +(word) memcpy::num#3 +(byte*) memcpy::return +(byte*) memcpy::return#0 +(byte*) memcpy::return#1 +(byte*) memcpy::return#2 +(byte*) memcpy::return#3 +(byte*) memcpy::return#4 +(byte*) memcpy::source +(byte*) memcpy::source#0 +(byte*) memcpy::source#1 +(byte*) memcpy::source#2 +(byte*) memcpy::src +(byte*) memcpy::src#0 +(byte*) memcpy::src#1 +(byte*) memcpy::src#2 + +Adding number conversion cast (unumber) 0 in (byte) BLACK#0 ← (number) 0 +Adding number conversion cast (unumber) 0 in (word) memcpy::i#0 ← (number) 0 +Adding number conversion cast (unumber) $3e8 in (word) memcpy::num#0 ← (number) $3e8 +Adding number conversion cast (unumber) $3e8 in (word) memcpy::num#1 ← (number) $3e8 +Adding number conversion cast (unumber) $3e7 in (byte*~) main::$2 ← (byte*) SCREEN#0 + (number) $3e7 +Adding number conversion cast (unumber) $e in *((byte*~) main::$2) ← *((byte*~) main::$2) ^ (number) $e +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast (byte*) BGCOL#0 ← (byte*)(number) $d021 +Inlining cast (byte*) COLS#0 ← (byte*)(number) $d800 +Inlining cast (byte) BLACK#0 ← (unumber)(number) 0 +Inlining cast (word) memcpy::i#0 ← (unumber)(number) 0 +Inlining cast (byte*) MEDUSA_SCREEN#0 ← (byte*)(number) $1000 +Inlining cast (byte*) MEDUSA_COLORS#0 ← (byte*)(number) $1400 +Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 +Inlining cast (word) memcpy::num#0 ← (unumber)(number) $3e8 +Inlining cast (word) memcpy::num#1 ← (unumber)(number) $3e8 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 53281 +Simplifying constant pointer cast (byte*) 55296 +Simplifying constant integer cast 0 +Simplifying constant integer cast 0 +Simplifying constant pointer cast (byte*) 4096 +Simplifying constant pointer cast (byte*) 5120 +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast $3e8 +Simplifying constant integer cast $3e8 +Simplifying constant integer cast $3e7 +Simplifying constant integer cast $e +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (byte) 0 +Finalized unsigned number type (word) $3e8 +Finalized unsigned number type (word) $3e8 +Finalized unsigned number type (word) $3e7 +Finalized unsigned number type (byte) $e +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias (byte*) memcpy::src#0 = (byte*) memcpy::source#2 +Alias (byte*) memcpy::dst#0 = (byte*) memcpy::destination#2 +Alias (byte*) memcpy::return#0 = (byte*) memcpy::destination#3 (byte*) memcpy::destination#4 (byte*) memcpy::return#4 (byte*) memcpy::return#1 +Successful SSA optimization Pass2AliasElimination +Self Phi Eliminated (word) memcpy::num#2 +Self Phi Eliminated (byte*) memcpy::return#0 +Successful SSA optimization Pass2SelfPhiElimination +Identical Phi Values (word) memcpy::num#2 (word) memcpy::num#3 +Identical Phi Values (byte*) memcpy::return#0 (byte*) memcpy::dst#0 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition (bool~) memcpy::$0 [13] if((word) memcpy::i#1<(word) memcpy::num#3) goto memcpy::@1 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant (const byte*) BGCOL#0 = (byte*) 53281 +Constant (const byte*) COLS#0 = (byte*) 55296 +Constant (const byte) BLACK#0 = 0 +Constant (const word) memcpy::i#0 = 0 +Constant (const byte*) MEDUSA_SCREEN#0 = (byte*) 4096 +Constant (const byte*) MEDUSA_COLORS#0 = (byte*) 5120 +Constant (const byte*) SCREEN#0 = (byte*) 1024 +Constant (const word) memcpy::num#0 = $3e8 +Constant (const word) memcpy::num#1 = $3e8 +Successful SSA optimization Pass2ConstantIdentification +Constant (const byte*) memcpy::destination#0 = SCREEN#0 +Constant (const byte*) memcpy::source#0 = MEDUSA_SCREEN#0 +Constant (const byte*) memcpy::destination#1 = COLS#0 +Constant (const byte*) memcpy::source#1 = MEDUSA_COLORS#0 +Successful SSA optimization Pass2ConstantIdentification +if() condition always true - replacing block destination [35] if(true) goto main::@2 +Successful SSA optimization Pass2ConstantIfs +Eliminating unused variable (byte*) memcpy::return#2 and assignment [12] (byte*) memcpy::return#2 ← (byte*) memcpy::dst#0 +Eliminating unused variable (byte*) memcpy::return#3 and assignment [14] (byte*) memcpy::return#3 ← (byte*) memcpy::dst#0 +Successful SSA optimization PassNEliminateUnusedVars +Removing unused block main::@return +Successful SSA optimization Pass2EliminateUnusedBlocks +Constant right-side identified [13] (byte*~) main::$2 ← (const byte*) SCREEN#0 + (word) $3e7 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant (const byte*) main::$2 = SCREEN#0+$3e7 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with var siblings (const word) memcpy::i#0 +Inlining constant with var siblings (const word) memcpy::num#0 +Inlining constant with var siblings (const word) memcpy::num#1 +Constant inlined memcpy::num#1 = (word) $3e8 +Constant inlined memcpy::num#0 = (word) $3e8 +Constant inlined memcpy::source#1 = (const byte*) MEDUSA_COLORS#0 +Constant inlined main::$2 = (const byte*) SCREEN#0+(word) $3e7 +Constant inlined memcpy::destination#0 = (const byte*) SCREEN#0 +Constant inlined memcpy::destination#1 = (const byte*) COLS#0 +Constant inlined memcpy::source#0 = (const byte*) MEDUSA_SCREEN#0 +Constant inlined memcpy::i#0 = (byte) 0 +Successful SSA optimization Pass2ConstantInlining +Identical Phi Values (word) memcpy::num#3 (word) $3e8 +Successful SSA optimization Pass2IdenticalPhiElimination +Added new block during phi lifting memcpy::@4(between memcpy::@1 and memcpy::@1) +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @8 +Adding NOP phi() at start of @9 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main::@7 +Adding NOP phi() at start of main::@8 +Adding NOP phi() at start of main::@1 +Adding NOP phi() at start of memcpy::@2 +CALL GRAPH +Calls in [] to main:4 +Calls in [main] to memcpy:8 memcpy:10 + +Created 5 initial phi equivalence classes +Coalesced [15] memcpy::src#3 ← memcpy::src#0 +Coalesced [16] memcpy::dst#3 ← memcpy::dst#0 +Coalesced [25] memcpy::src#4 ← memcpy::src#1 +Coalesced [26] memcpy::dst#4 ← memcpy::dst#1 +Coalesced [27] memcpy::i#3 ← memcpy::i#1 +Coalesced down to 3 phi equivalence classes +Culled Empty Block (label) @9 +Culled Empty Block (label) main::@8 +Culled Empty Block (label) main::@1 +Culled Empty Block (label) memcpy::@2 +Culled Empty Block (label) memcpy::@4 +Renumbering block @7 to @1 +Renumbering block @8 to @2 +Renumbering block main::@2 to main::@1 +Renumbering block main::@7 to main::@2 +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @2 +Adding NOP phi() at start of @end +Adding NOP phi() at start of main::@2 + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() + to:@1 +@1: scope:[] from @begin + kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + }} + kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + }} + to:@2 +@2: scope:[] from @1 + [3] phi() + [4] call main + to:@end +@end: scope:[] from @2 + [5] phi() +main: scope:[main] from @2 + [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 + [7] call memcpy + to:main::@2 +main::@2: scope:[main] from main + [8] phi() + [9] call memcpy + to:main::@1 +main::@1: scope:[main] from main::@1 main::@2 + [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e + to:main::@1 +memcpy: scope:[memcpy] from main main::@2 + [11] (byte*) memcpy::dst#0 ← phi( main/(const byte*) SCREEN#0 main::@2/(const byte*) COLS#0 ) + [11] (byte*) memcpy::src#0 ← phi( main/(const byte*) MEDUSA_SCREEN#0 main::@2/(const byte*) MEDUSA_COLORS#0 ) + to:memcpy::@1 +memcpy::@1: scope:[memcpy] from memcpy memcpy::@1 + [12] (word) memcpy::i#2 ← phi( memcpy/(byte) 0 memcpy::@1/(word) memcpy::i#1 ) + [12] (byte*) memcpy::dst#2 ← phi( memcpy/(byte*) memcpy::dst#0 memcpy::@1/(byte*) memcpy::dst#1 ) + [12] (byte*) memcpy::src#2 ← phi( memcpy/(byte*) memcpy::src#0 memcpy::@1/(byte*) memcpy::src#1 ) + [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) + [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 + [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 + [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 + [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 + to:memcpy::@return +memcpy::@return: scope:[memcpy] from memcpy::@1 + [18] return + to:@return + + +VARIABLE REGISTER WEIGHTS +(byte*) BGCOL +(byte) BLACK +(byte*) COLS +(byte*) MEDUSA_COLORS +(byte*) MEDUSA_SCREEN +(byte*) SCREEN +(void()) main() +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(byte*) memcpy::destination +(byte*) memcpy::dst +(byte*) memcpy::dst#0 2.0 +(byte*) memcpy::dst#1 5.5 +(byte*) memcpy::dst#2 17.5 +(word) memcpy::i +(word) memcpy::i#1 16.5 +(word) memcpy::i#2 5.5 +(word) memcpy::num +(byte*) memcpy::return +(byte*) memcpy::source +(byte*) memcpy::src +(byte*) memcpy::src#0 2.0 +(byte*) memcpy::src#1 7.333333333333333 +(byte*) memcpy::src#2 11.666666666666666 + +Initial phi equivalence classes +[ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +[ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +[ memcpy::i#2 memcpy::i#1 ] +Complete equivalence classes +[ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +[ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +[ memcpy::i#2 memcpy::i#1 ] +Allocated zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +Allocated zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +Allocated zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] + +INITIAL ASM +//SEG0 File Comments +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +//SEG3 @begin +bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) .fill fileScreen.getSize(), fileScreen.get(i) }} +//SEG6 kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) .fill fileCols.getSize(), fileCols.get(i) }} +//SEG7 [3] phi from @1 to @2 [phi:@1->@2] +b2_from_b1: + jmp b2 +//SEG8 @2 +b2: +//SEG9 [4] call main + jsr main +//SEG10 [5] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG11 @end +bend: +//SEG12 main +main: { + //SEG13 [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG14 [7] call memcpy + //SEG15 [11] phi from main to memcpy [phi:main->memcpy] + memcpy_from_main: + //SEG16 [11] phi (byte*) memcpy::dst#0 = (const byte*) SCREEN#0 [phi:main->memcpy#0] -- pbuz1=pbuc1 + lda #SCREEN + sta memcpy.dst+1 + //SEG17 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_SCREEN#0 [phi:main->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + //SEG18 [8] phi from main to main::@2 [phi:main->main::@2] + b2_from_main: + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [9] call memcpy + //SEG21 [11] phi from main::@2 to memcpy [phi:main::@2->memcpy] + memcpy_from_b2: + //SEG22 [11] phi (byte*) memcpy::dst#0 = (const byte*) COLS#0 [phi:main::@2->memcpy#0] -- pbuz1=pbuc1 + lda #COLS + sta memcpy.dst+1 + //SEG23 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_COLORS#0 [phi:main::@2->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + jmp b1 + //SEG24 main::@1 + b1: + //SEG25 [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e -- _deref_pbuc1=_deref_pbuc1_bxor_vbuc2 + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +//SEG26 memcpy +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + //SEG27 [12] phi from memcpy to memcpy::@1 [phi:memcpy->memcpy::@1] + b1_from_memcpy: + //SEG28 [12] phi (word) memcpy::i#2 = (byte) 0 [phi:memcpy->memcpy::@1#0] -- vwuz1=vbuc1 + lda #0 + sta i + lda #0 + sta i+1 + //SEG29 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#0 [phi:memcpy->memcpy::@1#1] -- register_copy + //SEG30 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#0 [phi:memcpy->memcpy::@1#2] -- register_copy + jmp b1 + //SEG31 [12] phi from memcpy::@1 to memcpy::@1 [phi:memcpy::@1->memcpy::@1] + b1_from_b1: + //SEG32 [12] phi (word) memcpy::i#2 = (word) memcpy::i#1 [phi:memcpy::@1->memcpy::@1#0] -- register_copy + //SEG33 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#1 [phi:memcpy::@1->memcpy::@1#1] -- register_copy + //SEG34 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#1 [phi:memcpy::@1->memcpy::@1#2] -- register_copy + jmp b1 + //SEG35 memcpy::@1 + b1: + //SEG36 [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (src),y + ldy #0 + sta (dst),y + //SEG37 [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 -- pbuz1=_inc_pbuz1 + inc dst + bne !+ + inc dst+1 + !: + //SEG38 [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 -- pbuz1=_inc_pbuz1 + inc src + bne !+ + inc src+1 + !: + //SEG39 [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 -- vwuz1=_inc_vwuz1 + inc i + bne !+ + inc i+1 + !: + //SEG40 [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 -- vwuz1_lt_vwuc1_then_la1 + lda i+1 + cmp #>$3e8 + bcc b1_from_b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1_from_b1 + !: + jmp breturn + //SEG41 memcpy::@return + breturn: + //SEG42 [18] return + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( main:4 [ ] ) always clobbers reg byte a +Statement [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e [ ] ( main:4 [ ] ) always clobbers reg byte a +Statement [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) [ memcpy::src#2 memcpy::dst#2 memcpy::i#2 ] ( main:4::memcpy:7 [ memcpy::src#2 memcpy::dst#2 memcpy::i#2 ] main:4::memcpy:9 [ memcpy::src#2 memcpy::dst#2 memcpy::i#2 ] ) always clobbers reg byte a reg byte y +Statement [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 [ memcpy::src#1 memcpy::dst#1 memcpy::i#1 ] ( main:4::memcpy:7 [ memcpy::src#1 memcpy::dst#1 memcpy::i#1 ] main:4::memcpy:9 [ memcpy::src#1 memcpy::dst#1 memcpy::i#1 ] ) always clobbers reg byte a +Potential registers zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] : zp ZP_WORD:2 , +Potential registers zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] : zp ZP_WORD:4 , +Potential registers zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] : zp ZP_WORD:6 , + +REGISTER UPLIFT SCOPES +Uplift Scope [memcpy] 25: zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] 22: zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] 21: zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +Uplift Scope [main] +Uplift Scope [] + +Uplifting [memcpy] best 1649 combination zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +Uplifting [main] best 1649 combination +Uplifting [] best 1649 combination + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 File Comments +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(bbegin) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +//SEG3 @begin +bbegin: + jmp b1 +//SEG4 @1 +b1: +//SEG5 kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) .fill fileScreen.getSize(), fileScreen.get(i) }} +//SEG6 kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) .fill fileCols.getSize(), fileCols.get(i) }} +//SEG7 [3] phi from @1 to @2 [phi:@1->@2] +b2_from_b1: + jmp b2 +//SEG8 @2 +b2: +//SEG9 [4] call main + jsr main +//SEG10 [5] phi from @2 to @end [phi:@2->@end] +bend_from_b2: + jmp bend +//SEG11 @end +bend: +//SEG12 main +main: { + //SEG13 [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG14 [7] call memcpy + //SEG15 [11] phi from main to memcpy [phi:main->memcpy] + memcpy_from_main: + //SEG16 [11] phi (byte*) memcpy::dst#0 = (const byte*) SCREEN#0 [phi:main->memcpy#0] -- pbuz1=pbuc1 + lda #SCREEN + sta memcpy.dst+1 + //SEG17 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_SCREEN#0 [phi:main->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + //SEG18 [8] phi from main to main::@2 [phi:main->main::@2] + b2_from_main: + jmp b2 + //SEG19 main::@2 + b2: + //SEG20 [9] call memcpy + //SEG21 [11] phi from main::@2 to memcpy [phi:main::@2->memcpy] + memcpy_from_b2: + //SEG22 [11] phi (byte*) memcpy::dst#0 = (const byte*) COLS#0 [phi:main::@2->memcpy#0] -- pbuz1=pbuc1 + lda #COLS + sta memcpy.dst+1 + //SEG23 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_COLORS#0 [phi:main::@2->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + jmp b1 + //SEG24 main::@1 + b1: + //SEG25 [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e -- _deref_pbuc1=_deref_pbuc1_bxor_vbuc2 + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +//SEG26 memcpy +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + //SEG27 [12] phi from memcpy to memcpy::@1 [phi:memcpy->memcpy::@1] + b1_from_memcpy: + //SEG28 [12] phi (word) memcpy::i#2 = (byte) 0 [phi:memcpy->memcpy::@1#0] -- vwuz1=vbuc1 + lda #0 + sta i + lda #0 + sta i+1 + //SEG29 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#0 [phi:memcpy->memcpy::@1#1] -- register_copy + //SEG30 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#0 [phi:memcpy->memcpy::@1#2] -- register_copy + jmp b1 + //SEG31 [12] phi from memcpy::@1 to memcpy::@1 [phi:memcpy::@1->memcpy::@1] + b1_from_b1: + //SEG32 [12] phi (word) memcpy::i#2 = (word) memcpy::i#1 [phi:memcpy::@1->memcpy::@1#0] -- register_copy + //SEG33 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#1 [phi:memcpy::@1->memcpy::@1#1] -- register_copy + //SEG34 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#1 [phi:memcpy::@1->memcpy::@1#2] -- register_copy + jmp b1 + //SEG35 memcpy::@1 + b1: + //SEG36 [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (src),y + ldy #0 + sta (dst),y + //SEG37 [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 -- pbuz1=_inc_pbuz1 + inc dst + bne !+ + inc dst+1 + !: + //SEG38 [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 -- pbuz1=_inc_pbuz1 + inc src + bne !+ + inc src+1 + !: + //SEG39 [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 -- vwuz1=_inc_vwuz1 + inc i + bne !+ + inc i+1 + !: + //SEG40 [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 -- vwuz1_lt_vwuc1_then_la1 + lda i+1 + cmp #>$3e8 + bcc b1_from_b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1_from_b1 + !: + jmp breturn + //SEG41 memcpy::@return + breturn: + //SEG42 [18] return + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b1 +Removing instruction jmp b2 +Removing instruction jmp bend +Removing instruction jmp b2 +Removing instruction jmp b1 +Removing instruction jmp b1 +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #0 +Removing instruction ldy #0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Replacing label b1_from_b1 with b1 +Replacing label b1_from_b1 with b1 +Removing instruction b1: +Removing instruction b2_from_b1: +Removing instruction b2: +Removing instruction bend_from_b2: +Removing instruction b2_from_main: +Removing instruction memcpy_from_b2: +Removing instruction b1_from_b1: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction bend: +Removing instruction memcpy_from_main: +Removing instruction b2: +Removing instruction b1_from_memcpy: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Updating BasicUpstart to call main directly +Removing instruction jsr main +Succesful ASM optimization Pass5SkipBegin +Removing instruction jmp b1 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = (byte*) 53281 +(byte) BLACK +(const byte) BLACK#0 BLACK = (byte) 0 +(byte*) COLS +(const byte*) COLS#0 COLS = (byte*) 55296 +(byte*) MEDUSA_COLORS +(const byte*) MEDUSA_COLORS#0 MEDUSA_COLORS = (byte*) 5120 +(byte*) MEDUSA_SCREEN +(const byte*) MEDUSA_SCREEN#0 MEDUSA_SCREEN = (byte*) 4096 +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(void()) main() +(label) main::@1 +(label) main::@2 +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(label) memcpy::@1 +(label) memcpy::@return +(byte*) memcpy::destination +(byte*) memcpy::dst +(byte*) memcpy::dst#0 dst zp ZP_WORD:4 2.0 +(byte*) memcpy::dst#1 dst zp ZP_WORD:4 5.5 +(byte*) memcpy::dst#2 dst zp ZP_WORD:4 17.5 +(word) memcpy::i +(word) memcpy::i#1 i zp ZP_WORD:6 16.5 +(word) memcpy::i#2 i zp ZP_WORD:6 5.5 +(word) memcpy::num +(byte*) memcpy::return +(byte*) memcpy::source +(byte*) memcpy::src +(byte*) memcpy::src#0 src zp ZP_WORD:2 2.0 +(byte*) memcpy::src#1 src zp ZP_WORD:2 7.333333333333333 +(byte*) memcpy::src#2 src zp ZP_WORD:2 11.666666666666666 + +zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ] + + +FINAL ASSEMBLER +Score: 1471 + +//SEG0 File Comments +// Display MEDUSA PETSCII by Buzz_clik +// https://csdb.dk/release/?id=178673 +//SEG1 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG2 Global Constants & labels + .label BGCOL = $d021 + // Color Ram + .label COLS = $d800 + // The colors of the C64 + .const BLACK = 0 + .label MEDUSA_SCREEN = $1000 + .label MEDUSA_COLORS = $1400 + .label SCREEN = $400 +//SEG3 @begin +//SEG4 @1 +//SEG5 kickasm(location (const byte*) MEDUSA_SCREEN#0) {{ .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) .fill fileScreen.getSize(), fileScreen.get(i) }} +//SEG6 kickasm(location (const byte*) MEDUSA_COLORS#0) {{ .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) .fill fileCols.getSize(), fileCols.get(i) }} +//SEG7 [3] phi from @1 to @2 [phi:@1->@2] +//SEG8 @2 +//SEG9 [4] call main +//SEG10 [5] phi from @2 to @end [phi:@2->@end] +//SEG11 @end +//SEG12 main +main: { + //SEG13 [6] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG14 [7] call memcpy + //SEG15 [11] phi from main to memcpy [phi:main->memcpy] + //SEG16 [11] phi (byte*) memcpy::dst#0 = (const byte*) SCREEN#0 [phi:main->memcpy#0] -- pbuz1=pbuc1 + lda #SCREEN + sta memcpy.dst+1 + //SEG17 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_SCREEN#0 [phi:main->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_SCREEN + sta memcpy.src+1 + jsr memcpy + //SEG18 [8] phi from main to main::@2 [phi:main->main::@2] + //SEG19 main::@2 + //SEG20 [9] call memcpy + //SEG21 [11] phi from main::@2 to memcpy [phi:main::@2->memcpy] + //SEG22 [11] phi (byte*) memcpy::dst#0 = (const byte*) COLS#0 [phi:main::@2->memcpy#0] -- pbuz1=pbuc1 + lda #COLS + sta memcpy.dst+1 + //SEG23 [11] phi (byte*) memcpy::src#0 = (const byte*) MEDUSA_COLORS#0 [phi:main::@2->memcpy#1] -- pbuz1=pbuc1 + lda #MEDUSA_COLORS + sta memcpy.src+1 + jsr memcpy + //SEG24 main::@1 + b1: + //SEG25 [10] *((const byte*) SCREEN#0+(word) $3e7) ← *((const byte*) SCREEN#0+(word) $3e7) ^ (byte) $e -- _deref_pbuc1=_deref_pbuc1_bxor_vbuc2 + lda #$e + eor SCREEN+$3e7 + sta SCREEN+$3e7 + jmp b1 +} +//SEG26 memcpy +// Copy block of memory +// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. +memcpy: { + .label src = 2 + .label dst = 4 + .label i = 6 + //SEG27 [12] phi from memcpy to memcpy::@1 [phi:memcpy->memcpy::@1] + //SEG28 [12] phi (word) memcpy::i#2 = (byte) 0 [phi:memcpy->memcpy::@1#0] -- vwuz1=vbuc1 + lda #0 + sta i + sta i+1 + //SEG29 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#0 [phi:memcpy->memcpy::@1#1] -- register_copy + //SEG30 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#0 [phi:memcpy->memcpy::@1#2] -- register_copy + //SEG31 [12] phi from memcpy::@1 to memcpy::@1 [phi:memcpy::@1->memcpy::@1] + //SEG32 [12] phi (word) memcpy::i#2 = (word) memcpy::i#1 [phi:memcpy::@1->memcpy::@1#0] -- register_copy + //SEG33 [12] phi (byte*) memcpy::dst#2 = (byte*) memcpy::dst#1 [phi:memcpy::@1->memcpy::@1#1] -- register_copy + //SEG34 [12] phi (byte*) memcpy::src#2 = (byte*) memcpy::src#1 [phi:memcpy::@1->memcpy::@1#2] -- register_copy + //SEG35 memcpy::@1 + b1: + //SEG36 [13] *((byte*) memcpy::dst#2) ← *((byte*) memcpy::src#2) -- _deref_pbuz1=_deref_pbuz2 + ldy #0 + lda (src),y + sta (dst),y + //SEG37 [14] (byte*) memcpy::dst#1 ← ++ (byte*) memcpy::dst#2 -- pbuz1=_inc_pbuz1 + inc dst + bne !+ + inc dst+1 + !: + //SEG38 [15] (byte*) memcpy::src#1 ← ++ (byte*) memcpy::src#2 -- pbuz1=_inc_pbuz1 + inc src + bne !+ + inc src+1 + !: + //SEG39 [16] (word) memcpy::i#1 ← ++ (word) memcpy::i#2 -- vwuz1=_inc_vwuz1 + inc i + bne !+ + inc i+1 + !: + //SEG40 [17] if((word) memcpy::i#1<(word) $3e8) goto memcpy::@1 -- vwuz1_lt_vwuc1_then_la1 + lda i+1 + cmp #>$3e8 + bcc b1 + bne !+ + lda i + cmp #<$3e8 + bcc b1 + !: + //SEG41 memcpy::@return + //SEG42 [18] return + rts +} +.pc = MEDUSA_SCREEN "MEDUSA_SCREEN" + .var fileScreen = LoadBinary("medusas.prg", BF_C64FILE) + .fill fileScreen.getSize(), fileScreen.get(i) + +.pc = MEDUSA_COLORS "MEDUSA_COLORS" + .var fileCols = LoadBinary("medusac.prg", BF_C64FILE) + .fill fileCols.getSize(), fileCols.get(i) + + diff --git a/src/test/ref/medusa.sym b/src/test/ref/medusa.sym new file mode 100644 index 000000000..aecc6c6fd --- /dev/null +++ b/src/test/ref/medusa.sym @@ -0,0 +1,41 @@ +(label) @1 +(label) @2 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = (byte*) 53281 +(byte) BLACK +(const byte) BLACK#0 BLACK = (byte) 0 +(byte*) COLS +(const byte*) COLS#0 COLS = (byte*) 55296 +(byte*) MEDUSA_COLORS +(const byte*) MEDUSA_COLORS#0 MEDUSA_COLORS = (byte*) 5120 +(byte*) MEDUSA_SCREEN +(const byte*) MEDUSA_SCREEN#0 MEDUSA_SCREEN = (byte*) 4096 +(byte*) SCREEN +(const byte*) SCREEN#0 SCREEN = (byte*) 1024 +(void()) main() +(label) main::@1 +(label) main::@2 +(byte*()) memcpy((byte*) memcpy::destination , (byte*) memcpy::source , (word) memcpy::num) +(label) memcpy::@1 +(label) memcpy::@return +(byte*) memcpy::destination +(byte*) memcpy::dst +(byte*) memcpy::dst#0 dst zp ZP_WORD:4 2.0 +(byte*) memcpy::dst#1 dst zp ZP_WORD:4 5.5 +(byte*) memcpy::dst#2 dst zp ZP_WORD:4 17.5 +(word) memcpy::i +(word) memcpy::i#1 i zp ZP_WORD:6 16.5 +(word) memcpy::i#2 i zp ZP_WORD:6 5.5 +(word) memcpy::num +(byte*) memcpy::return +(byte*) memcpy::source +(byte*) memcpy::src +(byte*) memcpy::src#0 src zp ZP_WORD:2 2.0 +(byte*) memcpy::src#1 src zp ZP_WORD:2 7.333333333333333 +(byte*) memcpy::src#2 src zp ZP_WORD:2 11.666666666666666 + +zp ZP_WORD:2 [ memcpy::src#2 memcpy::src#0 memcpy::src#1 ] +zp ZP_WORD:4 [ memcpy::dst#2 memcpy::dst#0 memcpy::dst#1 ] +zp ZP_WORD:6 [ memcpy::i#2 memcpy::i#1 ]