Inlined call call __init CONTROL FLOW GRAPH SSA void main() main: scope:[main] from __start::@1 cnt3#15 = phi( __start::@1/cnt3#16 ) cnt2#15 = phi( __start::@1/cnt2#16 ) cnt#16 = phi( __start::@1/cnt#17 ) call inccnt inccnt::return#0 = inccnt::return#3 to:main::@1 main::@1: scope:[main] from main cnt3#8 = phi( main/cnt3#4 ) cnt2#8 = phi( main/cnt2#4 ) cnt#9 = phi( main/cnt#5 ) inccnt::return#4 = phi( main/inccnt::return#0 ) main::$0 = inccnt::return#4 cnt#0 = cnt#9 cnt2#0 = cnt2#8 cnt3#0 = cnt3#8 SCREEN[0] = main::$0 cnt#1 = ++ cnt#0 call inccnt inccnt::return#1 = inccnt::return#3 to:main::@2 main::@2: scope:[main] from main::@1 cnt3#9 = phi( main::@1/cnt3#4 ) cnt2#9 = phi( main::@1/cnt2#4 ) cnt#10 = phi( main::@1/cnt#5 ) inccnt::return#5 = phi( main::@1/inccnt::return#1 ) main::$1 = inccnt::return#5 cnt#2 = cnt#10 cnt2#1 = cnt2#9 cnt3#1 = cnt3#9 SCREEN[1] = main::$1 SCREEN[2] = cnt2#1 SCREEN[3] = cnt3#1 to:main::@return main::@return: scope:[main] from main::@2 cnt3#10 = phi( main::@2/cnt3#1 ) cnt2#10 = phi( main::@2/cnt2#1 ) cnt#11 = phi( main::@2/cnt#2 ) cnt#3 = cnt#11 cnt2#2 = cnt2#10 cnt3#2 = cnt3#10 return to:@return char inccnt() inccnt: scope:[inccnt] from main main::@1 cnt3#11 = phi( main/cnt3#15, main::@1/cnt3#0 ) cnt2#11 = phi( main/cnt2#15, main::@1/cnt2#0 ) cnt#12 = phi( main/cnt#16, main::@1/cnt#1 ) cnt#4 = ++ cnt#12 cnt2#3 = ++ cnt2#11 cnt3#3 = ++ cnt3#11 inccnt::return#2 = cnt#4 to:inccnt::@return inccnt::@return: scope:[inccnt] from inccnt cnt3#12 = phi( inccnt/cnt3#3 ) cnt2#12 = phi( inccnt/cnt2#3 ) cnt#13 = phi( inccnt/cnt#4 ) inccnt::return#6 = phi( inccnt/inccnt::return#2 ) inccnt::return#3 = inccnt::return#6 cnt#5 = cnt#13 cnt2#4 = cnt2#12 cnt3#4 = cnt3#12 return to:@return void __start() __start: scope:[__start] from to:__start::__init1 __start::__init1: scope:[__start] from __start cnt#6 = 0 cnt2#5 = 0 cnt3#5 = 0 to:__start::@1 __start::@1: scope:[__start] from __start::__init1 cnt3#16 = phi( __start::__init1/cnt3#5 ) cnt2#16 = phi( __start::__init1/cnt2#5 ) cnt#17 = phi( __start::__init1/cnt#6 ) call main to:__start::@2 __start::@2: scope:[__start] from __start::@1 cnt3#13 = phi( __start::@1/cnt3#2 ) cnt2#13 = phi( __start::@1/cnt2#2 ) cnt#14 = phi( __start::@1/cnt#3 ) cnt#7 = cnt#14 cnt2#6 = cnt2#13 cnt3#6 = cnt3#13 to:__start::@return __start::@return: scope:[__start] from __start::@2 cnt3#14 = phi( __start::@2/cnt3#6 ) cnt2#14 = phi( __start::@2/cnt2#6 ) cnt#15 = phi( __start::@2/cnt#7 ) cnt#8 = cnt#15 cnt2#7 = cnt2#14 cnt3#7 = cnt3#14 return to:@return SYMBOL TABLE SSA __constant char SCREEN[$100] = (char *)$400 void __start() char cnt char cnt#0 char cnt#1 char cnt#10 char cnt#11 char cnt#12 char cnt#13 char cnt#14 char cnt#15 char cnt#16 char cnt#17 char cnt#2 char cnt#3 char cnt#4 char cnt#5 char cnt#6 char cnt#7 char cnt#8 char cnt#9 char cnt2 char cnt2#0 char cnt2#1 char cnt2#10 char cnt2#11 char cnt2#12 char cnt2#13 char cnt2#14 char cnt2#15 char cnt2#16 char cnt2#2 char cnt2#3 char cnt2#4 char cnt2#5 char cnt2#6 char cnt2#7 char cnt2#8 char cnt2#9 char cnt3 char cnt3#0 char cnt3#1 char cnt3#10 char cnt3#11 char cnt3#12 char cnt3#13 char cnt3#14 char cnt3#15 char cnt3#16 char cnt3#2 char cnt3#3 char cnt3#4 char cnt3#5 char cnt3#6 char cnt3#7 char cnt3#8 char cnt3#9 char inccnt() char inccnt::return char inccnt::return#0 char inccnt::return#1 char inccnt::return#2 char inccnt::return#3 char inccnt::return#4 char inccnt::return#5 char inccnt::return#6 void main() char main::$0 char main::$1 Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0 Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1 Adding number conversion cast (unumber) 2 in SCREEN[2] = cnt2#1 Adding number conversion cast (unumber) 3 in SCREEN[3] = cnt3#1 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant pointer cast (char *) 1024 Simplifying constant integer cast 0 Simplifying constant integer cast 1 Simplifying constant integer cast 2 Simplifying constant integer cast 3 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (char) 0 Finalized unsigned number type (char) 1 Finalized unsigned number type (char) 2 Finalized unsigned number type (char) 3 Successful SSA optimization PassNFinalizeNumberTypeConversions Alias inccnt::return#0 = inccnt::return#4 Alias cnt#0 = cnt#9 Alias cnt2#0 = cnt2#8 Alias cnt3#0 = cnt3#8 Alias inccnt::return#1 = inccnt::return#5 Alias cnt#10 = cnt#2 cnt#11 cnt#3 Alias cnt2#1 = cnt2#9 cnt2#10 cnt2#2 Alias cnt3#1 = cnt3#9 cnt3#10 cnt3#2 Alias inccnt::return#2 = inccnt::return#6 inccnt::return#3 Alias cnt#13 = cnt#4 cnt#5 Alias cnt2#12 = cnt2#3 cnt2#4 Alias cnt3#12 = cnt3#3 cnt3#4 Alias cnt#17 = cnt#6 Alias cnt2#16 = cnt2#5 Alias cnt3#16 = cnt3#5 Alias cnt#14 = cnt#7 cnt#15 cnt#8 Alias cnt2#13 = cnt2#6 cnt2#14 cnt2#7 Alias cnt3#13 = cnt3#6 cnt3#14 cnt3#7 Successful SSA optimization Pass2AliasElimination Identical Phi Values cnt#16 cnt#17 Identical Phi Values cnt2#15 cnt2#16 Identical Phi Values cnt3#15 cnt3#16 Identical Phi Values cnt#0 cnt#13 Identical Phi Values cnt2#0 cnt2#12 Identical Phi Values cnt3#0 cnt3#12 Identical Phi Values cnt#10 cnt#13 Identical Phi Values cnt2#1 cnt2#12 Identical Phi Values cnt3#1 cnt3#12 Identical Phi Values cnt#14 cnt#10 Identical Phi Values cnt2#13 cnt2#1 Identical Phi Values cnt3#13 cnt3#1 Successful SSA optimization Pass2IdenticalPhiElimination Constant cnt#17 = 0 Constant cnt2#16 = 0 Constant cnt3#16 = 0 Successful SSA optimization Pass2ConstantIdentification Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0 Successful SSA optimization PassNSimplifyExpressionWithZero Removing unused procedure __start Removing unused procedure block __start Removing unused procedure block __start::__init1 Removing unused procedure block __start::@1 Removing unused procedure block __start::@2 Removing unused procedure block __start::@return Successful SSA optimization PassNEliminateEmptyStart Inlining constant with var siblings cnt#17 Inlining constant with var siblings cnt2#16 Inlining constant with var siblings cnt3#16 Constant inlined cnt2#16 = 0 Constant inlined cnt3#16 = 0 Constant inlined cnt#17 = 0 Successful SSA optimization Pass2ConstantInlining Consolidated array index constant in *(SCREEN+1) Consolidated array index constant in *(SCREEN+2) Consolidated array index constant in *(SCREEN+3) Successful SSA optimization Pass2ConstantAdditionElimination Finalized unsigned number type (unsigned int) $100 Successful SSA optimization PassNFinalizeNumberTypeConversions Adding NOP phi() at start of main CALL GRAPH Calls in [main] to inccnt:1 inccnt:9 Created 3 initial phi equivalence classes Coalesced [6] cnt#18 = cnt#1 Coalesced [7] cnt2#17 = cnt2#12 Coalesced [8] cnt3#17 = cnt3#12 Coalesced down to 3 phi equivalence classes Adding NOP phi() at start of main FINAL CONTROL FLOW GRAPH void main() main: scope:[main] from [0] phi() [1] call inccnt [2] inccnt::return#0 = inccnt::return#2 to:main::@1 main::@1: scope:[main] from main [3] main::$0 = inccnt::return#0 [4] *SCREEN = main::$0 [5] cnt#1 = ++ cnt#13 [6] call inccnt [7] inccnt::return#1 = inccnt::return#2 to:main::@2 main::@2: scope:[main] from main::@1 [8] main::$1 = inccnt::return#1 [9] *(SCREEN+1) = main::$1 [10] *(SCREEN+2) = cnt2#12 [11] *(SCREEN+3) = cnt3#12 to:main::@return main::@return: scope:[main] from main::@2 [12] return to:@return char inccnt() inccnt: scope:[inccnt] from main main::@1 [13] cnt3#11 = phi( main/0, main::@1/cnt3#12 ) [13] cnt2#11 = phi( main/0, main::@1/cnt2#12 ) [13] cnt#12 = phi( main/0, main::@1/cnt#1 ) [14] cnt#13 = ++ cnt#12 [15] cnt2#12 = ++ cnt2#11 [16] cnt3#12 = ++ cnt3#11 [17] inccnt::return#2 = cnt#13 to:inccnt::@return inccnt::@return: scope:[inccnt] from inccnt [18] return to:@return VARIABLE REGISTER WEIGHTS char cnt char cnt#1 // 4.0 char cnt#12 // 13.0 char cnt#13 // 2.666666666666667 char cnt2 char cnt2#11 // 6.5 char cnt2#12 // 1.1538461538461537 char cnt3 char cnt3#11 // 4.333333333333333 char cnt3#12 // 1.1538461538461537 char inccnt() char inccnt::return char inccnt::return#0 // 4.0 char inccnt::return#1 // 4.0 char inccnt::return#2 // 3.75 void main() char main::$0 // 4.0 char main::$1 // 4.0 Initial phi equivalence classes [ cnt#12 cnt#1 ] [ cnt2#11 cnt2#12 ] [ cnt3#11 cnt3#12 ] Added variable inccnt::return#0 to live range equivalence class [ inccnt::return#0 ] Added variable main::$0 to live range equivalence class [ main::$0 ] Added variable inccnt::return#1 to live range equivalence class [ inccnt::return#1 ] Added variable main::$1 to live range equivalence class [ main::$1 ] Added variable cnt#13 to live range equivalence class [ cnt#13 ] Added variable inccnt::return#2 to live range equivalence class [ inccnt::return#2 ] Complete equivalence classes [ cnt#12 cnt#1 ] [ cnt2#11 cnt2#12 ] [ cnt3#11 cnt3#12 ] [ inccnt::return#0 ] [ main::$0 ] [ inccnt::return#1 ] [ main::$1 ] [ cnt#13 ] [ inccnt::return#2 ] Allocated zp[1]:2 [ cnt#12 cnt#1 ] Allocated zp[1]:3 [ cnt2#11 cnt2#12 ] Allocated zp[1]:4 [ cnt3#11 cnt3#12 ] Allocated zp[1]:5 [ inccnt::return#0 ] Allocated zp[1]:6 [ main::$0 ] Allocated zp[1]:7 [ inccnt::return#1 ] Allocated zp[1]:8 [ main::$1 ] Allocated zp[1]:9 [ inccnt::return#2 ] Allocated zp[1]:10 [ cnt#13 ] REGISTER UPLIFT POTENTIAL REGISTERS Potential registers zp[1]:2 [ cnt#12 cnt#1 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:3 [ cnt2#11 cnt2#12 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:4 [ cnt3#11 cnt3#12 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:5 [ inccnt::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:6 [ main::$0 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:7 [ inccnt::return#1 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:8 [ main::$1 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:10 [ cnt#13 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y , Potential registers zp[1]:9 [ inccnt::return#2 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES Uplift Scope [] 17: zp[1]:2 [ cnt#12 cnt#1 ] 7.65: zp[1]:3 [ cnt2#11 cnt2#12 ] 5.49: zp[1]:4 [ cnt3#11 cnt3#12 ] 2.67: zp[1]:10 [ cnt#13 ] Uplift Scope [inccnt] 4: zp[1]:5 [ inccnt::return#0 ] 4: zp[1]:7 [ inccnt::return#1 ] 3.75: zp[1]:9 [ inccnt::return#2 ] Uplift Scope [main] 4: zp[1]:6 [ main::$0 ] 4: zp[1]:8 [ main::$1 ] Uplifting [] best 112 combination reg byte a [ cnt#12 cnt#1 ] reg byte y [ cnt2#11 cnt2#12 ] reg byte x [ cnt3#11 cnt3#12 ] zp[1]:10 [ cnt#13 ] Limited combination testing to 100 combinations of 256 possible. Uplifting [inccnt] best 91 combination reg byte a [ inccnt::return#0 ] reg byte a [ inccnt::return#1 ] reg byte a [ inccnt::return#2 ] Uplifting [main] best 79 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ] Attempting to uplift remaining variables inzp[1]:10 [ cnt#13 ] Uplifting [] best 79 combination zp[1]:10 [ cnt#13 ] Allocated (was zp[1]:10) zp[1]:2 [ cnt#13 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Upstart // Commodore 64 PRG executable file .file [name="modglobal.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 .label SCREEN = $400 .label cnt = 2 .segment Code // main main: { // [1] call inccnt // [13] phi from main to inccnt [phi:main->inccnt] inccnt_from_main: // [13] phi cnt3#11 = 0 [phi:main->inccnt#0] -- vbuxx=vbuc1 ldx #0 // [13] phi cnt2#11 = 0 [phi:main->inccnt#1] -- vbuyy=vbuc1 ldy #0 // [13] phi cnt#12 = 0 [phi:main->inccnt#2] -- vbuaa=vbuc1 lda #0 jsr inccnt // [2] inccnt::return#0 = inccnt::return#2 jmp __b1 // main::@1 __b1: // [3] main::$0 = inccnt::return#0 // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa sta SCREEN // [5] cnt#1 = ++ cnt#13 -- vbuaa=_inc_vbuz1 lda.z cnt clc adc #1 // [6] call inccnt // [13] phi from main::@1 to inccnt [phi:main::@1->inccnt] inccnt_from___b1: // [13] phi cnt3#11 = cnt3#12 [phi:main::@1->inccnt#0] -- register_copy // [13] phi cnt2#11 = cnt2#12 [phi:main::@1->inccnt#1] -- register_copy // [13] phi cnt#12 = cnt#1 [phi:main::@1->inccnt#2] -- register_copy jsr inccnt // [7] inccnt::return#1 = inccnt::return#2 jmp __b2 // main::@2 __b2: // [8] main::$1 = inccnt::return#1 // [9] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa sta SCREEN+1 // [10] *(SCREEN+2) = cnt2#12 -- _deref_pbuc1=vbuyy sty SCREEN+2 // [11] *(SCREEN+3) = cnt3#12 -- _deref_pbuc1=vbuxx stx SCREEN+3 jmp __breturn // main::@return __breturn: // [12] return rts } // inccnt inccnt: { // [14] cnt#13 = ++ cnt#12 -- vbuz1=_inc_vbuaa clc adc #1 sta.z cnt // [15] cnt2#12 = ++ cnt2#11 -- vbuyy=_inc_vbuyy iny // [16] cnt3#12 = ++ cnt3#11 -- vbuxx=_inc_vbuxx inx // [17] inccnt::return#2 = cnt#13 -- vbuaa=vbuz1 lda.z cnt jmp __breturn // inccnt::@return __breturn: // [18] return rts } // File Data ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 Removing instruction jmp __b2 Removing instruction jmp __breturn Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination Replacing instruction lda #0 with TXA Removing instruction lda.z cnt Succesful ASM optimization Pass5UnnecesaryLoadElimination Removing instruction inccnt_from_main: Removing instruction __b1: Removing instruction inccnt_from___b1: Removing instruction __b2: Removing instruction __breturn: Removing instruction __breturn: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE __constant char SCREEN[$100] = (char *) 1024 char cnt char cnt#1 // reg byte a 4.0 char cnt#12 // reg byte a 13.0 char cnt#13 // cnt zp[1]:2 2.666666666666667 char cnt2 char cnt2#11 // reg byte y 6.5 char cnt2#12 // reg byte y 1.1538461538461537 char cnt3 char cnt3#11 // reg byte x 4.333333333333333 char cnt3#12 // reg byte x 1.1538461538461537 char inccnt() char inccnt::return char inccnt::return#0 // reg byte a 4.0 char inccnt::return#1 // reg byte a 4.0 char inccnt::return#2 // reg byte a 3.75 void main() char main::$0 // reg byte a 4.0 char main::$1 // reg byte a 4.0 reg byte a [ cnt#12 cnt#1 ] reg byte y [ cnt2#11 cnt2#12 ] reg byte x [ cnt3#11 cnt3#12 ] reg byte a [ inccnt::return#0 ] reg byte a [ main::$0 ] reg byte a [ inccnt::return#1 ] reg byte a [ main::$1 ] zp[1]:2 [ cnt#13 ] reg byte a [ inccnt::return#2 ] FINAL ASSEMBLER Score: 64 // File Comments // Upstart // Commodore 64 PRG executable file .file [name="modglobal.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 .label SCREEN = $400 .label cnt = 2 .segment Code // main main: { // inccnt() // [1] call inccnt // [13] phi from main to inccnt [phi:main->inccnt] // [13] phi cnt3#11 = 0 [phi:main->inccnt#0] -- vbuxx=vbuc1 ldx #0 // [13] phi cnt2#11 = 0 [phi:main->inccnt#1] -- vbuyy=vbuc1 ldy #0 // [13] phi cnt#12 = 0 [phi:main->inccnt#2] -- vbuaa=vbuc1 txa jsr inccnt // inccnt() // [2] inccnt::return#0 = inccnt::return#2 // main::@1 // [3] main::$0 = inccnt::return#0 // SCREEN[0]=inccnt() // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa sta SCREEN // cnt++; // [5] cnt#1 = ++ cnt#13 -- vbuaa=_inc_vbuz1 lda.z cnt clc adc #1 // inccnt() // [6] call inccnt // [13] phi from main::@1 to inccnt [phi:main::@1->inccnt] // [13] phi cnt3#11 = cnt3#12 [phi:main::@1->inccnt#0] -- register_copy // [13] phi cnt2#11 = cnt2#12 [phi:main::@1->inccnt#1] -- register_copy // [13] phi cnt#12 = cnt#1 [phi:main::@1->inccnt#2] -- register_copy jsr inccnt // inccnt() // [7] inccnt::return#1 = inccnt::return#2 // main::@2 // [8] main::$1 = inccnt::return#1 // SCREEN[1]=inccnt() // [9] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa sta SCREEN+1 // SCREEN[2]=cnt2 // [10] *(SCREEN+2) = cnt2#12 -- _deref_pbuc1=vbuyy sty SCREEN+2 // SCREEN[3]=cnt3 // [11] *(SCREEN+3) = cnt3#12 -- _deref_pbuc1=vbuxx stx SCREEN+3 // main::@return // } // [12] return rts } // inccnt inccnt: { // ++cnt; // [14] cnt#13 = ++ cnt#12 -- vbuz1=_inc_vbuaa clc adc #1 sta.z cnt // ++cnt2; // [15] cnt2#12 = ++ cnt2#11 -- vbuyy=_inc_vbuyy iny // ++cnt3; // [16] cnt3#12 = ++ cnt3#11 -- vbuxx=_inc_vbuxx inx // return cnt; // [17] inccnt::return#2 = cnt#13 -- vbuaa=vbuz1 // inccnt::@return // } // [18] return rts } // File Data