diff --git a/src/test/kc/makelong-0.c b/src/test/kc/makelong-0.c new file mode 100644 index 000000000..800c83b16 --- /dev/null +++ b/src/test/kc/makelong-0.c @@ -0,0 +1,11 @@ +// Test MAKELONG() + +void main() { + unsigned long* const SCREEN = (unsigned int*)0x0400; + for(unsigned int lo=0;lo<100;lo++) + for(unsigned int hi=0;hi<100;hi++) { + unsigned long i = MAKELONG(hi, lo); + *SCREEN = i; + } + +} \ No newline at end of file diff --git a/src/test/ref/makelong-0.asm b/src/test/ref/makelong-0.asm new file mode 100644 index 000000000..1626b5355 --- /dev/null +++ b/src/test/ref/makelong-0.asm @@ -0,0 +1,72 @@ +// Test MAKELONG() + // Commodore 64 PRG executable file +.file [name="makelong-0.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) +.segment Code +main: { + .label SCREEN = $400 + .label i = 6 + .label hi = 4 + .label lo = 2 + lda #<0 + sta.z lo + sta.z lo+1 + __b1: + // for(unsigned int lo=0;lo<100;lo++) + lda.z lo+1 + bne !+ + lda.z lo + cmp #$64 + bcc __b4 + !: + // } + rts + __b4: + lda #<0 + sta.z hi + sta.z hi+1 + __b2: + // for(unsigned int hi=0;hi<100;hi++) + lda.z hi+1 + bne !+ + lda.z hi + cmp #$64 + bcc __b3 + !: + // for(unsigned int lo=0;lo<100;lo++) + inc.z lo + bne !+ + inc.z lo+1 + !: + jmp __b1 + __b3: + // unsigned long i = MAKELONG(hi, lo) + lda.z hi + sta.z i+2 + lda.z hi+1 + sta.z i+3 + lda.z lo + sta.z i + lda.z lo+1 + sta.z i+1 + // *SCREEN = i + lda.z i + sta SCREEN + lda.z i+1 + sta SCREEN+1 + lda.z i+2 + sta SCREEN+2 + lda.z i+3 + sta SCREEN+3 + // for(unsigned int hi=0;hi<100;hi++) + inc.z hi + bne !+ + inc.z hi+1 + !: + jmp __b2 +} diff --git a/src/test/ref/makelong-0.cfg b/src/test/ref/makelong-0.cfg new file mode 100644 index 000000000..39d4f2641 --- /dev/null +++ b/src/test/ref/makelong-0.cfg @@ -0,0 +1,24 @@ + +void main() +main: scope:[main] from + [0] phi() + to:main::@1 +main::@1: scope:[main] from main main::@4 + [1] main::lo#2 = phi( main/0, main::@4/main::lo#1 ) + [2] if(main::lo#2<$64) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [3] return + to:@return +main::@2: scope:[main] from main::@1 main::@3 + [4] main::hi#2 = phi( main::@1/0, main::@3/main::hi#1 ) + [5] if(main::hi#2<$64) goto main::@3 + to:main::@4 +main::@4: scope:[main] from main::@2 + [6] main::lo#1 = ++ main::lo#2 + to:main::@1 +main::@3: scope:[main] from main::@2 + [7] main::i#0 = main::hi#2 dw= main::lo#2 + [8] *main::SCREEN = main::i#0 + [9] main::hi#1 = ++ main::hi#2 + to:main::@2 diff --git a/src/test/ref/makelong-0.log b/src/test/ref/makelong-0.log new file mode 100644 index 000000000..caa710384 --- /dev/null +++ b/src/test/ref/makelong-0.log @@ -0,0 +1,422 @@ + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + main::lo#0 = 0 + to:main::@1 +main::@1: scope:[main] from main main::@5 + main::lo#2 = phi( main/main::lo#0, main::@5/main::lo#1 ) + main::$0 = main::lo#2 < $64 + if(main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + main::lo#6 = phi( main::@1/main::lo#2 ) + main::hi#0 = 0 + to:main::@3 +main::@3: scope:[main] from main::@2 main::@4 + main::lo#5 = phi( main::@2/main::lo#6, main::@4/main::lo#3 ) + main::hi#2 = phi( main::@2/main::hi#0, main::@4/main::hi#1 ) + main::$1 = main::hi#2 < $64 + if(main::$1) goto main::@4 + to:main::@5 +main::@4: scope:[main] from main::@3 + main::lo#3 = phi( main::@3/main::lo#5 ) + main::hi#3 = phi( main::@3/main::hi#2 ) + main::$2 = main::hi#3 dw= main::lo#3 + main::i#0 = main::$2 + *main::SCREEN = main::i#0 + main::hi#1 = ++ main::hi#3 + to:main::@3 +main::@5: scope:[main] from main::@3 + main::lo#4 = phi( main::@3/main::lo#5 ) + main::lo#1 = ++ main::lo#4 + to:main::@1 +main::@return: scope:[main] from main::@1 + 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 +void __start() +void main() +bool~ main::$0 +bool~ main::$1 +dword~ main::$2 +constant dword* const main::SCREEN = (word*)$400 +word main::hi +word main::hi#0 +word main::hi#1 +word main::hi#2 +word main::hi#3 +dword main::i +dword main::i#0 +word main::lo +word main::lo#0 +word main::lo#1 +word main::lo#2 +word main::lo#3 +word main::lo#4 +word main::lo#5 +word main::lo#6 + +Adding number conversion cast (unumber) $64 in main::$0 = main::lo#2 < $64 +Adding number conversion cast (unumber) $64 in main::$1 = main::hi#2 < $64 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (word*) 1024 +Simplifying constant integer cast $64 +Simplifying constant integer cast $64 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) $64 +Finalized unsigned number type (byte) $64 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias main::lo#2 = main::lo#6 +Alias main::hi#2 = main::hi#3 +Alias main::lo#3 = main::lo#5 main::lo#4 +Alias main::i#0 = main::$2 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values main::lo#3 main::lo#2 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition main::$0 [3] if(main::lo#2<$64) goto main::@2 +Simple Condition main::$1 [7] if(main::hi#2<$64) goto main::@4 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant main::lo#0 = 0 +Constant main::hi#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +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 +Inlining constant with var siblings main::lo#0 +Inlining constant with var siblings main::hi#0 +Constant inlined main::lo#0 = 0 +Constant inlined main::hi#0 = 0 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of main +Adding NOP phi() at start of main::@2 +CALL GRAPH + +Created 2 initial phi equivalence classes +Coalesced [8] main::lo#7 = main::lo#1 +Coalesced [12] main::hi#4 = main::hi#1 +Coalesced down to 2 phi equivalence classes +Culled Empty Block label main::@2 +Renumbering block main::@3 to main::@2 +Renumbering block main::@4 to main::@3 +Renumbering block main::@5 to main::@4 +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] phi() + to:main::@1 +main::@1: scope:[main] from main main::@4 + [1] main::lo#2 = phi( main/0, main::@4/main::lo#1 ) + [2] if(main::lo#2<$64) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [3] return + to:@return +main::@2: scope:[main] from main::@1 main::@3 + [4] main::hi#2 = phi( main::@1/0, main::@3/main::hi#1 ) + [5] if(main::hi#2<$64) goto main::@3 + to:main::@4 +main::@4: scope:[main] from main::@2 + [6] main::lo#1 = ++ main::lo#2 + to:main::@1 +main::@3: scope:[main] from main::@2 + [7] main::i#0 = main::hi#2 dw= main::lo#2 + [8] *main::SCREEN = main::i#0 + [9] main::hi#1 = ++ main::hi#2 + to:main::@2 + + +VARIABLE REGISTER WEIGHTS +void main() +word main::hi +word main::hi#1 202.0 +word main::hi#2 101.0 +dword main::i +dword main::i#0 202.0 +word main::lo +word main::lo#1 22.0 +word main::lo#2 19.142857142857142 + +Initial phi equivalence classes +[ main::lo#2 main::lo#1 ] +[ main::hi#2 main::hi#1 ] +Added variable main::i#0 to live range equivalence class [ main::i#0 ] +Complete equivalence classes +[ main::lo#2 main::lo#1 ] +[ main::hi#2 main::hi#1 ] +[ main::i#0 ] +Allocated zp[2]:2 [ main::lo#2 main::lo#1 ] +Allocated zp[2]:4 [ main::hi#2 main::hi#1 ] +Allocated zp[4]:6 [ main::i#0 ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [2] if(main::lo#2<$64) goto main::@2 [ main::lo#2 ] ( [ main::lo#2 ] { } ) always clobbers reg byte a +Statement [5] if(main::hi#2<$64) goto main::@3 [ main::lo#2 main::hi#2 ] ( [ main::lo#2 main::hi#2 ] { } ) always clobbers reg byte a +Statement [7] main::i#0 = main::hi#2 dw= main::lo#2 [ main::lo#2 main::hi#2 main::i#0 ] ( [ main::lo#2 main::hi#2 main::i#0 ] { } ) always clobbers reg byte a +Statement [8] *main::SCREEN = main::i#0 [ main::lo#2 main::hi#2 ] ( [ main::lo#2 main::hi#2 ] { } ) always clobbers reg byte a +Potential registers zp[2]:2 [ main::lo#2 main::lo#1 ] : zp[2]:2 , +Potential registers zp[2]:4 [ main::hi#2 main::hi#1 ] : zp[2]:4 , +Potential registers zp[4]:6 [ main::i#0 ] : zp[4]:6 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 303: zp[2]:4 [ main::hi#2 main::hi#1 ] 202: zp[4]:6 [ main::i#0 ] 41.14: zp[2]:2 [ main::lo#2 main::lo#1 ] +Uplift Scope [] + +Uplifting [main] best 10101 combination zp[2]:4 [ main::hi#2 main::hi#1 ] zp[4]:6 [ main::i#0 ] zp[2]:2 [ main::lo#2 main::lo#1 ] +Uplifting [] best 10101 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test MAKELONG() + // Upstart + // Commodore 64 PRG executable file +.file [name="makelong-0.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 +.segment Code + // main +main: { + .label SCREEN = $400 + .label i = 6 + .label hi = 4 + .label lo = 2 + // [1] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [1] phi main::lo#2 = 0 [phi:main->main::@1#0] -- vwuz1=vwuc1 + lda #<0 + sta.z lo + lda #>0 + sta.z lo+1 + jmp __b1 + // main::@1 + __b1: + // [2] if(main::lo#2<$64) goto main::@2 -- vwuz1_lt_vbuc1_then_la1 + lda.z lo+1 + bne !+ + lda.z lo + cmp #$64 + bcc __b2_from___b1 + !: + jmp __breturn + // main::@return + __breturn: + // [3] return + rts + // [4] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + __b2_from___b1: + // [4] phi main::hi#2 = 0 [phi:main::@1->main::@2#0] -- vwuz1=vwuc1 + lda #<0 + sta.z hi + lda #>0 + sta.z hi+1 + jmp __b2 + // main::@2 + __b2: + // [5] if(main::hi#2<$64) goto main::@3 -- vwuz1_lt_vbuc1_then_la1 + lda.z hi+1 + bne !+ + lda.z hi + cmp #$64 + bcc __b3 + !: + jmp __b4 + // main::@4 + __b4: + // [6] main::lo#1 = ++ main::lo#2 -- vwuz1=_inc_vwuz1 + inc.z lo + bne !+ + inc.z lo+1 + !: + // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + __b1_from___b4: + // [1] phi main::lo#2 = main::lo#1 [phi:main::@4->main::@1#0] -- register_copy + jmp __b1 + // main::@3 + __b3: + // [7] main::i#0 = main::hi#2 dw= main::lo#2 -- vduz1=vwuz2_dword_vwuz3 + lda.z hi + sta.z i+2 + lda.z hi+1 + sta.z i+3 + lda.z lo + sta.z i + lda.z lo+1 + sta.z i+1 + // [8] *main::SCREEN = main::i#0 -- _deref_pduc1=vduz1 + lda.z i + sta SCREEN + lda.z i+1 + sta SCREEN+1 + lda.z i+2 + sta SCREEN+2 + lda.z i+3 + sta SCREEN+3 + // [9] main::hi#1 = ++ main::hi#2 -- vwuz1=_inc_vwuz1 + inc.z hi + bne !+ + inc.z hi+1 + !: + // [4] phi from main::@3 to main::@2 [phi:main::@3->main::@2] + __b2_from___b3: + // [4] phi main::hi#2 = main::hi#1 [phi:main::@3->main::@2#0] -- register_copy + jmp __b2 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Removing instruction jmp __b2 +Removing instruction jmp __b4 +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #>0 +Removing instruction lda #>0 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b4: +Removing instruction __b1_from___b4: +Removing instruction __b2_from___b3: +Succesful ASM optimization Pass5UnusedLabelElimination +Relabelling long label __b2_from___b1 to __b4 +Succesful ASM optimization Pass5RelabelLongLabels + +FINAL SYMBOL TABLE +void main() +constant dword* const main::SCREEN = (word*) 1024 +word main::hi +word main::hi#1 hi zp[2]:4 202.0 +word main::hi#2 hi zp[2]:4 101.0 +dword main::i +dword main::i#0 i zp[4]:6 202.0 +word main::lo +word main::lo#1 lo zp[2]:2 22.0 +word main::lo#2 lo zp[2]:2 19.142857142857142 + +zp[2]:2 [ main::lo#2 main::lo#1 ] +zp[2]:4 [ main::hi#2 main::hi#1 ] +zp[4]:6 [ main::i#0 ] + + +FINAL ASSEMBLER +Score: 9221 + + // File Comments +// Test MAKELONG() + // Upstart + // Commodore 64 PRG executable file +.file [name="makelong-0.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 +.segment Code + // main +main: { + .label SCREEN = $400 + .label i = 6 + .label hi = 4 + .label lo = 2 + // [1] phi from main to main::@1 [phi:main->main::@1] + // [1] phi main::lo#2 = 0 [phi:main->main::@1#0] -- vwuz1=vwuc1 + lda #<0 + sta.z lo + sta.z lo+1 + // main::@1 + __b1: + // for(unsigned int lo=0;lo<100;lo++) + // [2] if(main::lo#2<$64) goto main::@2 -- vwuz1_lt_vbuc1_then_la1 + lda.z lo+1 + bne !+ + lda.z lo + cmp #$64 + bcc __b4 + !: + // main::@return + // } + // [3] return + rts + // [4] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + __b4: + // [4] phi main::hi#2 = 0 [phi:main::@1->main::@2#0] -- vwuz1=vwuc1 + lda #<0 + sta.z hi + sta.z hi+1 + // main::@2 + __b2: + // for(unsigned int hi=0;hi<100;hi++) + // [5] if(main::hi#2<$64) goto main::@3 -- vwuz1_lt_vbuc1_then_la1 + lda.z hi+1 + bne !+ + lda.z hi + cmp #$64 + bcc __b3 + !: + // main::@4 + // for(unsigned int lo=0;lo<100;lo++) + // [6] main::lo#1 = ++ main::lo#2 -- vwuz1=_inc_vwuz1 + inc.z lo + bne !+ + inc.z lo+1 + !: + // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + // [1] phi main::lo#2 = main::lo#1 [phi:main::@4->main::@1#0] -- register_copy + jmp __b1 + // main::@3 + __b3: + // unsigned long i = MAKELONG(hi, lo) + // [7] main::i#0 = main::hi#2 dw= main::lo#2 -- vduz1=vwuz2_dword_vwuz3 + lda.z hi + sta.z i+2 + lda.z hi+1 + sta.z i+3 + lda.z lo + sta.z i + lda.z lo+1 + sta.z i+1 + // *SCREEN = i + // [8] *main::SCREEN = main::i#0 -- _deref_pduc1=vduz1 + lda.z i + sta SCREEN + lda.z i+1 + sta SCREEN+1 + lda.z i+2 + sta SCREEN+2 + lda.z i+3 + sta SCREEN+3 + // for(unsigned int hi=0;hi<100;hi++) + // [9] main::hi#1 = ++ main::hi#2 -- vwuz1=_inc_vwuz1 + inc.z hi + bne !+ + inc.z hi+1 + !: + // [4] phi from main::@3 to main::@2 [phi:main::@3->main::@2] + // [4] phi main::hi#2 = main::hi#1 [phi:main::@3->main::@2#0] -- register_copy + jmp __b2 +} + // File Data + diff --git a/src/test/ref/makelong-0.sym b/src/test/ref/makelong-0.sym new file mode 100644 index 000000000..7f22ef180 --- /dev/null +++ b/src/test/ref/makelong-0.sym @@ -0,0 +1,14 @@ +void main() +constant dword* const main::SCREEN = (word*) 1024 +word main::hi +word main::hi#1 hi zp[2]:4 202.0 +word main::hi#2 hi zp[2]:4 101.0 +dword main::i +dword main::i#0 i zp[4]:6 202.0 +word main::lo +word main::lo#1 lo zp[2]:2 22.0 +word main::lo#2 lo zp[2]:2 19.142857142857142 + +zp[2]:2 [ main::lo#2 main::lo#1 ] +zp[2]:4 [ main::hi#2 main::hi#1 ] +zp[4]:6 [ main::i#0 ]