Setting inferred volatile on symbol affected by address-of: fn1::param_char in asm { pla staparam_char } Setting inferred volatile on symbol affected by address-of: fn2::param_char in asm { pla staparam_char } Setting inferred volatile on symbol affected by address-of: main::param_char in asm { ldaparam_char pha } Inlined call call __init Calling convention STACK_CALL adding prepare/execute/finalize for call *main::f CONTROL FLOW GRAPH SSA void fn1() fn1: scope:[fn1] from fn1::ret_addr = 0 fn1::param_char = 0 asm { pla staret_addr pla staret_addr+1 } asm { pla staparam_char } fn1::b#0 = fn1::param_char asm { pla staparam_char } fn1::c#0 = fn1::param_char asm { ldaret_addr+1 pha ldaret_addr pha } SCREEN1[idx1] = fn1::b#0 idx1 = ++ idx1 SCREEN1[idx1] = fn1::c#0 idx1 = ++ idx1 to:fn1::@return fn1::@return: scope:[fn1] from fn1 return to:@return void fn2() fn2: scope:[fn2] from fn2::ret_addr = 0 fn2::param_char = 0 asm { pla staret_addr pla staret_addr+1 } asm { pla staparam_char } fn2::b#0 = fn2::param_char asm { pla staparam_char } fn2::c#0 = fn2::param_char asm { ldaret_addr+1 pha ldaret_addr pha } SCREEN2[idx2] = fn2::b#0 idx2 = ++ idx2 SCREEN2[idx2] = fn2::c#0 idx2 = ++ idx2 to:fn2::@return fn2::@return: scope:[fn2] from fn2 return to:@return void main() main: scope:[main] from __start::@1 main::i#0 = 'a' to:main::@1 main::@1: scope:[main] from main main::@5 main::i#2 = phi( main/main::i#0, main::@5/main::i#1 ) main::$0 = main::i#2 <= 'p' if(main::$0) goto main::@2 to:main::@return main::@2: scope:[main] from main::@1 main::i#6 = phi( main::@1/main::i#2 ) main::j#0 = 0 to:main::@3 main::@3: scope:[main] from main::@2 main::@6 main::i#5 = phi( main::@2/main::i#6, main::@6/main::i#7 ) main::j#2 = phi( main::@2/main::j#0, main::@6/main::j#1 ) main::$1 = main::j#2 < 2 if(main::$1) goto main::@4 to:main::@5 main::@4: scope:[main] from main::@3 main::j#3 = phi( main::@3/main::j#2 ) main::i#3 = phi( main::@3/main::i#5 ) main::param_char = 0 main::param_char = main::i#3 asm { ldaparam_char pha } main::param_char = main::j#3 asm { ldaparam_char pha } main::$3 = main::j#3 * SIZEOF_POINTER main::f#0 = main::fns[main::$3] callexecute *main::f#0 to:main::@6 main::@5: scope:[main] from main::@3 main::i#4 = phi( main::@3/main::i#5 ) main::i#1 = ++ main::i#4 to:main::@1 main::@6: scope:[main] from main::@4 main::i#7 = phi( main::@4/main::i#3 ) main::j#4 = phi( main::@4/main::j#3 ) main::j#1 = ++ main::j#4 to:main::@3 main::@return: scope:[main] from main::@1 return to:@return void __start() __start: scope:[__start] from to:__start::__init1 __start::__init1: scope:[__start] from __start idx1 = 0 idx2 = 0 to:__start::@1 __start::@1: scope:[__start] from __start::__init1 call main to:__start::@2 __start::@2: scope:[__start] from __start::@1 to:__start::@return __start::@return: scope:[__start] from __start::@2 return to:@return SYMBOL TABLE SSA __constant char * const SCREEN1 = (char *)$400 __constant char * const SCREEN2 = (char *)$428 __constant char SIZEOF_POINTER = 2 void __start() void fn1() char fn1::b char fn1::b#0 char fn1::c char fn1::c#0 __loadstore volatile char fn1::param_char __loadstore volatile unsigned int fn1::ret_addr void fn2() char fn2::b char fn2::b#0 char fn2::c char fn2::c#0 __loadstore volatile char fn2::param_char __loadstore volatile unsigned int fn2::ret_addr __loadstore volatile char idx1 __loadstore volatile char idx2 void main() bool main::$0 bool main::$1 char main::$3 void (*main::f)() void (*main::f#0)() __constant void (*main::fns[2])() = { &fn1, &fn2 } char main::i char main::i#0 char main::i#1 char main::i#2 char main::i#3 char main::i#4 char main::i#5 char main::i#6 char main::i#7 char main::j char main::j#0 char main::j#1 char main::j#2 char main::j#3 char main::j#4 __loadstore volatile char main::param_char Adding number conversion cast (unumber) 2 in main::$1 = main::j#2 < 2 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant pointer cast (char *) 1024 Simplifying constant pointer cast (char *) 1064 Simplifying constant integer cast 2 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (char) 2 Successful SSA optimization PassNFinalizeNumberTypeConversions Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#3 = main::i#5 main::param_char main::j#3 main::j#2 main::i#4 main::j#4 main::i#7 Alias main::i#2 = main::i#6 Successful SSA optimization Pass2AliasElimination Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#3 = main::i#5 main::param_char main::j#3 main::j#2 main::i#4 main::j#4 main::i#7 Identical Phi Values main::i#3 main::i#5 Identical Phi Values main::j#3 main::j#2 Identical Phi Values main::i#4 main::i#5 Identical Phi Values main::j#4 main::j#3 Identical Phi Values main::i#7 main::i#3 Successful SSA optimization Pass2IdenticalPhiElimination Identical Phi Values main::i#5 main::i#2 Successful SSA optimization Pass2IdenticalPhiElimination Simple Condition main::$0 [29] if(main::i#2<='p') goto main::@2 Simple Condition main::$1 [33] if(main::j#2<2) goto main::@4 Successful SSA optimization Pass2ConditionalJumpSimplification Constant main::i#0 = 'a' Constant main::j#0 = 0 Successful SSA optimization Pass2ConstantIdentification Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#2 = main::param_char main::j#2 Rewriting multiplication to use shift [35] main::$3 = main::j#2 * SIZEOF_POINTER Successful SSA optimization Pass2MultiplyToShiftRewriting Inlining constant with var siblings main::i#0 Inlining constant with var siblings main::j#0 Constant inlined main::i#0 = 'a' Constant inlined main::j#0 = 0 Successful SSA optimization Pass2ConstantInlining Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#2 = main::param_char main::j#2 Eliminating unused constant SIZEOF_POINTER Successful SSA optimization PassNEliminateUnusedVars Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#2 = main::param_char main::j#2 Finalized unsigned number type (char) 2 Successful SSA optimization PassNFinalizeNumberTypeConversions Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#2 = main::param_char main::j#2 Alias candidate removed (volatile)fn1::b#0 = fn1::param_char fn1::c#0 Alias candidate removed (volatile)fn2::b#0 = fn2::param_char fn2::c#0 Alias candidate removed (volatile)main::i#2 = main::param_char main::j#2 Adding NOP phi() at start of __start Adding NOP phi() at start of __start::@1 Adding NOP phi() at start of __start::@2 Adding NOP phi() at start of main Adding NOP phi() at start of main::@2 CALL GRAPH Calls in [__start] to main:4 Calls in [main] to null:49 Created 2 initial phi equivalence classes Coalesced [41] main::i#8 = main::i#1 Coalesced [51] main::j#5 = main::j#1 Coalesced down to 2 phi equivalence classes Culled Empty Block label __start::@2 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 Renumbering block main::@6 to main::@5 Adding NOP phi() at start of __start Adding NOP phi() at start of __start::@1 Adding NOP phi() at start of main FINAL CONTROL FLOW GRAPH void __start() __start: scope:[__start] from [0] phi() to:__start::__init1 __start::__init1: scope:[__start] from __start [1] idx1 = 0 [2] idx2 = 0 to:__start::@1 __start::@1: scope:[__start] from __start::__init1 [3] phi() [4] call main to:__start::@return __start::@return: scope:[__start] from __start::@1 [5] return to:@return void fn2() fn2: scope:[fn2] from [6] fn2::ret_addr = 0 [7] fn2::param_char = 0 asm { pla staret_addr pla staret_addr+1 } asm { pla staparam_char } [10] fn2::b#0 = fn2::param_char asm { pla staparam_char } [12] fn2::c#0 = fn2::param_char asm { ldaret_addr+1 pha ldaret_addr pha } [14] SCREEN2[idx2] = fn2::b#0 [15] idx2 = ++ idx2 [16] SCREEN2[idx2] = fn2::c#0 [17] idx2 = ++ idx2 to:fn2::@return fn2::@return: scope:[fn2] from fn2 [18] return to:@return void fn1() fn1: scope:[fn1] from [19] fn1::ret_addr = 0 [20] fn1::param_char = 0 asm { pla staret_addr pla staret_addr+1 } asm { pla staparam_char } [23] fn1::b#0 = fn1::param_char asm { pla staparam_char } [25] fn1::c#0 = fn1::param_char asm { ldaret_addr+1 pha ldaret_addr pha } [27] SCREEN1[idx1] = fn1::b#0 [28] idx1 = ++ idx1 [29] SCREEN1[idx1] = fn1::c#0 [30] idx1 = ++ idx1 to:fn1::@return fn1::@return: scope:[fn1] from fn1 [31] return to:@return void main() main: scope:[main] from __start::@1 [32] phi() to:main::@1 main::@1: scope:[main] from main main::@4 [33] main::i#2 = phi( main/'a', main::@4/main::i#1 ) [34] if(main::i#2<='p') goto main::@2 to:main::@return main::@return: scope:[main] from main::@1 [35] return to:@return main::@2: scope:[main] from main::@1 main::@5 [36] main::j#2 = phi( main::@1/0, main::@5/main::j#1 ) [37] if(main::j#2<2) goto main::@3 to:main::@4 main::@4: scope:[main] from main::@2 [38] main::i#1 = ++ main::i#2 to:main::@1 main::@3: scope:[main] from main::@2 [39] main::param_char = 0 [40] main::param_char = main::i#2 asm { ldaparam_char pha } [42] main::param_char = main::j#2 asm { ldaparam_char pha } [44] main::$3 = main::j#2 << 1 [45] main::f#0 = main::fns[main::$3] [46] callexecute *main::f#0 to:main::@5 main::@5: scope:[main] from main::@3 [47] main::j#1 = ++ main::j#2 to:main::@2 VARIABLE REGISTER WEIGHTS void __start() void fn1() char fn1::b char fn1::b#0 // 1.0 char fn1::c char fn1::c#0 // 1.0 __loadstore volatile char fn1::param_char // 1.2000000000000002 __loadstore volatile unsigned int fn1::ret_addr // 0.2857142857142857 void fn2() char fn2::b char fn2::b#0 // 1.0 char fn2::c char fn2::c#0 // 1.0 __loadstore volatile char fn2::param_char // 1.2000000000000002 __loadstore volatile unsigned int fn2::ret_addr // 0.2857142857142857 __loadstore volatile char idx1 // 1.272727272727273 __loadstore volatile char idx2 // 1.272727272727273 void main() char main::$3 // 2002.0 void (*main::f)() void (*main::f#0)() // 10010.0 char main::i char main::i#1 // 202.0 char main::i#2 // 186.28571428571428 char main::j char main::j#1 // 2002.0 char main::j#2 // 625.625 __loadstore volatile char main::param_char // 1501.5 Initial phi equivalence classes [ main::i#2 main::i#1 ] [ main::j#2 main::j#1 ] Added variable idx1 to live range equivalence class [ idx1 ] Added variable idx2 to live range equivalence class [ idx2 ] Added variable fn2::ret_addr to live range equivalence class [ fn2::ret_addr ] Added variable fn2::param_char to live range equivalence class [ fn2::param_char ] Added variable fn2::b#0 to live range equivalence class [ fn2::b#0 ] Added variable fn2::c#0 to live range equivalence class [ fn2::c#0 ] Added variable fn1::ret_addr to live range equivalence class [ fn1::ret_addr ] Added variable fn1::param_char to live range equivalence class [ fn1::param_char ] Added variable fn1::b#0 to live range equivalence class [ fn1::b#0 ] Added variable fn1::c#0 to live range equivalence class [ fn1::c#0 ] Added variable main::param_char to live range equivalence class [ main::param_char ] Added variable main::$3 to live range equivalence class [ main::$3 ] Added variable main::f#0 to live range equivalence class [ main::f#0 ] Complete equivalence classes [ main::i#2 main::i#1 ] [ main::j#2 main::j#1 ] [ idx1 ] [ idx2 ] [ fn2::ret_addr ] [ fn2::param_char ] [ fn2::b#0 ] [ fn2::c#0 ] [ fn1::ret_addr ] [ fn1::param_char ] [ fn1::b#0 ] [ fn1::c#0 ] [ main::param_char ] [ main::$3 ] [ main::f#0 ] Allocated zp[2]:2 [ main::f#0 ] Allocated zp[1]:4 [ main::j#2 main::j#1 ] Allocated zp[1]:5 [ main::$3 ] Allocated zp[1]:6 [ main::param_char ] Allocated zp[1]:7 [ main::i#2 main::i#1 ] Allocated zp[1]:8 [ idx1 ] Allocated zp[1]:9 [ idx2 ] Allocated zp[1]:10 [ fn2::param_char ] Allocated zp[1]:11 [ fn1::param_char ] Allocated zp[1]:12 [ fn2::b#0 ] Allocated zp[1]:13 [ fn2::c#0 ] Allocated zp[1]:14 [ fn1::b#0 ] Allocated zp[1]:15 [ fn1::c#0 ] Allocated zp[2]:16 [ fn2::ret_addr ] Allocated zp[2]:18 [ fn1::ret_addr ] REGISTER UPLIFT POTENTIAL REGISTERS Statement [1] idx1 = 0 [ ] ( [ ] { } ) always clobbers reg byte a Statement [2] idx2 = 0 [ ] ( [ ] { } ) always clobbers reg byte a Statement [6] fn2::ret_addr = 0 [ idx2 fn2::ret_addr ] ( [ idx2 fn2::ret_addr ] { } ) always clobbers reg byte a Statement [7] fn2::param_char = 0 [ idx2 fn2::ret_addr fn2::param_char ] ( [ idx2 fn2::ret_addr fn2::param_char ] { } ) always clobbers reg byte a Statement asm { pla staret_addr pla staret_addr+1 } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:12 [ fn2::b#0 ] Statement asm { ldaret_addr+1 pha ldaret_addr pha } always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:13 [ fn2::c#0 ] Statement [14] SCREEN2[idx2] = fn2::b#0 [ idx2 fn2::c#0 ] ( [ idx2 fn2::c#0 ] { } ) always clobbers reg byte a reg byte y Removing always clobbered register reg byte y as potential for zp[1]:13 [ fn2::c#0 ] Statement [16] SCREEN2[idx2] = fn2::c#0 [ idx2 ] ( [ idx2 ] { } ) always clobbers reg byte a reg byte y Statement [19] fn1::ret_addr = 0 [ idx1 fn1::ret_addr ] ( [ idx1 fn1::ret_addr ] { } ) always clobbers reg byte a Statement [20] fn1::param_char = 0 [ idx1 fn1::ret_addr fn1::param_char ] ( [ idx1 fn1::ret_addr fn1::param_char ] { } ) always clobbers reg byte a Statement asm { pla staret_addr pla staret_addr+1 } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:14 [ fn1::b#0 ] Statement asm { ldaret_addr+1 pha ldaret_addr pha } always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:15 [ fn1::c#0 ] Statement [27] SCREEN1[idx1] = fn1::b#0 [ idx1 fn1::c#0 ] ( [ idx1 fn1::c#0 ] { } ) always clobbers reg byte a reg byte y Removing always clobbered register reg byte y as potential for zp[1]:15 [ fn1::c#0 ] Statement [29] SCREEN1[idx1] = fn1::c#0 [ idx1 ] ( [ idx1 ] { } ) always clobbers reg byte a reg byte y Statement [39] main::param_char = 0 [ main::i#2 main::j#2 ] ( main:4 [ main::i#2 main::j#2 ] { } ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp[1]:7 [ main::i#2 main::i#1 ] Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::j#2 main::j#1 ] Statement asm { ldaparam_char pha } always clobbers reg byte a Statement asm { ldaparam_char pha } always clobbers reg byte a Statement [44] main::$3 = main::j#2 << 1 [ main::$3 ] ( main:4 [ main::$3 ] { } ) always clobbers reg byte a Statement [45] main::f#0 = main::fns[main::$3] [ ] ( main:4 [ ] { } ) always clobbers reg byte a Statement [46] callexecute *main::f#0 [ main::i#2 main::j#2 ] ( main:4 [ main::i#2 main::j#2 ] { } ) always clobbers reg byte a reg byte x reg byte y Removing always clobbered register reg byte x as potential for zp[1]:7 [ main::i#2 main::i#1 ] Removing always clobbered register reg byte y as potential for zp[1]:7 [ main::i#2 main::i#1 ] Removing always clobbered register reg byte x as potential for zp[1]:4 [ main::j#2 main::j#1 ] Removing always clobbered register reg byte y as potential for zp[1]:4 [ main::j#2 main::j#1 ] Statement [1] idx1 = 0 [ ] ( [ ] { } ) always clobbers reg byte a Statement [2] idx2 = 0 [ ] ( [ ] { } ) always clobbers reg byte a Statement [6] fn2::ret_addr = 0 [ idx2 fn2::ret_addr ] ( [ idx2 fn2::ret_addr ] { } ) always clobbers reg byte a Statement [7] fn2::param_char = 0 [ idx2 fn2::ret_addr fn2::param_char ] ( [ idx2 fn2::ret_addr fn2::param_char ] { } ) always clobbers reg byte a Statement asm { pla staret_addr pla staret_addr+1 } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Statement asm { ldaret_addr+1 pha ldaret_addr pha } always clobbers reg byte a Statement [14] SCREEN2[idx2] = fn2::b#0 [ idx2 fn2::c#0 ] ( [ idx2 fn2::c#0 ] { } ) always clobbers reg byte a reg byte y Statement [16] SCREEN2[idx2] = fn2::c#0 [ idx2 ] ( [ idx2 ] { } ) always clobbers reg byte a reg byte y Statement [19] fn1::ret_addr = 0 [ idx1 fn1::ret_addr ] ( [ idx1 fn1::ret_addr ] { } ) always clobbers reg byte a Statement [20] fn1::param_char = 0 [ idx1 fn1::ret_addr fn1::param_char ] ( [ idx1 fn1::ret_addr fn1::param_char ] { } ) always clobbers reg byte a Statement asm { pla staret_addr pla staret_addr+1 } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Statement asm { pla staparam_char } always clobbers reg byte a Statement asm { ldaret_addr+1 pha ldaret_addr pha } always clobbers reg byte a Statement [27] SCREEN1[idx1] = fn1::b#0 [ idx1 fn1::c#0 ] ( [ idx1 fn1::c#0 ] { } ) always clobbers reg byte a reg byte y Statement [29] SCREEN1[idx1] = fn1::c#0 [ idx1 ] ( [ idx1 ] { } ) always clobbers reg byte a reg byte y Statement [34] if(main::i#2<='p') goto main::@2 [ main::i#2 ] ( main:4 [ main::i#2 ] { } ) always clobbers reg byte a Statement [37] if(main::j#2<2) goto main::@3 [ main::i#2 main::j#2 ] ( main:4 [ main::i#2 main::j#2 ] { } ) always clobbers reg byte a Statement [39] main::param_char = 0 [ main::i#2 main::j#2 ] ( main:4 [ main::i#2 main::j#2 ] { } ) always clobbers reg byte a Statement [40] main::param_char = main::i#2 [ main::j#2 main::param_char ] ( main:4 [ main::j#2 main::param_char ] { } ) always clobbers reg byte a Statement asm { ldaparam_char pha } always clobbers reg byte a Statement [42] main::param_char = main::j#2 [ main::j#2 main::param_char ] ( main:4 [ main::j#2 main::param_char ] { } ) always clobbers reg byte a Statement asm { ldaparam_char pha } always clobbers reg byte a Statement [44] main::$3 = main::j#2 << 1 [ main::$3 ] ( main:4 [ main::$3 ] { } ) always clobbers reg byte a Statement [45] main::f#0 = main::fns[main::$3] [ ] ( main:4 [ ] { } ) always clobbers reg byte a Statement [46] callexecute *main::f#0 [ main::i#2 main::j#2 ] ( main:4 [ main::i#2 main::j#2 ] { } ) always clobbers reg byte a reg byte x reg byte y Potential registers zp[1]:7 [ main::i#2 main::i#1 ] : zp[1]:7 , Potential registers zp[1]:4 [ main::j#2 main::j#1 ] : zp[1]:4 , Potential registers zp[1]:8 [ idx1 ] : zp[1]:8 , Potential registers zp[1]:9 [ idx2 ] : zp[1]:9 , Potential registers zp[2]:16 [ fn2::ret_addr ] : zp[2]:16 , Potential registers zp[1]:10 [ fn2::param_char ] : zp[1]:10 , Potential registers zp[1]:12 [ fn2::b#0 ] : zp[1]:12 , reg byte x , reg byte y , Potential registers zp[1]:13 [ fn2::c#0 ] : zp[1]:13 , reg byte x , Potential registers zp[2]:18 [ fn1::ret_addr ] : zp[2]:18 , Potential registers zp[1]:11 [ fn1::param_char ] : zp[1]:11 , Potential registers zp[1]:14 [ fn1::b#0 ] : zp[1]:14 , reg byte x , reg byte y , Potential registers zp[1]:15 [ fn1::c#0 ] : zp[1]:15 , reg byte x , Potential registers zp[1]:6 [ main::param_char ] : zp[1]:6 , Potential registers zp[1]:5 [ main::$3 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y , Potential registers zp[2]:2 [ main::f#0 ] : zp[2]:2 , REGISTER UPLIFT SCOPES Uplift Scope [main] 10,010: zp[2]:2 [ main::f#0 ] 2,627.62: zp[1]:4 [ main::j#2 main::j#1 ] 2,002: zp[1]:5 [ main::$3 ] 1,501.5: zp[1]:6 [ main::param_char ] 388.29: zp[1]:7 [ main::i#2 main::i#1 ] Uplift Scope [fn1] 1.2: zp[1]:11 [ fn1::param_char ] 1: zp[1]:14 [ fn1::b#0 ] 1: zp[1]:15 [ fn1::c#0 ] 0.29: zp[2]:18 [ fn1::ret_addr ] Uplift Scope [fn2] 1.2: zp[1]:10 [ fn2::param_char ] 1: zp[1]:12 [ fn2::b#0 ] 1: zp[1]:13 [ fn2::c#0 ] 0.29: zp[2]:16 [ fn2::ret_addr ] Uplift Scope [] 1.27: zp[1]:8 [ idx1 ] 1.27: zp[1]:9 [ idx2 ] Uplift Scope [__start] Uplifting [main] best 9457 combination zp[2]:2 [ main::f#0 ] zp[1]:4 [ main::j#2 main::j#1 ] reg byte a [ main::$3 ] zp[1]:6 [ main::param_char ] zp[1]:7 [ main::i#2 main::i#1 ] Uplifting [fn1] best 9449 combination zp[1]:11 [ fn1::param_char ] reg byte y [ fn1::b#0 ] reg byte x [ fn1::c#0 ] zp[2]:18 [ fn1::ret_addr ] Uplifting [fn2] best 9441 combination zp[1]:10 [ fn2::param_char ] reg byte y [ fn2::b#0 ] reg byte x [ fn2::c#0 ] zp[2]:16 [ fn2::ret_addr ] Uplifting [] best 9441 combination zp[1]:8 [ idx1 ] zp[1]:9 [ idx2 ] Uplifting [__start] best 9441 combination Attempting to uplift remaining variables inzp[1]:4 [ main::j#2 main::j#1 ] Uplifting [main] best 9441 combination zp[1]:4 [ main::j#2 main::j#1 ] Attempting to uplift remaining variables inzp[1]:6 [ main::param_char ] Uplifting [main] best 9441 combination zp[1]:6 [ main::param_char ] Attempting to uplift remaining variables inzp[1]:7 [ main::i#2 main::i#1 ] Uplifting [main] best 9441 combination zp[1]:7 [ main::i#2 main::i#1 ] Attempting to uplift remaining variables inzp[1]:8 [ idx1 ] Uplifting [] best 9441 combination zp[1]:8 [ idx1 ] Attempting to uplift remaining variables inzp[1]:9 [ idx2 ] Uplifting [] best 9441 combination zp[1]:9 [ idx2 ] Attempting to uplift remaining variables inzp[1]:10 [ fn2::param_char ] Uplifting [fn2] best 9441 combination zp[1]:10 [ fn2::param_char ] Attempting to uplift remaining variables inzp[1]:11 [ fn1::param_char ] Uplifting [fn1] best 9441 combination zp[1]:11 [ fn1::param_char ] Allocated (was zp[1]:6) zp[1]:5 [ main::param_char ] Allocated (was zp[1]:7) zp[1]:6 [ main::i#2 main::i#1 ] Allocated (was zp[1]:8) zp[1]:7 [ idx1 ] Allocated (was zp[1]:9) zp[1]:8 [ idx2 ] Allocated (was zp[1]:10) zp[1]:9 [ fn2::param_char ] Allocated (was zp[1]:11) zp[1]:10 [ fn1::param_char ] Allocated (was zp[2]:16) zp[2]:11 [ fn2::ret_addr ] Allocated (was zp[2]:18) zp[2]:13 [ fn1::ret_addr ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Demonstrates work-around for passing parameters to function pointers // Save the return address, declare parameter variables // Restore the return address // Declare and pull a char parameter // Begin passing parameters using the stack. Declares parameter variables. // Pass a char parameter // Upstart // Commodore 64 PRG executable file .file [name="function-pointer-param-workaround.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(__start) // Global Constants & labels .label SCREEN1 = $400 .label SCREEN2 = $428 .label idx1 = 7 .label idx2 = 8 .segment Code // __start __start: { jmp __init1 // __start::__init1 __init1: // [1] idx1 = 0 -- vbuz1=vbuc1 lda #0 sta.z idx1 // [2] idx2 = 0 -- vbuz1=vbuc1 lda #0 sta.z idx2 // [3] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1] __b1_from___init1: jmp __b1 // __start::@1 __b1: // [4] call main // [32] phi from __start::@1 to main [phi:__start::@1->main] main_from___b1: jsr main jmp __breturn // __start::@return __breturn: // [5] return rts } // fn2 fn2: { .label ret_addr = $b .label param_char = 9 // [6] fn2::ret_addr = 0 -- vwuz1=vwuc1 lda #<0 sta.z ret_addr lda #>0 sta.z ret_addr+1 // [7] fn2::param_char = 0 -- vbuz1=vbuc1 lda #0 sta.z param_char // asm { pla staret_addr pla staret_addr+1 } pla sta ret_addr pla sta ret_addr+1 // asm { pla staparam_char } pla sta param_char // [10] fn2::b#0 = fn2::param_char -- vbuyy=vbuz1 ldy.z param_char // asm { pla staparam_char } pla sta param_char // [12] fn2::c#0 = fn2::param_char -- vbuxx=vbuz1 ldx.z param_char // asm { ldaret_addr+1 pha ldaret_addr pha } lda ret_addr+1 pha lda ret_addr pha // [14] SCREEN2[idx2] = fn2::b#0 -- pbuc1_derefidx_vbuz1=vbuyy // Function body tya ldy.z idx2 sta SCREEN2,y // [15] idx2 = ++ idx2 -- vbuz1=_inc_vbuz1 inc.z idx2 // [16] SCREEN2[idx2] = fn2::c#0 -- pbuc1_derefidx_vbuz1=vbuxx ldy.z idx2 txa sta SCREEN2,y // [17] idx2 = ++ idx2 -- vbuz1=_inc_vbuz1 inc.z idx2 jmp __breturn // fn2::@return __breturn: // [18] return rts } // fn1 fn1: { .label ret_addr = $d .label param_char = $a // [19] fn1::ret_addr = 0 -- vwuz1=vwuc1 lda #<0 sta.z ret_addr lda #>0 sta.z ret_addr+1 // [20] fn1::param_char = 0 -- vbuz1=vbuc1 lda #0 sta.z param_char // asm { pla staret_addr pla staret_addr+1 } pla sta ret_addr pla sta ret_addr+1 // asm { pla staparam_char } pla sta param_char // [23] fn1::b#0 = fn1::param_char -- vbuyy=vbuz1 ldy.z param_char // asm { pla staparam_char } pla sta param_char // [25] fn1::c#0 = fn1::param_char -- vbuxx=vbuz1 ldx.z param_char // asm { ldaret_addr+1 pha ldaret_addr pha } lda ret_addr+1 pha lda ret_addr pha // [27] SCREEN1[idx1] = fn1::b#0 -- pbuc1_derefidx_vbuz1=vbuyy // Function body tya ldy.z idx1 sta SCREEN1,y // [28] idx1 = ++ idx1 -- vbuz1=_inc_vbuz1 inc.z idx1 // [29] SCREEN1[idx1] = fn1::c#0 -- pbuc1_derefidx_vbuz1=vbuxx ldy.z idx1 txa sta SCREEN1,y // [30] idx1 = ++ idx1 -- vbuz1=_inc_vbuz1 inc.z idx1 jmp __breturn // fn1::@return __breturn: // [31] return rts } // main main: { .label param_char = 5 .label f = 2 .label i = 6 .label j = 4 // [33] phi from main to main::@1 [phi:main->main::@1] __b1_from_main: // [33] phi main::i#2 = 'a' [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #'a' sta.z i jmp __b1 // main::@1 __b1: // [34] if(main::i#2<='p') goto main::@2 -- vbuz1_le_vbuc1_then_la1 lda #'p' cmp.z i bcs __b2_from___b1 jmp __breturn // main::@return __breturn: // [35] return rts // [36] phi from main::@1 to main::@2 [phi:main::@1->main::@2] __b2_from___b1: // [36] phi main::j#2 = 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 lda #0 sta.z j jmp __b2 // main::@2 __b2: // [37] if(main::j#2<2) goto main::@3 -- vbuz1_lt_vbuc1_then_la1 lda.z j cmp #2 bcc __b3 jmp __b4 // main::@4 __b4: // [38] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [33] phi from main::@4 to main::@1 [phi:main::@4->main::@1] __b1_from___b4: // [33] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy jmp __b1 // main::@3 __b3: // [39] main::param_char = 0 -- vbuz1=vbuc1 lda #0 sta.z param_char // [40] main::param_char = main::i#2 -- vbuz1=vbuz2 lda.z i sta.z param_char // asm { ldaparam_char pha } lda param_char pha // [42] main::param_char = main::j#2 -- vbuz1=vbuz2 lda.z j sta.z param_char // asm { ldaparam_char pha } lda param_char pha // [44] main::$3 = main::j#2 << 1 -- vbuaa=vbuz1_rol_1 lda.z j asl // [45] main::f#0 = main::fns[main::$3] -- pprz1=qprc1_derefidx_vbuaa tay lda fns,y sta.z f lda fns+1,y sta.z f+1 // [46] callexecute *main::f#0 -- call__deref_pprz1 jsr icall1 jmp __b5 // main::@5 __b5: // [47] main::j#1 = ++ main::j#2 -- vbuz1=_inc_vbuz1 inc.z j // [36] phi from main::@5 to main::@2 [phi:main::@5->main::@2] __b2_from___b5: // [36] phi main::j#2 = main::j#1 [phi:main::@5->main::@2#0] -- register_copy jmp __b2 // Outside Flow icall1: jmp (f) .segment Data fns: .word fn1, fn2 } // File Data ASSEMBLER OPTIMIZATIONS Removing instruction jmp __init1 Removing instruction jmp __b1 Removing instruction jmp __breturn Removing instruction jmp __breturn Removing instruction jmp __breturn Removing instruction jmp __b1 Removing instruction jmp __breturn Removing instruction jmp __b2 Removing instruction jmp __b4 Removing instruction jmp __b5 Succesful ASM optimization Pass5NextJumpElimination Removing instruction lda #0 Removing instruction lda #>0 Removing instruction lda #0 Replacing instruction ldy.z param_char with TAY Replacing instruction ldx.z param_char with TAX Removing instruction lda #>0 Removing instruction lda #0 Replacing instruction ldy.z param_char with TAY Replacing instruction ldx.z param_char with TAX Removing instruction lda param_char Removing instruction lda param_char Succesful ASM optimization Pass5UnnecesaryLoadElimination Removing instruction __b1_from___init1: Removing instruction main_from___b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction __init1: Removing instruction __b1: Removing instruction __breturn: Removing instruction __breturn: Removing instruction __breturn: Removing instruction __b1_from_main: Removing instruction __breturn: Removing instruction __b4: Removing instruction __b1_from___b4: Removing instruction __b5: Removing instruction __b2_from___b5: Succesful ASM optimization Pass5UnusedLabelElimination Relabelling long label __b2_from___b1 to __b4 Succesful ASM optimization Pass5RelabelLongLabels FINAL SYMBOL TABLE __constant char * const SCREEN1 = (char *) 1024 __constant char * const SCREEN2 = (char *) 1064 void __start() void fn1() char fn1::b char fn1::b#0 // reg byte y 1.0 char fn1::c char fn1::c#0 // reg byte x 1.0 __loadstore volatile char fn1::param_char // zp[1]:10 1.2000000000000002 __loadstore volatile unsigned int fn1::ret_addr // zp[2]:13 0.2857142857142857 void fn2() char fn2::b char fn2::b#0 // reg byte y 1.0 char fn2::c char fn2::c#0 // reg byte x 1.0 __loadstore volatile char fn2::param_char // zp[1]:9 1.2000000000000002 __loadstore volatile unsigned int fn2::ret_addr // zp[2]:11 0.2857142857142857 __loadstore volatile char idx1 // zp[1]:7 1.272727272727273 __loadstore volatile char idx2 // zp[1]:8 1.272727272727273 void main() char main::$3 // reg byte a 2002.0 void (*main::f)() void (*main::f#0)() // f zp[2]:2 10010.0 __constant void (*main::fns[2])() = { &fn1, &fn2 } char main::i char main::i#1 // i zp[1]:6 202.0 char main::i#2 // i zp[1]:6 186.28571428571428 char main::j char main::j#1 // j zp[1]:4 2002.0 char main::j#2 // j zp[1]:4 625.625 __loadstore volatile char main::param_char // zp[1]:5 1501.5 zp[1]:6 [ main::i#2 main::i#1 ] zp[1]:4 [ main::j#2 main::j#1 ] zp[1]:7 [ idx1 ] zp[1]:8 [ idx2 ] zp[2]:11 [ fn2::ret_addr ] zp[1]:9 [ fn2::param_char ] reg byte y [ fn2::b#0 ] reg byte x [ fn2::c#0 ] zp[2]:13 [ fn1::ret_addr ] zp[1]:10 [ fn1::param_char ] reg byte y [ fn1::b#0 ] reg byte x [ fn1::c#0 ] zp[1]:5 [ main::param_char ] reg byte a [ main::$3 ] zp[2]:2 [ main::f#0 ] FINAL ASSEMBLER Score: 7625 // File Comments // Demonstrates work-around for passing parameters to function pointers // Save the return address, declare parameter variables // Restore the return address // Declare and pull a char parameter // Begin passing parameters using the stack. Declares parameter variables. // Pass a char parameter // Upstart // Commodore 64 PRG executable file .file [name="function-pointer-param-workaround.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(__start) // Global Constants & labels .label SCREEN1 = $400 .label SCREEN2 = $428 .label idx1 = 7 .label idx2 = 8 .segment Code // __start __start: { // __start::__init1 // volatile char idx1 = 0 // [1] idx1 = 0 -- vbuz1=vbuc1 lda #0 sta.z idx1 // volatile char idx2 = 0 // [2] idx2 = 0 -- vbuz1=vbuc1 sta.z idx2 // [3] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1] // __start::@1 // [4] call main // [32] phi from __start::@1 to main [phi:__start::@1->main] jsr main // __start::@return // [5] return rts } // fn2 fn2: { .label ret_addr = $b .label param_char = 9 // PARAM_BEGIN // [6] fn2::ret_addr = 0 -- vwuz1=vwuc1 lda #<0 sta.z ret_addr sta.z ret_addr+1 // [7] fn2::param_char = 0 -- vbuz1=vbuc1 sta.z param_char // asm { pla staret_addr pla staret_addr+1 } pla sta ret_addr pla sta ret_addr+1 // PARAM_CHAR // asm { pla staparam_char } pla sta param_char // [10] fn2::b#0 = fn2::param_char -- vbuyy=vbuz1 tay // asm { pla staparam_char } pla sta param_char // [12] fn2::c#0 = fn2::param_char -- vbuxx=vbuz1 tax // PARAM_END // asm { ldaret_addr+1 pha ldaret_addr pha } lda ret_addr+1 pha lda ret_addr pha // SCREEN2[idx2++] = b // [14] SCREEN2[idx2] = fn2::b#0 -- pbuc1_derefidx_vbuz1=vbuyy // Function body tya ldy.z idx2 sta SCREEN2,y // SCREEN2[idx2++] = b; // [15] idx2 = ++ idx2 -- vbuz1=_inc_vbuz1 inc.z idx2 // SCREEN2[idx2++] = c // [16] SCREEN2[idx2] = fn2::c#0 -- pbuc1_derefidx_vbuz1=vbuxx ldy.z idx2 txa sta SCREEN2,y // SCREEN2[idx2++] = c; // [17] idx2 = ++ idx2 -- vbuz1=_inc_vbuz1 inc.z idx2 // fn2::@return // } // [18] return rts } // fn1 fn1: { .label ret_addr = $d .label param_char = $a // PARAM_BEGIN // [19] fn1::ret_addr = 0 -- vwuz1=vwuc1 lda #<0 sta.z ret_addr sta.z ret_addr+1 // [20] fn1::param_char = 0 -- vbuz1=vbuc1 sta.z param_char // asm { pla staret_addr pla staret_addr+1 } pla sta ret_addr pla sta ret_addr+1 // PARAM_CHAR // asm { pla staparam_char } pla sta param_char // [23] fn1::b#0 = fn1::param_char -- vbuyy=vbuz1 tay // asm { pla staparam_char } pla sta param_char // [25] fn1::c#0 = fn1::param_char -- vbuxx=vbuz1 tax // PARAM_END // asm { ldaret_addr+1 pha ldaret_addr pha } lda ret_addr+1 pha lda ret_addr pha // SCREEN1[idx1++] = b // [27] SCREEN1[idx1] = fn1::b#0 -- pbuc1_derefidx_vbuz1=vbuyy // Function body tya ldy.z idx1 sta SCREEN1,y // SCREEN1[idx1++] = b; // [28] idx1 = ++ idx1 -- vbuz1=_inc_vbuz1 inc.z idx1 // SCREEN1[idx1++] = c // [29] SCREEN1[idx1] = fn1::c#0 -- pbuc1_derefidx_vbuz1=vbuxx ldy.z idx1 txa sta SCREEN1,y // SCREEN1[idx1++] = c; // [30] idx1 = ++ idx1 -- vbuz1=_inc_vbuz1 inc.z idx1 // fn1::@return // } // [31] return rts } // main main: { .label param_char = 5 .label f = 2 .label i = 6 .label j = 4 // [33] phi from main to main::@1 [phi:main->main::@1] // [33] phi main::i#2 = 'a' [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #'a' sta.z i // main::@1 __b1: // for(char i='a';i<='p';i++) // [34] if(main::i#2<='p') goto main::@2 -- vbuz1_le_vbuc1_then_la1 lda #'p' cmp.z i bcs __b4 // main::@return // } // [35] return rts // [36] phi from main::@1 to main::@2 [phi:main::@1->main::@2] __b4: // [36] phi main::j#2 = 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 lda #0 sta.z j // main::@2 __b2: // for(char j=0;j<2;j++) // [37] if(main::j#2<2) goto main::@3 -- vbuz1_lt_vbuc1_then_la1 lda.z j cmp #2 bcc __b3 // main::@4 // for(char i='a';i<='p';i++) // [38] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [33] phi from main::@4 to main::@1 [phi:main::@4->main::@1] // [33] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy jmp __b1 // main::@3 __b3: // CALL_BEGIN // [39] main::param_char = 0 -- vbuz1=vbuc1 lda #0 sta.z param_char // CALL_CHAR // [40] main::param_char = main::i#2 -- vbuz1=vbuz2 lda.z i sta.z param_char // asm { ldaparam_char pha } pha // [42] main::param_char = main::j#2 -- vbuz1=vbuz2 lda.z j sta.z param_char // asm { ldaparam_char pha } pha // void(*f)() = fns[j] // [44] main::$3 = main::j#2 << 1 -- vbuaa=vbuz1_rol_1 lda.z j asl // [45] main::f#0 = main::fns[main::$3] -- pprz1=qprc1_derefidx_vbuaa tay lda fns,y sta.z f lda fns+1,y sta.z f+1 // (*f)() // [46] callexecute *main::f#0 -- call__deref_pprz1 jsr icall1 // main::@5 // for(char j=0;j<2;j++) // [47] main::j#1 = ++ main::j#2 -- vbuz1=_inc_vbuz1 inc.z j // [36] phi from main::@5 to main::@2 [phi:main::@5->main::@2] // [36] phi main::j#2 = main::j#1 [phi:main::@5->main::@2#0] -- register_copy jmp __b2 // Outside Flow icall1: jmp (f) .segment Data fns: .word fn1, fn2 } // File Data