Setting inferred volatile on symbol affected by address-of (byte*) main::addrA ← &(byte) A Identified constant variable (byte*) SCREEN Identified constant variable (byte) main::B Identified constant variable (byte*) main::addrA Identified constant variable (byte) sub::C Culled Empty Block (label) @1 CONTROL FLOW GRAPH SSA @begin: scope:[] from (byte) A#0 ← (byte) 'a' to:@2 (void()) main() main: scope:[main] from @2 (byte) A#1 ← phi( @2/(byte) A#3 ) *((const byte*) SCREEN + (number) 0) ← (byte) A#1 *((const byte*) SCREEN + (number) 1) ← (const byte) main::B *((const byte*) SCREEN + (number) 2) ← *((const byte*) main::addrA) call sub to:main::@1 main::@1: scope:[main] from main to:main::@return main::@return: scope:[main] from main::@1 return to:@return (void()) sub() sub: scope:[sub] from main (byte) A#2 ← phi( main/(byte) A#1 ) *((const byte*) SCREEN + (number) 3) ← (const byte) sub::C (number~) sub::$0 ← (byte) A#2 + (number) 1 (byte) sub::D#0 ← (number~) sub::$0 *((const byte*) SCREEN + (number) 4) ← (byte) sub::D#0 to:sub::@return sub::@return: scope:[sub] from sub return to:@return @2: scope:[] from @begin (byte) A#3 ← phi( @begin/(byte) A#0 ) 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 (byte) A (byte) A#0 (byte) A#1 (byte) A#2 (byte) A#3 (const byte*) SCREEN = (byte*)(number) $400 (void()) main() (label) main::@1 (label) main::@return (const byte) main::B = (byte) 'b' (const byte*) main::addrA = &(byte) A (void()) sub() (number~) sub::$0 (label) sub::@return (const byte) sub::C = (byte) 'c' (byte) sub::D (byte) sub::D#0 Adding number conversion cast (unumber) 0 in *((const byte*) SCREEN + (number) 0) ← (byte) A#1 Adding number conversion cast (unumber) 1 in *((const byte*) SCREEN + (number) 1) ← (const byte) main::B Adding number conversion cast (unumber) 2 in *((const byte*) SCREEN + (number) 2) ← *((const byte*) main::addrA) Adding number conversion cast (unumber) 3 in *((const byte*) SCREEN + (number) 3) ← (const byte) sub::C Adding number conversion cast (unumber) 1 in (number~) sub::$0 ← (byte) A#2 + (number) 1 Adding number conversion cast (unumber) sub::$0 in (number~) sub::$0 ← (byte) A#2 + (unumber)(number) 1 Adding number conversion cast (unumber) 4 in *((const byte*) SCREEN + (number) 4) ← (byte) sub::D#0 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant pointer cast (byte*) 1024 Simplifying constant integer cast 0 Simplifying constant integer cast 1 Simplifying constant integer cast 2 Simplifying constant integer cast 3 Simplifying constant integer cast 1 Simplifying constant integer cast 4 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 3 Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 4 Successful SSA optimization PassNFinalizeNumberTypeConversions Inferred type updated to byte in (unumber~) sub::$0 ← (byte) A#2 + (byte) 1 Alias (byte) sub::D#0 = (byte~) sub::$0 Alias (byte) A#0 = (byte) A#3 Successful SSA optimization Pass2AliasElimination Identical Phi Values (byte) A#1 (byte) A#0 Identical Phi Values (byte) A#2 (byte) A#1 Successful SSA optimization Pass2IdenticalPhiElimination Simplifying expression containing zero SCREEN in [2] *((const byte*) SCREEN + (byte) 0) ← (byte) A#0 Successful SSA optimization PassNSimplifyExpressionWithZero Consolidated array index constant in *(SCREEN+1) Consolidated array index constant in *(SCREEN+2) Consolidated array index constant in *(SCREEN+3) Consolidated array index constant in *(SCREEN+4) Successful SSA optimization Pass2ConstantAdditionElimination 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 CALL GRAPH Calls in [] to main:2 Calls in [main] to sub:8 Created 0 initial phi equivalence classes Coalesced down to 0 phi equivalence classes Culled Empty Block (label) @3 Culled Empty Block (label) main::@1 Renumbering block @2 to @1 Adding NOP phi() at start of @1 Adding NOP phi() at start of @end FINAL CONTROL FLOW GRAPH @begin: scope:[] from [0] (byte) A#0 ← (byte) 'a' to:@1 @1: scope:[] from @begin [1] phi() [2] call main to:@end @end: scope:[] from @1 [3] phi() (void()) main() main: scope:[main] from @1 [4] *((const byte*) SCREEN) ← (byte) A#0 [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::B [6] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::addrA) [7] call sub to:main::@return main::@return: scope:[main] from main [8] return to:@return (void()) sub() sub: scope:[sub] from main [9] *((const byte*) SCREEN+(byte) 3) ← (const byte) sub::C [10] (byte) sub::D#0 ← (byte) A#0 + (byte) 1 [11] *((const byte*) SCREEN+(byte) 4) ← (byte) sub::D#0 to:sub::@return sub::@return: scope:[sub] from sub [12] return to:@return VARIABLE REGISTER WEIGHTS (byte) A (byte) A#0 1.0 (void()) main() (void()) sub() (byte) sub::D (byte) sub::D#0 4.0 Initial phi equivalence classes Added variable sub::D#0 to zero page equivalence class [ sub::D#0 ] Complete equivalence classes [ A#0 ] [ sub::D#0 ] Allocated zp[1]:2 [ A#0 ] Allocated zp[1]:3 [ sub::D#0 ] INITIAL ASM Target platform is c64basic / MOS6502X // File Comments // Tests that constants are identified early // Upstart .pc = $801 "Basic" :BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels .label SCREEN = $400 .label A = 2 // @begin __bbegin: // [0] (byte) A#0 ← (byte) 'a' -- vbuz1=vbuc1 // Not an early constant (address-of is used) lda #'a' sta.z A // [1] phi from @begin to @1 [phi:@begin->@1] __b1_from___bbegin: jmp __b1 // @1 __b1: // [2] call main jsr main // [3] phi from @1 to @end [phi:@1->@end] __bend_from___b1: jmp __bend // @end __bend: // main main: { .const B = 'b' .label addrA = A // [4] *((const byte*) SCREEN) ← (byte) A#0 -- _deref_pbuc1=vbuz1 lda.z A sta SCREEN // [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::B -- _deref_pbuc1=vbuc2 lda #B sta SCREEN+1 // [6] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::addrA) -- _deref_pbuc1=_deref_pbuc2 lda.z addrA sta SCREEN+2 // [7] call sub jsr sub jmp __breturn // main::@return __breturn: // [8] return rts } // sub sub: { .const C = 'c' .label D = 3 // [9] *((const byte*) SCREEN+(byte) 3) ← (const byte) sub::C -- _deref_pbuc1=vbuc2 lda #C sta SCREEN+3 // [10] (byte) sub::D#0 ← (byte) A#0 + (byte) 1 -- vbuz1=vbuz2_plus_1 ldy.z A iny sty.z D // [11] *((const byte*) SCREEN+(byte) 4) ← (byte) sub::D#0 -- _deref_pbuc1=vbuz1 lda.z D sta SCREEN+4 jmp __breturn // sub::@return __breturn: // [12] return rts } // File Data REGISTER UPLIFT POTENTIAL REGISTERS Statement [0] (byte) A#0 ← (byte) 'a' [ A#0 ] ( [ A#0 ] ) always clobbers reg byte a Statement [4] *((const byte*) SCREEN) ← (byte) A#0 [ A#0 ] ( main:2 [ A#0 ] ) always clobbers reg byte a Statement [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::B [ A#0 ] ( main:2 [ A#0 ] ) always clobbers reg byte a Statement [6] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::addrA) [ A#0 ] ( main:2 [ A#0 ] ) always clobbers reg byte a Statement [9] *((const byte*) SCREEN+(byte) 3) ← (const byte) sub::C [ A#0 ] ( main:2::sub:7 [ A#0 ] ) always clobbers reg byte a Potential registers zp[1]:2 [ A#0 ] : zp[1]:2 , Potential registers zp[1]:3 [ sub::D#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES Uplift Scope [sub] 4: zp[1]:3 [ sub::D#0 ] Uplift Scope [] 1: zp[1]:2 [ A#0 ] Uplift Scope [main] Uplifting [sub] best 76 combination reg byte x [ sub::D#0 ] Uplifting [] best 76 combination zp[1]:2 [ A#0 ] Uplifting [main] best 76 combination Attempting to uplift remaining variables inzp[1]:2 [ A#0 ] Uplifting [] best 76 combination zp[1]:2 [ A#0 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Tests that constants are identified early // Upstart .pc = $801 "Basic" :BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels .label SCREEN = $400 .label A = 2 // @begin __bbegin: // [0] (byte) A#0 ← (byte) 'a' -- vbuz1=vbuc1 // Not an early constant (address-of is used) lda #'a' sta.z A // [1] phi from @begin to @1 [phi:@begin->@1] __b1_from___bbegin: jmp __b1 // @1 __b1: // [2] call main jsr main // [3] phi from @1 to @end [phi:@1->@end] __bend_from___b1: jmp __bend // @end __bend: // main main: { .const B = 'b' .label addrA = A // [4] *((const byte*) SCREEN) ← (byte) A#0 -- _deref_pbuc1=vbuz1 lda.z A sta SCREEN // [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::B -- _deref_pbuc1=vbuc2 lda #B sta SCREEN+1 // [6] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::addrA) -- _deref_pbuc1=_deref_pbuc2 lda.z addrA sta SCREEN+2 // [7] call sub jsr sub jmp __breturn // main::@return __breturn: // [8] return rts } // sub sub: { .const C = 'c' // [9] *((const byte*) SCREEN+(byte) 3) ← (const byte) sub::C -- _deref_pbuc1=vbuc2 lda #C sta SCREEN+3 // [10] (byte) sub::D#0 ← (byte) A#0 + (byte) 1 -- vbuxx=vbuz1_plus_1 ldx.z A inx // [11] *((const byte*) SCREEN+(byte) 4) ← (byte) sub::D#0 -- _deref_pbuc1=vbuxx stx SCREEN+4 jmp __breturn // sub::@return __breturn: // [12] return rts } // File Data ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 Removing instruction jmp __bend Removing instruction jmp __breturn Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination Removing instruction __b1_from___bbegin: Removing instruction __bend_from___b1: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction __b1: Removing instruction __bend: Removing instruction __breturn: Removing instruction __breturn: Succesful ASM optimization Pass5UnusedLabelElimination Adding RTS to root block Succesful ASM optimization Pass5AddMainRts FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (byte) A (byte) A#0 A zp[1]:2 1.0 (const byte*) SCREEN = (byte*) 1024 (void()) main() (label) main::@return (const byte) main::B = (byte) 'b' (const byte*) main::addrA = &(byte) A (void()) sub() (label) sub::@return (const byte) sub::C = (byte) 'c' (byte) sub::D (byte) sub::D#0 reg byte x 4.0 zp[1]:2 [ A#0 ] reg byte x [ sub::D#0 ] FINAL ASSEMBLER Score: 70 // File Comments // Tests that constants are identified early // Upstart .pc = $801 "Basic" :BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels .label SCREEN = $400 .label A = 2 // @begin __bbegin: // A = 'a' // [0] (byte) A#0 ← (byte) 'a' -- vbuz1=vbuc1 // Not an early constant (address-of is used) lda #'a' sta.z A // [1] phi from @begin to @1 [phi:@begin->@1] // @1 // [2] call main jsr main rts // [3] phi from @1 to @end [phi:@1->@end] // @end // main main: { .const B = 'b' .label addrA = A // SCREEN[0] = A // [4] *((const byte*) SCREEN) ← (byte) A#0 -- _deref_pbuc1=vbuz1 lda.z A sta SCREEN // SCREEN[1] = B // [5] *((const byte*) SCREEN+(byte) 1) ← (const byte) main::B -- _deref_pbuc1=vbuc2 lda #B sta SCREEN+1 // SCREEN[2] = *addrA // [6] *((const byte*) SCREEN+(byte) 2) ← *((const byte*) main::addrA) -- _deref_pbuc1=_deref_pbuc2 lda.z addrA sta SCREEN+2 // sub() // [7] call sub jsr sub // main::@return // } // [8] return rts } // sub sub: { .const C = 'c' // SCREEN[3] = C // [9] *((const byte*) SCREEN+(byte) 3) ← (const byte) sub::C -- _deref_pbuc1=vbuc2 lda #C sta SCREEN+3 // D = A+1 // [10] (byte) sub::D#0 ← (byte) A#0 + (byte) 1 -- vbuxx=vbuz1_plus_1 ldx.z A inx // SCREEN[4] = D // [11] *((const byte*) SCREEN+(byte) 4) ← (byte) sub::D#0 -- _deref_pbuc1=vbuxx stx SCREEN+4 // sub::@return // } // [12] return rts } // File Data