1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-29 03:56:15 +00:00
kickc/src/test/ref/function-pointer-param-workaround.log

1084 lines
37 KiB
Plaintext

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