From 08bb1aa9a075b5663eb85b90121a662c5c4be7d3 Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sun, 25 Jul 2021 02:21:45 +0200 Subject: [PATCH] Working on classic structs and unions. #197 --- src/test/ref/intermediates-simple.asm | 62 +++ src/test/ref/intermediates-simple.cfg | 44 ++ src/test/ref/intermediates-simple.log | 633 ++++++++++++++++++++++++++ src/test/ref/intermediates-simple.sym | 36 ++ src/test/ref/intermediates-struct.asm | 50 ++ src/test/ref/intermediates-struct.cfg | 34 ++ src/test/ref/intermediates-struct.log | 585 ++++++++++++++++++++++++ src/test/ref/intermediates-struct.sym | 33 ++ 8 files changed, 1477 insertions(+) create mode 100644 src/test/ref/intermediates-simple.asm create mode 100644 src/test/ref/intermediates-simple.cfg create mode 100644 src/test/ref/intermediates-simple.log create mode 100644 src/test/ref/intermediates-simple.sym create mode 100644 src/test/ref/intermediates-struct.asm create mode 100644 src/test/ref/intermediates-struct.cfg create mode 100644 src/test/ref/intermediates-struct.log create mode 100644 src/test/ref/intermediates-struct.sym diff --git a/src/test/ref/intermediates-simple.asm b/src/test/ref/intermediates-simple.asm new file mode 100644 index 000000000..7d48a0b6d --- /dev/null +++ b/src/test/ref/intermediates-simple.asm @@ -0,0 +1,62 @@ +// Test intermediate vars + // Commodore 64 PRG executable file +.file [name="intermediates-simple.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) + .label SCREEN = $400 +.segment Code +main: { + .label i = 2 + ldy #0 + tya + sta.z i + __b1: + // for(char i=0;i<5;i++) + lda.z i + cmp #5 + bcc __b4 + // } + rts + __b4: + ldx #0 + __b2: + // for(char j=0;j<5;j++) + cpx #5 + bcc __b3 + // for(char i=0;i<5;i++) + inc.z i + jmp __b1 + __b3: + // char x = i+j + txa + clc + adc.z i + // SCREEN[idx++] = x + sta SCREEN,y + // SCREEN[idx++] = x; + iny + // sum(i,j) + lda.z i + jsr sum + // char y = sum(i,j) + // SCREEN[idx++] = y + sta SCREEN,y + // SCREEN[idx++] = y; + iny + // for(char j=0;j<5;j++) + inx + jmp __b2 +} +// sum(byte register(A) a, byte register(X) b) +sum: { + // a+b + stx.z $ff + clc + adc.z $ff + // } + rts +} diff --git a/src/test/ref/intermediates-simple.cfg b/src/test/ref/intermediates-simple.cfg new file mode 100644 index 000000000..e6714a937 --- /dev/null +++ b/src/test/ref/intermediates-simple.cfg @@ -0,0 +1,44 @@ + +void main() +main: scope:[main] from + [0] phi() + to:main::@1 +main::@1: scope:[main] from main main::@4 + [1] idx#12 = phi( main/0, main::@4/idx#11 ) + [1] main::i#2 = phi( main/0, main::@4/main::i#1 ) + [2] if(main::i#2<5) 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::@5 + [4] idx#11 = phi( main::@1/idx#12, main::@5/idx#1 ) + [4] main::j#2 = phi( main::@1/0, main::@5/main::j#1 ) + [5] if(main::j#2<5) goto main::@3 + to:main::@4 +main::@4: scope:[main] from main::@2 + [6] main::i#1 = ++ main::i#2 + to:main::@1 +main::@3: scope:[main] from main::@2 + [7] main::x#0 = main::i#2 + main::j#2 + [8] SCREEN[idx#11] = main::x#0 + [9] idx#0 = ++ idx#11 + [10] sum::a#0 = main::i#2 + [11] sum::b#0 = main::j#2 + [12] call sum + [13] sum::return#0 = sum::return#1 + to:main::@5 +main::@5: scope:[main] from main::@3 + [14] main::y#0 = sum::return#0 + [15] SCREEN[idx#0] = main::y#0 + [16] idx#1 = ++ idx#0 + [17] main::j#1 = ++ main::j#2 + to:main::@2 + +byte sum(byte sum::a , byte sum::b) +sum: scope:[sum] from main::@3 + [18] sum::return#1 = sum::a#0 + sum::b#0 + to:sum::@return +sum::@return: scope:[sum] from sum + [19] return + to:@return diff --git a/src/test/ref/intermediates-simple.log b/src/test/ref/intermediates-simple.log new file mode 100644 index 000000000..c6cc1a975 --- /dev/null +++ b/src/test/ref/intermediates-simple.log @@ -0,0 +1,633 @@ +Inlined call call __init + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start::@1 + idx#14 = phi( __start::@1/idx#13 ) + main::i#0 = 0 + to:main::@1 +main::@1: scope:[main] from main main::@5 + idx#12 = phi( main/idx#14, main::@5/idx#15 ) + main::i#2 = phi( main/main::i#0, main::@5/main::i#1 ) + main::$0 = main::i#2 < 5 + if(main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + idx#16 = phi( main::@1/idx#12 ) + 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 + idx#11 = phi( main::@2/idx#16, main::@6/idx#1 ) + 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 < 5 + if(main::$1) goto main::@4 + to:main::@5 +main::@4: scope:[main] from main::@3 + idx#6 = phi( main::@3/idx#11 ) + main::j#3 = phi( main::@3/main::j#2 ) + main::i#3 = phi( main::@3/main::i#5 ) + main::$2 = main::i#3 + main::j#3 + main::x#0 = main::$2 + SCREEN[idx#6] = main::x#0 + idx#0 = ++ idx#6 + sum::a#0 = main::i#3 + sum::b#0 = main::j#3 + call sum + sum::return#0 = sum::return#2 + to:main::@6 +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 ) + idx#7 = phi( main::@4/idx#0 ) + sum::return#3 = phi( main::@4/sum::return#0 ) + main::$3 = sum::return#3 + main::y#0 = main::$3 + SCREEN[idx#7] = main::y#0 + idx#1 = ++ idx#7 + main::j#1 = ++ main::j#4 + to:main::@3 +main::@5: scope:[main] from main::@3 + idx#15 = phi( main::@3/idx#11 ) + main::i#4 = phi( main::@3/main::i#5 ) + main::i#1 = ++ main::i#4 + to:main::@1 +main::@return: scope:[main] from main::@1 + idx#8 = phi( main::@1/idx#12 ) + idx#2 = idx#8 + return + to:@return + +byte sum(byte sum::a , byte sum::b) +sum: scope:[sum] from main::@4 + sum::b#1 = phi( main::@4/sum::b#0 ) + sum::a#1 = phi( main::@4/sum::a#0 ) + sum::$0 = sum::a#1 + sum::b#1 + sum::return#1 = sum::$0 + to:sum::@return +sum::@return: scope:[sum] from sum + sum::return#4 = phi( sum/sum::return#1 ) + sum::return#2 = sum::return#4 + return + to:@return + +void __start() +__start: scope:[__start] from + to:__start::__init1 +__start::__init1: scope:[__start] from __start + idx#3 = 0 + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + idx#13 = phi( __start::__init1/idx#3 ) + call main + to:__start::@2 +__start::@2: scope:[__start] from __start::@1 + idx#9 = phi( __start::@1/idx#2 ) + idx#4 = idx#9 + to:__start::@return +__start::@return: scope:[__start] from __start::@2 + idx#10 = phi( __start::@2/idx#4 ) + idx#5 = idx#10 + return + to:@return + +SYMBOL TABLE SSA +constant byte* const SCREEN = (byte*)$400 +void __start() +byte idx +byte idx#0 +byte idx#1 +byte idx#10 +byte idx#11 +byte idx#12 +byte idx#13 +byte idx#14 +byte idx#15 +byte idx#16 +byte idx#2 +byte idx#3 +byte idx#4 +byte idx#5 +byte idx#6 +byte idx#7 +byte idx#8 +byte idx#9 +void main() +bool~ main::$0 +bool~ main::$1 +byte~ main::$2 +byte~ main::$3 +byte main::i +byte main::i#0 +byte main::i#1 +byte main::i#2 +byte main::i#3 +byte main::i#4 +byte main::i#5 +byte main::i#6 +byte main::i#7 +byte main::j +byte main::j#0 +byte main::j#1 +byte main::j#2 +byte main::j#3 +byte main::j#4 +byte main::x +byte main::x#0 +byte main::y +byte main::y#0 +byte sum(byte sum::a , byte sum::b) +byte~ sum::$0 +byte sum::a +byte sum::a#0 +byte sum::a#1 +byte sum::b +byte sum::b#0 +byte sum::b#1 +byte sum::return +byte sum::return#0 +byte sum::return#1 +byte sum::return#2 +byte sum::return#3 +byte sum::return#4 + +Adding number conversion cast (unumber) 5 in main::$0 = main::i#2 < 5 +Adding number conversion cast (unumber) 5 in main::$1 = main::j#2 < 5 +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 5 +Simplifying constant integer cast 5 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 5 +Finalized unsigned number type (byte) 5 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias main::i#2 = main::i#6 +Alias idx#12 = idx#16 idx#8 idx#2 +Alias main::i#3 = main::i#5 main::i#7 main::i#4 +Alias main::j#2 = main::j#3 main::j#4 +Alias idx#11 = idx#6 idx#15 +Alias main::x#0 = main::$2 +Alias sum::return#0 = sum::return#3 +Alias idx#0 = idx#7 +Alias main::y#0 = main::$3 +Alias sum::return#1 = sum::$0 sum::return#4 sum::return#2 +Alias idx#13 = idx#3 +Alias idx#10 = idx#4 idx#9 idx#5 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values idx#14 idx#13 +Identical Phi Values main::i#3 main::i#2 +Identical Phi Values sum::a#1 sum::a#0 +Identical Phi Values sum::b#1 sum::b#0 +Identical Phi Values idx#10 idx#12 +Successful SSA optimization Pass2IdenticalPhiElimination +Simple Condition main::$0 [4] if(main::i#2<5) goto main::@2 +Simple Condition main::$1 [8] if(main::j#2<5) goto main::@4 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant main::i#0 = 0 +Constant main::j#0 = 0 +Constant idx#13 = 0 +Successful SSA optimization Pass2ConstantIdentification +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 main::i#0 +Inlining constant with var siblings main::j#0 +Inlining constant with var siblings idx#13 +Constant inlined main::i#0 = 0 +Constant inlined main::j#0 = 0 +Constant inlined idx#13 = 0 +Successful SSA optimization Pass2ConstantInlining +Adding NOP phi() at start of main +CALL GRAPH +Calls in [main] to sum:15 + +Created 4 initial phi equivalence classes +Coalesced [4] idx#18 = idx#12 +Coalesced [8] main::i#8 = main::i#1 +Coalesced (already) [9] idx#17 = idx#11 +Coalesced [21] main::j#5 = main::j#1 +Coalesced [22] idx#19 = idx#1 +Coalesced down to 3 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 +Renumbering block main::@6 to main::@5 +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] idx#12 = phi( main/0, main::@4/idx#11 ) + [1] main::i#2 = phi( main/0, main::@4/main::i#1 ) + [2] if(main::i#2<5) 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::@5 + [4] idx#11 = phi( main::@1/idx#12, main::@5/idx#1 ) + [4] main::j#2 = phi( main::@1/0, main::@5/main::j#1 ) + [5] if(main::j#2<5) goto main::@3 + to:main::@4 +main::@4: scope:[main] from main::@2 + [6] main::i#1 = ++ main::i#2 + to:main::@1 +main::@3: scope:[main] from main::@2 + [7] main::x#0 = main::i#2 + main::j#2 + [8] SCREEN[idx#11] = main::x#0 + [9] idx#0 = ++ idx#11 + [10] sum::a#0 = main::i#2 + [11] sum::b#0 = main::j#2 + [12] call sum + [13] sum::return#0 = sum::return#1 + to:main::@5 +main::@5: scope:[main] from main::@3 + [14] main::y#0 = sum::return#0 + [15] SCREEN[idx#0] = main::y#0 + [16] idx#1 = ++ idx#0 + [17] main::j#1 = ++ main::j#2 + to:main::@2 + +byte sum(byte sum::a , byte sum::b) +sum: scope:[sum] from main::@3 + [18] sum::return#1 = sum::a#0 + sum::b#0 + to:sum::@return +sum::@return: scope:[sum] from sum + [19] return + to:@return + + +VARIABLE REGISTER WEIGHTS +byte idx +byte idx#0 43.285714285714285 +byte idx#1 101.0 +byte idx#11 65.0 +byte idx#12 11.0 +void main() +byte main::i +byte main::i#1 22.0 +byte main::i#2 15.666666666666668 +byte main::j +byte main::j#1 202.0 +byte main::j#2 42.08333333333333 +byte main::x +byte main::x#0 202.0 +byte main::y +byte main::y#0 202.0 +byte sum(byte sum::a , byte sum::b) +byte sum::a +byte sum::a#0 551.0 +byte sum::b +byte sum::b#0 1102.0 +byte sum::return +byte sum::return#0 202.0 +byte sum::return#1 367.33333333333337 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +[ idx#12 idx#11 idx#1 ] +[ main::j#2 main::j#1 ] +Added variable main::x#0 to live range equivalence class [ main::x#0 ] +Added variable idx#0 to live range equivalence class [ idx#0 ] +Added variable sum::a#0 to live range equivalence class [ sum::a#0 ] +Added variable sum::b#0 to live range equivalence class [ sum::b#0 ] +Added variable sum::return#0 to live range equivalence class [ sum::return#0 ] +Added variable main::y#0 to live range equivalence class [ main::y#0 ] +Added variable sum::return#1 to live range equivalence class [ sum::return#1 ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ idx#12 idx#11 idx#1 ] +[ main::j#2 main::j#1 ] +[ main::x#0 ] +[ idx#0 ] +[ sum::a#0 ] +[ sum::b#0 ] +[ sum::return#0 ] +[ main::y#0 ] +[ sum::return#1 ] +Allocated zp[1]:2 [ main::i#2 main::i#1 ] +Allocated zp[1]:3 [ idx#12 idx#11 idx#1 ] +Allocated zp[1]:4 [ main::j#2 main::j#1 ] +Allocated zp[1]:5 [ main::x#0 ] +Allocated zp[1]:6 [ idx#0 ] +Allocated zp[1]:7 [ sum::a#0 ] +Allocated zp[1]:8 [ sum::b#0 ] +Allocated zp[1]:9 [ sum::return#0 ] +Allocated zp[1]:10 [ main::y#0 ] +Allocated zp[1]:11 [ sum::return#1 ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [7] main::x#0 = main::i#2 + main::j#2 [ main::i#2 idx#11 main::j#2 main::x#0 ] ( [ main::i#2 idx#11 main::j#2 main::x#0 ] { { sum::a#0 = main::i#2 } { sum::b#0 = main::j#2 } { sum::return#0 = sum::return#1 } } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ] +Removing always clobbered register reg byte a as potential for zp[1]:3 [ idx#12 idx#11 idx#1 ] +Removing always clobbered register reg byte a as potential for zp[1]:4 [ main::j#2 main::j#1 ] +Statement [18] sum::return#1 = sum::a#0 + sum::b#0 [ sum::return#1 ] ( sum:12 [ main::i#2 main::j#2 idx#0 sum::return#1 ] { { sum::a#0 = main::i#2 } { sum::b#0 = main::j#2 } { sum::return#0 = sum::return#1 } } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:6 [ idx#0 ] +Statement [7] main::x#0 = main::i#2 + main::j#2 [ main::i#2 idx#11 main::j#2 main::x#0 ] ( [ main::i#2 idx#11 main::j#2 main::x#0 ] { { sum::a#0 = main::i#2 } { sum::b#0 = main::j#2 } { sum::return#0 = sum::return#1 } } ) always clobbers reg byte a +Statement [18] sum::return#1 = sum::a#0 + sum::b#0 [ sum::return#1 ] ( sum:12 [ main::i#2 main::j#2 idx#0 sum::return#1 ] { { sum::a#0 = main::i#2 } { sum::b#0 = main::j#2 } { sum::return#0 = sum::return#1 } } ) always clobbers reg byte a +Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y , +Potential registers zp[1]:3 [ idx#12 idx#11 idx#1 ] : zp[1]:3 , reg byte x , reg byte y , +Potential registers zp[1]:4 [ main::j#2 main::j#1 ] : zp[1]:4 , reg byte x , reg byte y , +Potential registers zp[1]:5 [ main::x#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:6 [ idx#0 ] : zp[1]:6 , reg byte x , reg byte y , +Potential registers zp[1]:7 [ sum::a#0 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:8 [ sum::b#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:9 [ sum::return#0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:10 [ main::y#0 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:11 [ sum::return#1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y , + +REGISTER UPLIFT SCOPES +Uplift Scope [sum] 1,102: zp[1]:8 [ sum::b#0 ] 551: zp[1]:7 [ sum::a#0 ] 367.33: zp[1]:11 [ sum::return#1 ] 202: zp[1]:9 [ sum::return#0 ] +Uplift Scope [main] 244.08: zp[1]:4 [ main::j#2 main::j#1 ] 202: zp[1]:5 [ main::x#0 ] 202: zp[1]:10 [ main::y#0 ] 37.67: zp[1]:2 [ main::i#2 main::i#1 ] +Uplift Scope [] 177: zp[1]:3 [ idx#12 idx#11 idx#1 ] 43.29: zp[1]:6 [ idx#0 ] + +Uplifting [sum] best 9688 combination reg byte x [ sum::b#0 ] reg byte a [ sum::a#0 ] reg byte a [ sum::return#1 ] reg byte a [ sum::return#0 ] +Limited combination testing to 100 combinations of 256 possible. +Uplifting [main] best 7188 combination reg byte x [ main::j#2 main::j#1 ] reg byte a [ main::x#0 ] reg byte a [ main::y#0 ] zp[1]:2 [ main::i#2 main::i#1 ] +Limited combination testing to 100 combinations of 144 possible. +Uplifting [] best 5358 combination reg byte y [ idx#12 idx#11 idx#1 ] reg byte y [ idx#0 ] +Attempting to uplift remaining variables inzp[1]:2 [ main::i#2 main::i#1 ] +Uplifting [main] best 5358 combination zp[1]:2 [ main::i#2 main::i#1 ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test intermediate vars + // Upstart + // Commodore 64 PRG executable file +.file [name="intermediates-simple.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 +.segment Code + // main +main: { + .label i = 2 + // [1] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [1] phi idx#12 = 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + // [1] phi main::i#2 = 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + lda #0 + sta.z i + jmp __b1 + // main::@1 + __b1: + // [2] if(main::i#2<5) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda.z i + cmp #5 + 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 idx#11 = idx#12 [phi:main::@1->main::@2#0] -- register_copy + // [4] phi main::j#2 = 0 [phi:main::@1->main::@2#1] -- vbuxx=vbuc1 + ldx #0 + jmp __b2 + // main::@2 + __b2: + // [5] if(main::j#2<5) goto main::@3 -- vbuxx_lt_vbuc1_then_la1 + cpx #5 + bcc __b3 + jmp __b4 + // main::@4 + __b4: + // [6] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + __b1_from___b4: + // [1] phi idx#12 = idx#11 [phi:main::@4->main::@1#0] -- register_copy + // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#1] -- register_copy + jmp __b1 + // main::@3 + __b3: + // [7] main::x#0 = main::i#2 + main::j#2 -- vbuaa=vbuz1_plus_vbuxx + txa + clc + adc.z i + // [8] SCREEN[idx#11] = main::x#0 -- pbuc1_derefidx_vbuyy=vbuaa + sta SCREEN,y + // [9] idx#0 = ++ idx#11 -- vbuyy=_inc_vbuyy + iny + // [10] sum::a#0 = main::i#2 -- vbuaa=vbuz1 + lda.z i + // [11] sum::b#0 = main::j#2 + // [12] call sum + jsr sum + // [13] sum::return#0 = sum::return#1 + jmp __b5 + // main::@5 + __b5: + // [14] main::y#0 = sum::return#0 + // [15] SCREEN[idx#0] = main::y#0 -- pbuc1_derefidx_vbuyy=vbuaa + sta SCREEN,y + // [16] idx#1 = ++ idx#0 -- vbuyy=_inc_vbuyy + iny + // [17] main::j#1 = ++ main::j#2 -- vbuxx=_inc_vbuxx + inx + // [4] phi from main::@5 to main::@2 [phi:main::@5->main::@2] + __b2_from___b5: + // [4] phi idx#11 = idx#1 [phi:main::@5->main::@2#0] -- register_copy + // [4] phi main::j#2 = main::j#1 [phi:main::@5->main::@2#1] -- register_copy + jmp __b2 +} + // sum +// sum(byte register(A) a, byte register(X) b) +sum: { + // [18] sum::return#1 = sum::a#0 + sum::b#0 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + jmp __breturn + // sum::@return + __breturn: + // [19] return + rts +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Removing instruction jmp __b2 +Removing instruction jmp __b4 +Removing instruction jmp __b5 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Replacing instruction lda #0 with TYA +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b4: +Removing instruction __b1_from___b4: +Removing instruction __b5: +Removing instruction __b2_from___b5: +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination +Relabelling long label __b2_from___b1 to __b4 +Succesful ASM optimization Pass5RelabelLongLabels + +FINAL SYMBOL TABLE +constant byte* const SCREEN = (byte*) 1024 +byte idx +byte idx#0 reg byte y 43.285714285714285 +byte idx#1 reg byte y 101.0 +byte idx#11 reg byte y 65.0 +byte idx#12 reg byte y 11.0 +void main() +byte main::i +byte main::i#1 i zp[1]:2 22.0 +byte main::i#2 i zp[1]:2 15.666666666666668 +byte main::j +byte main::j#1 reg byte x 202.0 +byte main::j#2 reg byte x 42.08333333333333 +byte main::x +byte main::x#0 reg byte a 202.0 +byte main::y +byte main::y#0 reg byte a 202.0 +byte sum(byte sum::a , byte sum::b) +byte sum::a +byte sum::a#0 reg byte a 551.0 +byte sum::b +byte sum::b#0 reg byte x 1102.0 +byte sum::return +byte sum::return#0 reg byte a 202.0 +byte sum::return#1 reg byte a 367.33333333333337 + +zp[1]:2 [ main::i#2 main::i#1 ] +reg byte y [ idx#12 idx#11 idx#1 ] +reg byte x [ main::j#2 main::j#1 ] +reg byte a [ main::x#0 ] +reg byte y [ idx#0 ] +reg byte a [ sum::a#0 ] +reg byte x [ sum::b#0 ] +reg byte a [ sum::return#0 ] +reg byte a [ main::y#0 ] +reg byte a [ sum::return#1 ] + + +FINAL ASSEMBLER +Score: 4395 + + // File Comments +// Test intermediate vars + // Upstart + // Commodore 64 PRG executable file +.file [name="intermediates-simple.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 +.segment Code + // main +main: { + .label i = 2 + // [1] phi from main to main::@1 [phi:main->main::@1] + // [1] phi idx#12 = 0 [phi:main->main::@1#0] -- vbuyy=vbuc1 + ldy #0 + // [1] phi main::i#2 = 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 + tya + sta.z i + // main::@1 + __b1: + // for(char i=0;i<5;i++) + // [2] if(main::i#2<5) goto main::@2 -- vbuz1_lt_vbuc1_then_la1 + lda.z i + cmp #5 + bcc __b4 + // main::@return + // } + // [3] return + rts + // [4] phi from main::@1 to main::@2 [phi:main::@1->main::@2] + __b4: + // [4] phi idx#11 = idx#12 [phi:main::@1->main::@2#0] -- register_copy + // [4] phi main::j#2 = 0 [phi:main::@1->main::@2#1] -- vbuxx=vbuc1 + ldx #0 + // main::@2 + __b2: + // for(char j=0;j<5;j++) + // [5] if(main::j#2<5) goto main::@3 -- vbuxx_lt_vbuc1_then_la1 + cpx #5 + bcc __b3 + // main::@4 + // for(char i=0;i<5;i++) + // [6] main::i#1 = ++ main::i#2 -- vbuz1=_inc_vbuz1 + inc.z i + // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1] + // [1] phi idx#12 = idx#11 [phi:main::@4->main::@1#0] -- register_copy + // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#1] -- register_copy + jmp __b1 + // main::@3 + __b3: + // char x = i+j + // [7] main::x#0 = main::i#2 + main::j#2 -- vbuaa=vbuz1_plus_vbuxx + txa + clc + adc.z i + // SCREEN[idx++] = x + // [8] SCREEN[idx#11] = main::x#0 -- pbuc1_derefidx_vbuyy=vbuaa + sta SCREEN,y + // SCREEN[idx++] = x; + // [9] idx#0 = ++ idx#11 -- vbuyy=_inc_vbuyy + iny + // sum(i,j) + // [10] sum::a#0 = main::i#2 -- vbuaa=vbuz1 + lda.z i + // [11] sum::b#0 = main::j#2 + // [12] call sum + jsr sum + // [13] sum::return#0 = sum::return#1 + // main::@5 + // char y = sum(i,j) + // [14] main::y#0 = sum::return#0 + // SCREEN[idx++] = y + // [15] SCREEN[idx#0] = main::y#0 -- pbuc1_derefidx_vbuyy=vbuaa + sta SCREEN,y + // SCREEN[idx++] = y; + // [16] idx#1 = ++ idx#0 -- vbuyy=_inc_vbuyy + iny + // for(char j=0;j<5;j++) + // [17] main::j#1 = ++ main::j#2 -- vbuxx=_inc_vbuxx + inx + // [4] phi from main::@5 to main::@2 [phi:main::@5->main::@2] + // [4] phi idx#11 = idx#1 [phi:main::@5->main::@2#0] -- register_copy + // [4] phi main::j#2 = main::j#1 [phi:main::@5->main::@2#1] -- register_copy + jmp __b2 +} + // sum +// sum(byte register(A) a, byte register(X) b) +sum: { + // a+b + // [18] sum::return#1 = sum::a#0 + sum::b#0 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // sum::@return + // } + // [19] return + rts +} + // File Data + diff --git a/src/test/ref/intermediates-simple.sym b/src/test/ref/intermediates-simple.sym new file mode 100644 index 000000000..e81a5c179 --- /dev/null +++ b/src/test/ref/intermediates-simple.sym @@ -0,0 +1,36 @@ +constant byte* const SCREEN = (byte*) 1024 +byte idx +byte idx#0 reg byte y 43.285714285714285 +byte idx#1 reg byte y 101.0 +byte idx#11 reg byte y 65.0 +byte idx#12 reg byte y 11.0 +void main() +byte main::i +byte main::i#1 i zp[1]:2 22.0 +byte main::i#2 i zp[1]:2 15.666666666666668 +byte main::j +byte main::j#1 reg byte x 202.0 +byte main::j#2 reg byte x 42.08333333333333 +byte main::x +byte main::x#0 reg byte a 202.0 +byte main::y +byte main::y#0 reg byte a 202.0 +byte sum(byte sum::a , byte sum::b) +byte sum::a +byte sum::a#0 reg byte a 551.0 +byte sum::b +byte sum::b#0 reg byte x 1102.0 +byte sum::return +byte sum::return#0 reg byte a 202.0 +byte sum::return#1 reg byte a 367.33333333333337 + +zp[1]:2 [ main::i#2 main::i#1 ] +reg byte y [ idx#12 idx#11 idx#1 ] +reg byte x [ main::j#2 main::j#1 ] +reg byte a [ main::x#0 ] +reg byte y [ idx#0 ] +reg byte a [ sum::a#0 ] +reg byte x [ sum::b#0 ] +reg byte a [ sum::return#0 ] +reg byte a [ main::y#0 ] +reg byte a [ sum::return#1 ] diff --git a/src/test/ref/intermediates-struct.asm b/src/test/ref/intermediates-struct.asm new file mode 100644 index 000000000..a74e62574 --- /dev/null +++ b/src/test/ref/intermediates-struct.asm @@ -0,0 +1,50 @@ +// Test intermediate vars + // Commodore 64 PRG executable file +.file [name="intermediates-struct.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) + .const OFFSET_STRUCT_DATA_D = 1 + // #pragma struct_model(classic) + .label SCREEN = $400 +.segment Code +main: { + // sum(1,2) + ldx #2 + lda #1 + jsr sum + // sum(1,2) + txa + // struct Data x = sum(1,2) + // SCREEN[idx++] = x.c + sta SCREEN + // sum(3, 4) + ldx #4 + lda #3 + jsr sum + // sum(3, 4) + // struct Data y = sum(3, 4) + // SCREEN[idx++] = y.d + sta SCREEN+1 + // } + rts +} +// sum(byte register(A) a, byte register(X) b) +sum: { + .label d = 2 + // a+b + stx.z $ff + clc + adc.z $ff + // __ma struct Data d = { a+b, b } + sta.z d + stx d+OFFSET_STRUCT_DATA_D + // return d; + tax + lda d+OFFSET_STRUCT_DATA_D + // } + rts +} diff --git a/src/test/ref/intermediates-struct.cfg b/src/test/ref/intermediates-struct.cfg new file mode 100644 index 000000000..323d180d3 --- /dev/null +++ b/src/test/ref/intermediates-struct.cfg @@ -0,0 +1,34 @@ + +void main() +main: scope:[main] from + [0] phi() + [1] call sum + [2] sum::return_c#0 = sum::return_c#2 + to:main::@1 +main::@1: scope:[main] from main + [3] main::x_c#0 = sum::return_c#0 + [4] *SCREEN = main::x_c#0 + [5] call sum + [6] sum::return_d#1 = sum::return_d#2 + to:main::@2 +main::@2: scope:[main] from main::@1 + [7] main::y_d#0 = sum::return_d#1 + [8] *(SCREEN+1) = main::y_d#0 + to:main::@return +main::@return: scope:[main] from main::@2 + [9] return + to:@return + +struct Data sum(byte sum::a , byte sum::b) +sum: scope:[sum] from main main::@1 + [10] sum::b#2 = phi( main/2, main::@1/4 ) + [10] sum::a#2 = phi( main/1, main::@1/3 ) + [11] sum::$0 = sum::a#2 + sum::b#2 + [12] *((byte*)&sum::d) = sum::$0 + [13] *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) = sum::b#2 + [14] sum::return_c#2 = *((byte*)&sum::d) + [15] sum::return_d#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) + to:sum::@return +sum::@return: scope:[sum] from sum + [16] return + to:@return diff --git a/src/test/ref/intermediates-struct.log b/src/test/ref/intermediates-struct.log new file mode 100644 index 000000000..4e71d9860 --- /dev/null +++ b/src/test/ref/intermediates-struct.log @@ -0,0 +1,585 @@ +Inlined call call __init +Eliminating unused variable with no statement main::$0 +Eliminating unused variable with no statement main::$1 +Unwinding list assignment { main::$0_c, main::$0_d } = { sum::return_c, sum::return_d } +Unwinding list assignment { main::$1_c, main::$1_d } = { sum::return_c, sum::return_d } +Unwinding list assignment { sum::return_c#0, sum::return_d#0 } = { sum::return_c#3, sum::return_d#3 } +Unwinding list assignment { sum::return_c#1, sum::return_d#1 } = { sum::return_c#3, sum::return_d#3 } +Removing C-classic struct-unwound assignment sum::d = struct-unwound {*((byte*)&sum::d+OFFSET_STRUCT_DATA_C), *((byte*)&sum::d+OFFSET_STRUCT_DATA_D)} + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start::@1 + idx#11 = phi( __start::@1/idx#12 ) + sum::a#0 = 1 + sum::b#0 = 2 + call sum + sum::return_c#0 = sum::return_c#3 + sum::return_d#0 = sum::return_d#3 + to:main::@1 +main::@1: scope:[main] from main + idx#6 = phi( main/idx#11 ) + sum::return_d#4 = phi( main/sum::return_d#0 ) + sum::return_c#4 = phi( main/sum::return_c#0 ) + main::$0_c = sum::return_c#4 + main::$0_d = sum::return_d#4 + main::x_c#0 = main::$0_c + SCREEN[idx#6] = main::x_c#0 + idx#0 = ++ idx#6 + sum::a#1 = 3 + sum::b#1 = 4 + call sum + sum::return_c#1 = sum::return_c#3 + sum::return_d#1 = sum::return_d#3 + to:main::@2 +main::@2: scope:[main] from main::@1 + idx#7 = phi( main::@1/idx#0 ) + sum::return_d#5 = phi( main::@1/sum::return_d#1 ) + sum::return_c#5 = phi( main::@1/sum::return_c#1 ) + main::$1_c = sum::return_c#5 + main::$1_d = sum::return_d#5 + main::y_d#0 = main::$1_d + SCREEN[idx#7] = main::y_d#0 + idx#1 = ++ idx#7 + to:main::@return +main::@return: scope:[main] from main::@2 + idx#8 = phi( main::@2/idx#1 ) + idx#2 = idx#8 + return + to:@return + +struct Data sum(byte sum::a , byte sum::b) +sum: scope:[sum] from main main::@1 + sum::b#2 = phi( main/sum::b#0, main::@1/sum::b#1 ) + sum::a#2 = phi( main/sum::a#0, main::@1/sum::a#1 ) + sum::$0 = sum::a#2 + sum::b#2 + *((byte*)&sum::d+OFFSET_STRUCT_DATA_C) = sum::$0 + *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) = sum::b#2 + sum::return_c#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_C) + sum::return_d#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) + sum::return#0 = struct-unwound {sum::return_c#2, sum::return_d#2} + to:sum::@return +sum::@return: scope:[sum] from sum + sum::return_d#6 = phi( sum/sum::return_d#2 ) + sum::return_c#6 = phi( sum/sum::return_c#2 ) + sum::return_c#3 = sum::return_c#6 + sum::return_d#3 = sum::return_d#6 + sum::return#1 = struct-unwound {sum::return_c#3, sum::return_d#3} + return + to:@return + +void __start() +__start: scope:[__start] from + to:__start::__init1 +__start::__init1: scope:[__start] from __start + idx#3 = 0 + to:__start::@1 +__start::@1: scope:[__start] from __start::__init1 + idx#12 = phi( __start::__init1/idx#3 ) + call main + to:__start::@2 +__start::@2: scope:[__start] from __start::@1 + idx#9 = phi( __start::@1/idx#2 ) + idx#4 = idx#9 + to:__start::@return +__start::@return: scope:[__start] from __start::@2 + idx#10 = phi( __start::@2/idx#4 ) + idx#5 = idx#10 + return + to:@return + +SYMBOL TABLE SSA +constant byte OFFSET_STRUCT_DATA_C = 0 +constant byte OFFSET_STRUCT_DATA_D = 1 +constant byte* const SCREEN = (byte*)$400 +void __start() +byte idx +byte idx#0 +byte idx#1 +byte idx#10 +byte idx#11 +byte idx#12 +byte idx#2 +byte idx#3 +byte idx#4 +byte idx#5 +byte idx#6 +byte idx#7 +byte idx#8 +byte idx#9 +void main() +byte~ main::$0_c +byte~ main::$0_d +byte~ main::$1_c +byte~ main::$1_d +byte main::x_c +byte main::x_c#0 +byte main::y_d +byte main::y_d#0 +struct Data sum(byte sum::a , byte sum::b) +byte~ sum::$0 +byte sum::a +byte sum::a#0 +byte sum::a#1 +byte sum::a#2 +byte sum::b +byte sum::b#0 +byte sum::b#1 +byte sum::b#2 +struct Data sum::d loadstore +struct Data sum::return +struct Data sum::return#0 +struct Data sum::return#1 +byte sum::return_c +byte sum::return_c#0 +byte sum::return_c#1 +byte sum::return_c#2 +byte sum::return_c#3 +byte sum::return_c#4 +byte sum::return_c#5 +byte sum::return_c#6 +byte sum::return_d +byte sum::return_d#0 +byte sum::return_d#1 +byte sum::return_d#2 +byte sum::return_d#3 +byte sum::return_d#4 +byte sum::return_d#5 +byte sum::return_d#6 + +Adding number conversion cast (unumber) 1 in sum::a#0 = 1 +Adding number conversion cast (unumber) 2 in sum::b#0 = 2 +Adding number conversion cast (unumber) 3 in sum::a#1 = 3 +Adding number conversion cast (unumber) 4 in sum::b#1 = 4 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast sum::a#0 = (unumber)1 +Inlining cast sum::b#0 = (unumber)2 +Inlining cast sum::a#1 = (unumber)3 +Inlining cast sum::b#1 = (unumber)4 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (byte*) 1024 +Simplifying constant integer cast 1 +Simplifying constant integer cast 2 +Simplifying constant integer cast 3 +Simplifying constant integer cast 4 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (byte) 1 +Finalized unsigned number type (byte) 2 +Finalized unsigned number type (byte) 3 +Finalized unsigned number type (byte) 4 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias sum::return_c#0 = sum::return_c#4 +Alias sum::return_d#0 = sum::return_d#4 +Alias idx#11 = idx#6 +Alias main::x_c#0 = main::$0_c +Alias sum::return_c#1 = sum::return_c#5 +Alias sum::return_d#1 = sum::return_d#5 +Alias idx#0 = idx#7 +Alias main::y_d#0 = main::$1_d +Alias idx#1 = idx#8 idx#2 +Alias sum::return_c#2 = sum::return_c#6 sum::return_c#3 +Alias sum::return_d#2 = sum::return_d#6 sum::return_d#3 +Alias idx#12 = idx#3 +Alias idx#10 = idx#4 idx#9 idx#5 +Successful SSA optimization Pass2AliasElimination +Identical Phi Values idx#11 idx#12 +Identical Phi Values idx#10 idx#1 +Successful SSA optimization Pass2IdenticalPhiElimination +Constant sum::a#0 = 1 +Constant sum::b#0 = 2 +Constant sum::a#1 = 3 +Constant sum::b#1 = 4 +Constant idx#12 = 0 +Successful SSA optimization Pass2ConstantIdentification +Simplifying expression containing zero SCREEN in [8] SCREEN[idx#12] = main::x_c#0 +Simplifying expression containing zero (byte*)&sum::d in [22] *((byte*)&sum::d+OFFSET_STRUCT_DATA_C) = sum::$0 +Simplifying expression containing zero (byte*)&sum::d in [24] sum::return_c#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_C) +Successful SSA optimization PassNSimplifyExpressionWithZero +Eliminating unused variable main::$0_d and assignment [4] main::$0_d = sum::return_d#0 +Eliminating unused variable main::$1_c and assignment [10] main::$1_c = sum::return_c#1 +Eliminating unused variable idx#1 and assignment [13] idx#1 = ++ idx#0 +Eliminating unused variable sum::return#0 and assignment [21] sum::return#0 = struct-unwound {sum::return_c#2, sum::return_d#2} +Eliminating unused variable sum::return#1 and assignment [22] sum::return#1 = struct-unwound {sum::return_c#2, sum::return_d#2} +Eliminating unused constant OFFSET_STRUCT_DATA_C +Successful SSA optimization PassNEliminateUnusedVars +Eliminating unused variable sum::return_d#0 and assignment [2] sum::return_d#0 = sum::return_d#2 +Eliminating unused variable sum::return_c#1 and assignment [7] sum::return_c#1 = sum::return_c#2 +Successful SSA optimization PassNEliminateUnusedVars +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 +Constant right-side identified [4] idx#0 = ++ idx#12 +Successful SSA optimization Pass2ConstantRValueConsolidation +Constant idx#0 = ++idx#12 +Successful SSA optimization Pass2ConstantIdentification +Inlining constant with var siblings sum::a#0 +Inlining constant with var siblings sum::b#0 +Inlining constant with var siblings sum::a#1 +Inlining constant with var siblings sum::b#1 +Inlining constant with different constant siblings idx#12 +Inlining constant with different constant siblings idx#0 +Constant inlined idx#12 = 0 +Constant inlined sum::b#1 = 4 +Constant inlined sum::b#0 = 2 +Constant inlined sum::a#1 = 3 +Constant inlined idx#0 = ++0 +Constant inlined sum::a#0 = 1 +Successful SSA optimization Pass2ConstantInlining +Consolidated array index constant in *(SCREEN+++0) +Successful SSA optimization Pass2ConstantAdditionElimination +Simplifying constant integer increment ++0 +Successful SSA optimization Pass2ConstantSimplification +Adding NOP phi() at start of main +CALL GRAPH +Calls in [main] to sum:1 sum:5 + +Created 2 initial phi equivalence classes +Coalesced down to 2 phi equivalence classes +Adding NOP phi() at start of main + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] phi() + [1] call sum + [2] sum::return_c#0 = sum::return_c#2 + to:main::@1 +main::@1: scope:[main] from main + [3] main::x_c#0 = sum::return_c#0 + [4] *SCREEN = main::x_c#0 + [5] call sum + [6] sum::return_d#1 = sum::return_d#2 + to:main::@2 +main::@2: scope:[main] from main::@1 + [7] main::y_d#0 = sum::return_d#1 + [8] *(SCREEN+1) = main::y_d#0 + to:main::@return +main::@return: scope:[main] from main::@2 + [9] return + to:@return + +struct Data sum(byte sum::a , byte sum::b) +sum: scope:[sum] from main main::@1 + [10] sum::b#2 = phi( main/2, main::@1/4 ) + [10] sum::a#2 = phi( main/1, main::@1/3 ) + [11] sum::$0 = sum::a#2 + sum::b#2 + [12] *((byte*)&sum::d) = sum::$0 + [13] *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) = sum::b#2 + [14] sum::return_c#2 = *((byte*)&sum::d) + [15] sum::return_d#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) + to:sum::@return +sum::@return: scope:[sum] from sum + [16] return + to:@return + + +VARIABLE REGISTER WEIGHTS +byte idx +void main() +byte main::x_c +byte main::x_c#0 4.0 +byte main::y_d +byte main::y_d#0 4.0 +struct Data sum(byte sum::a , byte sum::b) +byte~ sum::$0 22.0 +byte sum::a +byte sum::a#2 11.0 +byte sum::b +byte sum::b#2 7.333333333333333 +struct Data sum::d loadstore +struct Data sum::return +byte sum::return_c +byte sum::return_c#0 4.0 +byte sum::return_c#2 3.25 +byte sum::return_d +byte sum::return_d#1 4.0 +byte sum::return_d#2 4.333333333333333 + +Initial phi equivalence classes +[ sum::a#2 ] +[ sum::b#2 ] +Added variable sum::return_c#0 to live range equivalence class [ sum::return_c#0 ] +Added variable main::x_c#0 to live range equivalence class [ main::x_c#0 ] +Added variable sum::return_d#1 to live range equivalence class [ sum::return_d#1 ] +Added variable main::y_d#0 to live range equivalence class [ main::y_d#0 ] +Added variable sum::$0 to live range equivalence class [ sum::$0 ] +Added variable sum::return_c#2 to live range equivalence class [ sum::return_c#2 ] +Added variable sum::return_d#2 to live range equivalence class [ sum::return_d#2 ] +Added variable sum::d to live range equivalence class [ sum::d ] +Complete equivalence classes +[ sum::a#2 ] +[ sum::b#2 ] +[ sum::return_c#0 ] +[ main::x_c#0 ] +[ sum::return_d#1 ] +[ main::y_d#0 ] +[ sum::$0 ] +[ sum::return_c#2 ] +[ sum::return_d#2 ] +[ sum::d ] +Allocated zp[1]:2 [ sum::a#2 ] +Allocated zp[1]:3 [ sum::b#2 ] +Allocated zp[1]:4 [ sum::return_c#0 ] +Allocated zp[1]:5 [ main::x_c#0 ] +Allocated zp[1]:6 [ sum::return_d#1 ] +Allocated zp[1]:7 [ main::y_d#0 ] +Allocated zp[1]:8 [ sum::$0 ] +Allocated zp[1]:9 [ sum::return_c#2 ] +Allocated zp[1]:10 [ sum::return_d#2 ] +Allocated zp[2]:11 [ sum::d ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [11] sum::$0 = sum::a#2 + sum::b#2 [ sum::b#2 sum::$0 sum::d ] ( sum:1 [ sum::b#2 sum::$0 sum::d ] { { sum::return_c#0 = sum::return_c#2 } } sum:5 [ sum::b#2 sum::$0 sum::d ] { { sum::return_d#1 = sum::return_d#2 } } ) always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:3 [ sum::b#2 ] +Statement [11] sum::$0 = sum::a#2 + sum::b#2 [ sum::b#2 sum::$0 sum::d ] ( sum:1 [ sum::b#2 sum::$0 sum::d ] { { sum::return_c#0 = sum::return_c#2 } } sum:5 [ sum::b#2 sum::$0 sum::d ] { { sum::return_d#1 = sum::return_d#2 } } ) always clobbers reg byte a +Potential registers zp[1]:2 [ sum::a#2 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:3 [ sum::b#2 ] : zp[1]:3 , reg byte x , reg byte y , +Potential registers zp[1]:4 [ sum::return_c#0 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:5 [ main::x_c#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:6 [ sum::return_d#1 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:7 [ main::y_d#0 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:8 [ sum::$0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:9 [ sum::return_c#2 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y , +Potential registers zp[1]:10 [ sum::return_d#2 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y , +Potential registers zp[2]:11 [ sum::d ] : zp[2]:11 , + +REGISTER UPLIFT SCOPES +Uplift Scope [sum] 22: zp[1]:8 [ sum::$0 ] 11: zp[1]:2 [ sum::a#2 ] 7.33: zp[1]:3 [ sum::b#2 ] 4.33: zp[1]:10 [ sum::return_d#2 ] 4: zp[1]:4 [ sum::return_c#0 ] 4: zp[1]:6 [ sum::return_d#1 ] 3.25: zp[1]:9 [ sum::return_c#2 ] 0: zp[2]:11 [ sum::d ] +Uplift Scope [main] 4: zp[1]:5 [ main::x_c#0 ] 4: zp[1]:7 [ main::y_d#0 ] +Uplift Scope [Data] +Uplift Scope [] + +Uplifting [sum] best 104 combination reg byte a [ sum::$0 ] reg byte a [ sum::a#2 ] reg byte x [ sum::b#2 ] reg byte a [ sum::return_d#2 ] zp[1]:4 [ sum::return_c#0 ] zp[1]:6 [ sum::return_d#1 ] zp[1]:9 [ sum::return_c#2 ] zp[2]:11 [ sum::d ] +Limited combination testing to 100 combinations of 12288 possible. +Uplifting [main] best 92 combination reg byte a [ main::x_c#0 ] reg byte a [ main::y_d#0 ] +Uplifting [Data] best 92 combination +Uplifting [] best 92 combination +Attempting to uplift remaining variables inzp[1]:4 [ sum::return_c#0 ] +Uplifting [sum] best 86 combination reg byte a [ sum::return_c#0 ] +Attempting to uplift remaining variables inzp[1]:6 [ sum::return_d#1 ] +Uplifting [sum] best 80 combination reg byte a [ sum::return_d#1 ] +Attempting to uplift remaining variables inzp[1]:9 [ sum::return_c#2 ] +Uplifting [sum] best 76 combination reg byte x [ sum::return_c#2 ] +Allocated (was zp[2]:11) zp[2]:2 [ sum::d ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Test intermediate vars + // Upstart + // Commodore 64 PRG executable file +.file [name="intermediates-struct.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 + .const OFFSET_STRUCT_DATA_D = 1 + // #pragma struct_model(classic) + .label SCREEN = $400 +.segment Code + // main +main: { + // [1] call sum + // [10] phi from main to sum [phi:main->sum] + sum_from_main: + // [10] phi sum::b#2 = 2 [phi:main->sum#0] -- vbuxx=vbuc1 + ldx #2 + // [10] phi sum::a#2 = 1 [phi:main->sum#1] -- vbuaa=vbuc1 + lda #1 + jsr sum + // [2] sum::return_c#0 = sum::return_c#2 -- vbuaa=vbuxx + txa + jmp __b1 + // main::@1 + __b1: + // [3] main::x_c#0 = sum::return_c#0 + // [4] *SCREEN = main::x_c#0 -- _deref_pbuc1=vbuaa + sta SCREEN + // [5] call sum + // [10] phi from main::@1 to sum [phi:main::@1->sum] + sum_from___b1: + // [10] phi sum::b#2 = 4 [phi:main::@1->sum#0] -- vbuxx=vbuc1 + ldx #4 + // [10] phi sum::a#2 = 3 [phi:main::@1->sum#1] -- vbuaa=vbuc1 + lda #3 + jsr sum + // [6] sum::return_d#1 = sum::return_d#2 + jmp __b2 + // main::@2 + __b2: + // [7] main::y_d#0 = sum::return_d#1 + // [8] *(SCREEN+1) = main::y_d#0 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + jmp __breturn + // main::@return + __breturn: + // [9] return + rts +} + // sum +// sum(byte register(A) a, byte register(X) b) +sum: { + .label d = 2 + // [11] sum::$0 = sum::a#2 + sum::b#2 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // [12] *((byte*)&sum::d) = sum::$0 -- _deref_pbuc1=vbuaa + sta.z d + // [13] *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) = sum::b#2 -- _deref_pbuc1=vbuxx + stx d+OFFSET_STRUCT_DATA_D + // [14] sum::return_c#2 = *((byte*)&sum::d) -- vbuxx=_deref_pbuc1 + ldx.z d + // [15] sum::return_d#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) -- vbuaa=_deref_pbuc1 + lda d+OFFSET_STRUCT_DATA_D + jmp __breturn + // sum::@return + __breturn: + // [16] 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 ldx.z d with TAX +Removing instruction sum_from_main: +Removing instruction __b1: +Removing instruction sum_from___b1: +Removing instruction __b2: +Removing instruction __breturn: +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +constant byte OFFSET_STRUCT_DATA_D = 1 +constant byte* const SCREEN = (byte*) 1024 +byte idx +void main() +byte main::x_c +byte main::x_c#0 reg byte a 4.0 +byte main::y_d +byte main::y_d#0 reg byte a 4.0 +struct Data sum(byte sum::a , byte sum::b) +byte~ sum::$0 reg byte a 22.0 +byte sum::a +byte sum::a#2 reg byte a 11.0 +byte sum::b +byte sum::b#2 reg byte x 7.333333333333333 +struct Data sum::d loadstore zp[2]:2 +struct Data sum::return +byte sum::return_c +byte sum::return_c#0 reg byte a 4.0 +byte sum::return_c#2 reg byte x 3.25 +byte sum::return_d +byte sum::return_d#1 reg byte a 4.0 +byte sum::return_d#2 reg byte a 4.333333333333333 + +reg byte a [ sum::a#2 ] +reg byte x [ sum::b#2 ] +reg byte a [ sum::return_c#0 ] +reg byte a [ main::x_c#0 ] +reg byte a [ sum::return_d#1 ] +reg byte a [ main::y_d#0 ] +reg byte a [ sum::$0 ] +reg byte x [ sum::return_c#2 ] +reg byte a [ sum::return_d#2 ] +zp[2]:2 [ sum::d ] + + +FINAL ASSEMBLER +Score: 63 + + // File Comments +// Test intermediate vars + // Upstart + // Commodore 64 PRG executable file +.file [name="intermediates-struct.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 + .const OFFSET_STRUCT_DATA_D = 1 + // #pragma struct_model(classic) + .label SCREEN = $400 +.segment Code + // main +main: { + // sum(1,2) + // [1] call sum + // [10] phi from main to sum [phi:main->sum] + // [10] phi sum::b#2 = 2 [phi:main->sum#0] -- vbuxx=vbuc1 + ldx #2 + // [10] phi sum::a#2 = 1 [phi:main->sum#1] -- vbuaa=vbuc1 + lda #1 + jsr sum + // sum(1,2) + // [2] sum::return_c#0 = sum::return_c#2 -- vbuaa=vbuxx + txa + // main::@1 + // struct Data x = sum(1,2) + // [3] main::x_c#0 = sum::return_c#0 + // SCREEN[idx++] = x.c + // [4] *SCREEN = main::x_c#0 -- _deref_pbuc1=vbuaa + sta SCREEN + // sum(3, 4) + // [5] call sum + // [10] phi from main::@1 to sum [phi:main::@1->sum] + // [10] phi sum::b#2 = 4 [phi:main::@1->sum#0] -- vbuxx=vbuc1 + ldx #4 + // [10] phi sum::a#2 = 3 [phi:main::@1->sum#1] -- vbuaa=vbuc1 + lda #3 + jsr sum + // sum(3, 4) + // [6] sum::return_d#1 = sum::return_d#2 + // main::@2 + // struct Data y = sum(3, 4) + // [7] main::y_d#0 = sum::return_d#1 + // SCREEN[idx++] = y.d + // [8] *(SCREEN+1) = main::y_d#0 -- _deref_pbuc1=vbuaa + sta SCREEN+1 + // main::@return + // } + // [9] return + rts +} + // sum +// sum(byte register(A) a, byte register(X) b) +sum: { + .label d = 2 + // a+b + // [11] sum::$0 = sum::a#2 + sum::b#2 -- vbuaa=vbuaa_plus_vbuxx + stx.z $ff + clc + adc.z $ff + // __ma struct Data d = { a+b, b } + // [12] *((byte*)&sum::d) = sum::$0 -- _deref_pbuc1=vbuaa + sta.z d + // [13] *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) = sum::b#2 -- _deref_pbuc1=vbuxx + stx d+OFFSET_STRUCT_DATA_D + // return d; + // [14] sum::return_c#2 = *((byte*)&sum::d) -- vbuxx=_deref_pbuc1 + tax + // [15] sum::return_d#2 = *((byte*)&sum::d+OFFSET_STRUCT_DATA_D) -- vbuaa=_deref_pbuc1 + lda d+OFFSET_STRUCT_DATA_D + // sum::@return + // } + // [16] return + rts +} + // File Data + diff --git a/src/test/ref/intermediates-struct.sym b/src/test/ref/intermediates-struct.sym new file mode 100644 index 000000000..2ad8f8a91 --- /dev/null +++ b/src/test/ref/intermediates-struct.sym @@ -0,0 +1,33 @@ +constant byte OFFSET_STRUCT_DATA_D = 1 +constant byte* const SCREEN = (byte*) 1024 +byte idx +void main() +byte main::x_c +byte main::x_c#0 reg byte a 4.0 +byte main::y_d +byte main::y_d#0 reg byte a 4.0 +struct Data sum(byte sum::a , byte sum::b) +byte~ sum::$0 reg byte a 22.0 +byte sum::a +byte sum::a#2 reg byte a 11.0 +byte sum::b +byte sum::b#2 reg byte x 7.333333333333333 +struct Data sum::d loadstore zp[2]:2 +struct Data sum::return +byte sum::return_c +byte sum::return_c#0 reg byte a 4.0 +byte sum::return_c#2 reg byte x 3.25 +byte sum::return_d +byte sum::return_d#1 reg byte a 4.0 +byte sum::return_d#2 reg byte a 4.333333333333333 + +reg byte a [ sum::a#2 ] +reg byte x [ sum::b#2 ] +reg byte a [ sum::return_c#0 ] +reg byte a [ main::x_c#0 ] +reg byte a [ sum::return_d#1 ] +reg byte a [ main::y_d#0 ] +reg byte a [ sum::$0 ] +reg byte x [ sum::return_c#2 ] +reg byte a [ sum::return_d#2 ] +zp[2]:2 [ sum::d ]