Setting inferred volatile on symbol affected by address-of main::pscreen = &main::screen CONTROL FLOW GRAPH SSA void main() main: scope:[main] from __start main::screen = (byte*)$400 sub::ch#0 = 'a' sub::dst#0 = main::pscreen call sub to:main::@1 main::@1: scope:[main] from main sub::ch#1 = 'b' sub::dst#1 = main::pscreen call sub to:main::@2 main::@2: scope:[main] from main::@1 to:main::@return main::@return: scope:[main] from main::@2 return to:@return void sub(byte sub::ch , byte** sub::dst) sub: scope:[sub] from main main::@1 sub::dst#2 = phi( main/sub::dst#0, main::@1/sub::dst#1 ) sub::ch#2 = phi( main/sub::ch#0, main::@1/sub::ch#1 ) *(*sub::dst#2) = sub::ch#2 *sub::dst#2 = ++ *sub::dst#2 to:sub::@return sub::@return: scope:[sub] from sub return to:@return void __start() __start: scope:[__start] from call main to:__start::@1 __start::@1: scope:[__start] from __start to:__start::@return __start::@return: scope:[__start] from __start::@1 return to:@return SYMBOL TABLE SSA void __start() void main() const byte** main::pscreen = &main::screen volatile byte* main::screen loadstore void sub(byte sub::ch , byte** sub::dst) byte sub::ch byte sub::ch#0 byte sub::ch#1 byte sub::ch#2 byte** sub::dst byte** sub::dst#0 byte** sub::dst#1 byte** sub::dst#2 Simplifying constant pointer cast (byte*) 1024 Successful SSA optimization PassNCastSimplification Constant sub::ch#0 = 'a' Constant sub::dst#0 = main::pscreen Constant sub::ch#1 = 'b' Constant sub::dst#1 = main::pscreen Successful SSA optimization Pass2ConstantIdentification Removing unused procedure __start Removing unused procedure block __start Removing unused procedure block __start::@1 Removing unused procedure block __start::@return Successful SSA optimization PassNEliminateEmptyStart Inlining constant with var siblings sub::ch#0 Inlining constant with var siblings sub::dst#0 Inlining constant with var siblings sub::ch#1 Inlining constant with var siblings sub::dst#1 Constant inlined sub::ch#1 = 'b' Constant inlined sub::ch#0 = 'a' Constant inlined sub::dst#1 = main::pscreen Constant inlined sub::dst#0 = main::pscreen Successful SSA optimization Pass2ConstantInlining Identical Phi Values sub::dst#2 main::pscreen Successful SSA optimization Pass2IdenticalPhiElimination Adding NOP phi() at start of main::@1 Adding NOP phi() at start of main::@2 CALL GRAPH Calls in [main] to sub:1 sub:3 Created 1 initial phi equivalence classes Coalesced down to 1 phi equivalence classes Culled Empty Block label main::@2 Adding NOP phi() at start of main::@1 FINAL CONTROL FLOW GRAPH void main() main: scope:[main] from [0] main::screen = (byte*) 1024 [1] call sub to:main::@1 main::@1: scope:[main] from main [2] phi() [3] call sub to:main::@return main::@return: scope:[main] from main::@1 [4] return to:@return void sub(byte sub::ch , byte** sub::dst) sub: scope:[sub] from main main::@1 [5] sub::ch#2 = phi( main/'a', main::@1/'b' ) [6] *(*main::pscreen) = sub::ch#2 [7] *main::pscreen = ++ *main::pscreen to:sub::@return sub::@return: scope:[sub] from sub [8] return to:@return VARIABLE REGISTER WEIGHTS void main() volatile byte* main::screen loadstore 20.0 void sub(byte sub::ch , byte** sub::dst) byte sub::ch byte sub::ch#2 11.0 byte** sub::dst Initial phi equivalence classes [ sub::ch#2 ] Added variable main::screen to live range equivalence class [ main::screen ] Complete equivalence classes [ sub::ch#2 ] [ main::screen ] Allocated zp[1]:2 [ sub::ch#2 ] Allocated zp[2]:3 [ main::screen ] REGISTER UPLIFT POTENTIAL REGISTERS Statement [0] main::screen = (byte*) 1024 [ ] ( [ ] { } ) always clobbers reg byte a Statement [6] *(*main::pscreen) = sub::ch#2 [ ] ( sub:1 [ ] { } sub:3 [ ] { } ) always clobbers reg byte y Potential registers zp[1]:2 [ sub::ch#2 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y , Potential registers zp[2]:3 [ main::screen ] : zp[2]:3 , REGISTER UPLIFT SCOPES Uplift Scope [main] 20: zp[2]:3 [ main::screen ] Uplift Scope [sub] 11: zp[1]:2 [ sub::ch#2 ] Uplift Scope [] Uplifting [main] best 88 combination zp[2]:3 [ main::screen ] Uplifting [sub] best 79 combination reg byte a [ sub::ch#2 ] Uplifting [] best 79 combination Allocated (was zp[2]:3) zp[2]:2 [ main::screen ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Tests optimization of constant pointers to pointers // Upstart // Commodore 64 PRG executable file .file [name="ptrptr-optimize-1.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$0801] .segmentdef Code [start=$80d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(main) // Global Constants & labels .segment Code // main main: { .label pscreen = screen .label screen = 2 // [0] main::screen = (byte*) 1024 -- pbuz1=pbuc1 lda #<$400 sta.z screen lda #>$400 sta.z screen+1 // [1] call sub // [5] phi from main to sub [phi:main->sub] sub_from_main: // [5] phi sub::ch#2 = 'a' [phi:main->sub#0] -- vbuaa=vbuc1 lda #'a' jsr sub // [2] phi from main to main::@1 [phi:main->main::@1] __b1_from_main: jmp __b1 // main::@1 __b1: // [3] call sub // [5] phi from main::@1 to sub [phi:main::@1->sub] sub_from___b1: // [5] phi sub::ch#2 = 'b' [phi:main::@1->sub#0] -- vbuaa=vbuc1 lda #'b' jsr sub jmp __breturn // main::@return __breturn: // [4] return rts } // sub // sub(byte register(A) ch) sub: { // [6] *(*main::pscreen) = sub::ch#2 -- _deref_(_deref_qbuc1)=vbuaa ldy.z main.pscreen sty.z $fe ldy.z main.pscreen+1 sty.z $ff ldy #0 sta ($fe),y // [7] *main::pscreen = ++ *main::pscreen -- _deref_qbuc1=_inc__deref_qbuc1 inc.z main.pscreen bne !+ inc.z main.pscreen+1 !: jmp __breturn // sub::@return __breturn: // [8] return rts } // File Data ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 Removing instruction jmp __breturn Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination Removing instruction __b1_from_main: Removing instruction sub_from___b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction sub_from_main: Removing instruction __b1: Removing instruction __breturn: Removing instruction __breturn: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE void main() const byte** main::pscreen = &main::screen volatile byte* main::screen loadstore zp[2]:2 20.0 void sub(byte sub::ch , byte** sub::dst) byte sub::ch byte sub::ch#2 reg byte a 11.0 byte** sub::dst reg byte a [ sub::ch#2 ] zp[2]:2 [ main::screen ] FINAL ASSEMBLER Score: 70 // File Comments // Tests optimization of constant pointers to pointers // Upstart // Commodore 64 PRG executable file .file [name="ptrptr-optimize-1.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$0801] .segmentdef Code [start=$80d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(main) // Global Constants & labels .segment Code // main main: { .label pscreen = screen .label screen = 2 // screen = 0x400 // [0] main::screen = (byte*) 1024 -- pbuz1=pbuc1 lda #<$400 sta.z screen lda #>$400 sta.z screen+1 // sub('a',pscreen) // [1] call sub // [5] phi from main to sub [phi:main->sub] // [5] phi sub::ch#2 = 'a' [phi:main->sub#0] -- vbuaa=vbuc1 lda #'a' jsr sub // [2] phi from main to main::@1 [phi:main->main::@1] // main::@1 // sub('b',pscreen) // [3] call sub // [5] phi from main::@1 to sub [phi:main::@1->sub] // [5] phi sub::ch#2 = 'b' [phi:main::@1->sub#0] -- vbuaa=vbuc1 lda #'b' jsr sub // main::@return // } // [4] return rts } // sub // sub(byte register(A) ch) sub: { // *(*dst)++ = ch // [6] *(*main::pscreen) = sub::ch#2 -- _deref_(_deref_qbuc1)=vbuaa ldy.z main.pscreen sty.z $fe ldy.z main.pscreen+1 sty.z $ff ldy #0 sta ($fe),y // *(*dst)++ = ch; // [7] *main::pscreen = ++ *main::pscreen -- _deref_qbuc1=_inc__deref_qbuc1 inc.z main.pscreen bne !+ inc.z main.pscreen+1 !: // sub::@return // } // [8] return rts } // File Data