Adding pointer type conversion cast (byte*) main::screen in (byte*) main::screen ← (number) $400 Culled Empty Block (label) @1 CONTROL FLOW GRAPH SSA @begin: scope:[] from to:@2 main: scope:[main] from @2 (byte*) main::screen#0 ← ((byte*)) (number) $400 (byte**~) main::$0 ← & (byte*) main::screen#0 (byte**) main::pscreen#0 ← (byte**~) main::$0 (byte) sub::ch#0 ← (byte) 'a' (byte**) sub::dst#0 ← (byte**) main::pscreen#0 call sub to:main::@1 main::@1: scope:[main] from main (byte**) main::pscreen#1 ← phi( main/(byte**) main::pscreen#0 ) (byte) sub::ch#1 ← (byte) 'b' (byte**) sub::dst#1 ← (byte**) main::pscreen#1 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 sub: scope:[sub] from main main::@1 (byte**) sub::dst#2 ← phi( main/(byte**) sub::dst#0 main::@1/(byte**) sub::dst#1 ) (byte) sub::ch#2 ← phi( main/(byte) sub::ch#0 main::@1/(byte) sub::ch#1 ) *(*((byte**) sub::dst#2)) ← (byte) sub::ch#2 *((byte**) sub::dst#2) ← ++ *((byte**) sub::dst#2) to:sub::@return sub::@return: scope:[sub] from sub return to:@return @2: scope:[] from @begin call main to:@3 @3: scope:[] from @2 to:@end @end: scope:[] from @3 SYMBOL TABLE SSA (label) @2 (label) @3 (label) @begin (label) @end (void()) main() (byte**~) main::$0 (label) main::@1 (label) main::@2 (label) main::@return (byte**) main::pscreen (byte**) main::pscreen#0 (byte**) main::pscreen#1 (byte*) main::screen (byte*) main::screen#0 (void()) sub((byte) sub::ch , (byte**) sub::dst) (label) sub::@return (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 Inlining cast (byte*) main::screen#0 ← (byte*)(number) $400 Successful SSA optimization Pass2InlineCast Simplifying constant pointer cast (byte*) 1024 Successful SSA optimization PassNCastSimplification Alias (byte**) main::pscreen#0 = (byte**~) main::$0 (byte**) main::pscreen#1 Successful SSA optimization Pass2AliasElimination Constant right-side identified [1] (byte**) main::pscreen#0 ← & (byte*) main::screen#0 Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte**) main::pscreen#0 = &main::screen#0 Constant (const byte) sub::ch#0 = 'a' Constant (const byte) sub::ch#1 = 'b' Successful SSA optimization Pass2ConstantIdentification Constant (const byte**) sub::dst#0 = main::pscreen#0 Constant (const byte**) sub::dst#1 = main::pscreen#0 Successful SSA optimization Pass2ConstantIdentification Inlining constant with var siblings (const byte) sub::ch#0 Inlining constant with var siblings (const byte) sub::ch#1 Inlining constant with var siblings (const byte**) sub::dst#0 Inlining constant with var siblings (const byte**) sub::dst#1 Constant inlined sub::ch#1 = (byte) 'b' Constant inlined sub::ch#0 = (byte) 'a' Constant inlined sub::dst#1 = (const byte**) main::pscreen#0 Constant inlined sub::dst#0 = (const byte**) main::pscreen#0 Successful SSA optimization Pass2ConstantInlining Identical Phi Values (byte**) sub::dst#2 (const byte**) main::pscreen#0 Successful SSA optimization Pass2IdenticalPhiElimination Adding NOP phi() at start of @begin Adding NOP phi() at start of @2 Adding NOP phi() at start of @3 Adding NOP phi() at start of @end Adding NOP phi() at start of main::@1 Adding NOP phi() at start of main::@2 CALL GRAPH Calls in [] to main:2 Calls in [main] to sub:6 sub:8 Created 1 initial phi equivalence classes Coalesced down to 1 phi equivalence classes Culled Empty Block (label) @3 Culled Empty Block (label) main::@2 Renumbering block @2 to @1 Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @end Adding NOP phi() at start of main::@1 FINAL CONTROL FLOW GRAPH @begin: scope:[] from [0] phi() to:@1 @1: scope:[] from @begin [1] phi() [2] call main to:@end @end: scope:[] from @1 [3] phi() main: scope:[main] from @1 [4] (byte*) main::screen#0 ← (byte*) 1024 [5] call sub to:main::@1 main::@1: scope:[main] from main [6] phi() [7] call sub to:main::@return main::@return: scope:[main] from main::@1 [8] return to:@return sub: scope:[sub] from main main::@1 [9] (byte) sub::ch#2 ← phi( main/(byte) 'a' main::@1/(byte) 'b' ) [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) to:sub::@return sub::@return: scope:[sub] from sub [12] return to:@return VARIABLE REGISTER WEIGHTS (void()) main() (byte**) main::pscreen (byte*) main::screen (byte*) main::screen#0 20.0 (void()) sub((byte) sub::ch , (byte**) sub::dst) (byte) sub::ch (byte) sub::ch#2 2.0 (byte**) sub::dst Initial phi equivalence classes [ sub::ch#2 ] Added variable main::screen#0 to zero page equivalence class [ main::screen#0 ] Complete equivalence classes [ sub::ch#2 ] [ main::screen#0 ] Allocated zp ZP_BYTE:2 [ sub::ch#2 ] Allocated zp ZP_WORD:3 [ main::screen#0 ] INITIAL ASM //SEG0 File Comments // Tests optimization of constant pointers to pointers //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels //SEG3 @begin bbegin: //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 //SEG5 @1 b1: //SEG6 [2] call main jsr main //SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend //SEG8 @end bend: //SEG9 main main: { .label pscreen = screen .label screen = 3 //SEG10 [4] (byte*) main::screen#0 ← (byte*) 1024 -- pbuz1=pbuc1 lda #<$400 sta screen lda #>$400 sta screen+1 //SEG11 [5] call sub //SEG12 [9] phi from main to sub [phi:main->sub] sub_from_main: //SEG13 [9] phi (byte) sub::ch#2 = (byte) 'a' [phi:main->sub#0] -- vbuz1=vbuc1 lda #'a' sta sub.ch jsr sub //SEG14 [6] phi from main to main::@1 [phi:main->main::@1] b1_from_main: jmp b1 //SEG15 main::@1 b1: //SEG16 [7] call sub //SEG17 [9] phi from main::@1 to sub [phi:main::@1->sub] sub_from_b1: //SEG18 [9] phi (byte) sub::ch#2 = (byte) 'b' [phi:main::@1->sub#0] -- vbuz1=vbuc1 lda #'b' sta sub.ch jsr sub jmp breturn //SEG19 main::@return breturn: //SEG20 [8] return rts } //SEG21 sub // sub(byte zeropage(2) ch) sub: { .label ch = 2 //SEG22 [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 -- _deref__deref_pptc1=vbuz1 lda ch ldy #0 sta (main.pscreen),y //SEG23 [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc main.pscreen bne !+ inc main.pscreen+1 !: jmp breturn //SEG24 sub::@return breturn: //SEG25 [12] return rts } REGISTER UPLIFT POTENTIAL REGISTERS Statement [4] (byte*) main::screen#0 ← (byte*) 1024 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 [ ] ( main:2::sub:5 [ ] main:2::sub:7 [ ] ) always clobbers reg byte y Potential registers zp ZP_BYTE:2 [ sub::ch#2 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_WORD:3 [ main::screen#0 ] : zp ZP_WORD:3 , REGISTER UPLIFT SCOPES Uplift Scope [main] 20: zp ZP_WORD:3 [ main::screen#0 ] Uplift Scope [sub] 2: zp ZP_BYTE:2 [ sub::ch#2 ] Uplift Scope [] Uplifting [main] best 90 combination zp ZP_WORD:3 [ main::screen#0 ] Uplifting [sub] best 81 combination reg byte a [ sub::ch#2 ] Uplifting [] best 81 combination Allocated (was zp ZP_WORD:3) zp ZP_WORD:2 [ main::screen#0 ] ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments // Tests optimization of constant pointers to pointers //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels //SEG3 @begin bbegin: //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] b1_from_bbegin: jmp b1 //SEG5 @1 b1: //SEG6 [2] call main jsr main //SEG7 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend //SEG8 @end bend: //SEG9 main main: { .label pscreen = screen .label screen = 2 //SEG10 [4] (byte*) main::screen#0 ← (byte*) 1024 -- pbuz1=pbuc1 lda #<$400 sta screen lda #>$400 sta screen+1 //SEG11 [5] call sub //SEG12 [9] phi from main to sub [phi:main->sub] sub_from_main: //SEG13 [9] phi (byte) sub::ch#2 = (byte) 'a' [phi:main->sub#0] -- vbuaa=vbuc1 lda #'a' jsr sub //SEG14 [6] phi from main to main::@1 [phi:main->main::@1] b1_from_main: jmp b1 //SEG15 main::@1 b1: //SEG16 [7] call sub //SEG17 [9] phi from main::@1 to sub [phi:main::@1->sub] sub_from_b1: //SEG18 [9] phi (byte) sub::ch#2 = (byte) 'b' [phi:main::@1->sub#0] -- vbuaa=vbuc1 lda #'b' jsr sub jmp breturn //SEG19 main::@return breturn: //SEG20 [8] return rts } //SEG21 sub // sub(byte register(A) ch) sub: { //SEG22 [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 -- _deref__deref_pptc1=vbuaa ldy #0 sta (main.pscreen),y //SEG23 [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc main.pscreen bne !+ inc main.pscreen+1 !: jmp breturn //SEG24 sub::@return breturn: //SEG25 [12] return rts } ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp b1 Removing instruction jmp breturn Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination Removing instruction b1_from_bbegin: Removing instruction b1: Removing instruction bend_from_b1: Removing instruction b1_from_main: Removing instruction sub_from_b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: Removing instruction sub_from_main: Removing instruction b1: Removing instruction breturn: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination Updating BasicUpstart to call main directly Removing instruction jsr main Succesful ASM optimization Pass5SkipBegin Removing instruction bbegin: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (void()) main() (label) main::@1 (label) main::@return (byte**) main::pscreen (const byte**) main::pscreen#0 pscreen = &(byte*) main::screen#0 (byte*) main::screen (byte*) main::screen#0 screen zp ZP_WORD:2 20.0 (void()) sub((byte) sub::ch , (byte**) sub::dst) (label) sub::@return (byte) sub::ch (byte) sub::ch#2 reg byte a 2.0 (byte**) sub::dst reg byte a [ sub::ch#2 ] zp ZP_WORD:2 [ main::screen#0 ] FINAL ASSEMBLER Score: 60 //SEG0 File Comments // Tests optimization of constant pointers to pointers //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels //SEG3 @begin //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] //SEG5 @1 //SEG6 [2] call main //SEG7 [3] phi from @1 to @end [phi:@1->@end] //SEG8 @end //SEG9 main main: { .label pscreen = screen .label screen = 2 //SEG10 [4] (byte*) main::screen#0 ← (byte*) 1024 -- pbuz1=pbuc1 lda #<$400 sta screen lda #>$400 sta screen+1 //SEG11 [5] call sub //SEG12 [9] phi from main to sub [phi:main->sub] //SEG13 [9] phi (byte) sub::ch#2 = (byte) 'a' [phi:main->sub#0] -- vbuaa=vbuc1 lda #'a' jsr sub //SEG14 [6] phi from main to main::@1 [phi:main->main::@1] //SEG15 main::@1 //SEG16 [7] call sub //SEG17 [9] phi from main::@1 to sub [phi:main::@1->sub] //SEG18 [9] phi (byte) sub::ch#2 = (byte) 'b' [phi:main::@1->sub#0] -- vbuaa=vbuc1 lda #'b' jsr sub //SEG19 main::@return //SEG20 [8] return rts } //SEG21 sub // sub(byte register(A) ch) sub: { //SEG22 [10] *(*((const byte**) main::pscreen#0)) ← (byte) sub::ch#2 -- _deref__deref_pptc1=vbuaa ldy #0 sta (main.pscreen),y //SEG23 [11] *((const byte**) main::pscreen#0) ← ++ *((const byte**) main::pscreen#0) -- _deref_pptc1=_inc__deref_pptc1 inc main.pscreen bne !+ inc main.pscreen+1 !: //SEG24 sub::@return //SEG25 [12] return rts }