Culled Empty Block (label) main::@2 Culled Empty Block (label) @1 Culled Empty Block (label) sub1::@1 CONTROL FLOW GRAPH SSA @begin: scope:[] from to:@2 (void()) main() main: scope:[main] from @2 (byte*) main::SCREEN ← ((byte*)) (number) $400 (byte) main::i#0 ← (byte) 0 to:main::@1 main::@1: scope:[main] from main main::@3 (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 ) (byte) sub1::i#0 ← (byte) main::i#2 call sub1 (byte) sub1::return#0 ← (byte) sub1::return#2 to:main::@3 main::@3: scope:[main] from main::@1 (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 ) (byte) sub1::return#3 ← phi( main::@1/(byte) sub1::return#0 ) (byte~) main::$0 ← (byte) sub1::return#3 *((byte*) main::SCREEN + (byte) main::i#3) ← (byte~) main::$0 (byte) main::i#1 ← (byte) main::i#3 + rangenext(0,2) (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,2) if((bool~) main::$1) goto main::@1 to:main::@return main::@return: scope:[main] from main::@3 return to:@return (byte()) sub1((byte) sub1::i) sub1: scope:[sub1] from main::@1 (byte) sub1::i#1 ← phi( main::@1/(byte) sub1::i#0 ) (byte~) sub1::$0 ← (byte) sub1::i#1 + (byte) sub1::i#1 (byte) sub1::return#1 ← (byte~) sub1::$0 to:sub1::@return sub1::@return: scope:[sub1] from sub1 (byte) sub1::return#4 ← phi( sub1/(byte) sub1::return#1 ) (byte) sub1::return#2 ← (byte) sub1::return#4 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 (bool~) main::$1 (label) main::@1 (label) main::@3 (label) main::@return (byte*) main::SCREEN (byte) main::i (byte) main::i#0 (byte) main::i#1 (byte) main::i#2 (byte) main::i#3 (byte()) sub1((byte) sub1::i) (byte~) sub1::$0 (label) sub1::@return (byte) sub1::i (byte) sub1::i#0 (byte) sub1::i#1 (byte) sub1::return (byte) sub1::return#0 (byte) sub1::return#1 (byte) sub1::return#2 (byte) sub1::return#3 (byte) sub1::return#4 Inlining cast (byte*) main::SCREEN ← (byte*)(number) $400 Successful SSA optimization Pass2InlineCast Simplifying constant pointer cast (byte*) 1024 Successful SSA optimization PassNCastSimplification Alias (byte) sub1::return#0 = (byte) sub1::return#3 Alias (byte) main::i#2 = (byte) main::i#3 Alias (byte) sub1::return#1 = (byte~) sub1::$0 (byte) sub1::return#4 (byte) sub1::return#2 Successful SSA optimization Pass2AliasElimination Identical Phi Values (byte) sub1::i#1 (byte) sub1::i#0 Successful SSA optimization Pass2IdenticalPhiElimination Simple Condition (bool~) main::$1 [11] if((byte) main::i#1!=rangelast(0,2)) goto main::@1 Successful SSA optimization Pass2ConditionalJumpSimplification Constant (const byte*) main::SCREEN = (byte*) 1024 Successful SSA optimization Pass2ConstantIdentification Resolved ranged next value [9] main::i#1 ← ++ main::i#2 to ++ Resolved ranged comparison value [11] if(main::i#1!=rangelast(0,2)) goto main::@1 to (number) 3 Adding number conversion cast (unumber) 3 in if((byte) main::i#1!=(number) 3) goto main::@1 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant integer cast 3 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 3 Successful SSA optimization PassNFinalizeNumberTypeConversions Added new block during phi lifting main::@4(between main::@3 and main::@1) 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 CALL GRAPH Calls in [] to main:2 Calls in [main] to sub1:9 Created 1 initial phi equivalence classes Coalesced [6] main::i#4 ← main::i#0 Coalesced [16] main::i#5 ← main::i#1 Coalesced down to 1 phi equivalence classes Culled Empty Block (label) @3 Culled Empty Block (label) main::@4 Renumbering block @2 to @1 Renumbering block main::@3 to main::@2 Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @end 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() (void()) main() main: scope:[main] from @1 [4] (byte) main::i#0 ← (byte) 0 to:main::@1 main::@1: scope:[main] from main main::@2 [5] (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 ) [6] (byte) sub1::i#0 ← (byte) main::i#2 [7] call sub1 [8] (byte) sub1::return#0 ← (byte) sub1::return#1 to:main::@2 main::@2: scope:[main] from main::@1 [9] (byte~) main::$0 ← (byte) sub1::return#0 [10] *((const byte*) main::SCREEN + (byte) main::i#2) ← (byte~) main::$0 [11] (byte) main::i#1 ← ++ (byte) main::i#2 [12] if((byte) main::i#1!=(byte) 3) goto main::@1 to:main::@return main::@return: scope:[main] from main::@2 [13] return to:@return (byte()) sub1((byte) sub1::i) sub1: scope:[sub1] from main::@1 [14] (byte) sub1::return#1 ← (byte) sub1::i#0 + (byte) sub1::i#0 to:sub1::@return sub1::@return: scope:[sub1] from sub1 [15] return to:@return VARIABLE REGISTER WEIGHTS (void()) main() (byte~) main::$0 22.0 (byte) main::i (byte) main::i#0 4.0 (byte) main::i#1 16.5 (byte) main::i#2 7.666666666666666 (byte()) sub1((byte) sub1::i) (byte) sub1::i (byte) sub1::i#0 15.0 (byte) sub1::return (byte) sub1::return#0 22.0 (byte) sub1::return#1 4.333333333333333 Initial phi equivalence classes [ main::i#2 main::i#0 main::i#1 ] Added variable sub1::i#0 to zero page equivalence class [ sub1::i#0 ] Added variable sub1::return#0 to zero page equivalence class [ sub1::return#0 ] Added variable main::$0 to zero page equivalence class [ main::$0 ] Added variable sub1::return#1 to zero page equivalence class [ sub1::return#1 ] Complete equivalence classes [ main::i#2 main::i#0 main::i#1 ] [ sub1::i#0 ] [ sub1::return#0 ] [ main::$0 ] [ sub1::return#1 ] Allocated zp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] Allocated zp ZP_BYTE:6 [ sub1::i#0 ] Allocated zp ZP_BYTE:7 [ sub1::return#0 ] Allocated zp ZP_BYTE:8 [ main::$0 ] Allocated zp ZP_BYTE:9 [ sub1::return#1 ] INITIAL ASM Target platform is c64basic / MOS6502X // File Comments // Demonstrates global directive reserving addresses on zeropage // Upstart .pc = $801 "Basic" :BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels // @begin __bbegin: // [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: { .label SCREEN = $400 .label __0 = 8 .label i = 4 // [4] (byte) main::i#0 ← (byte) 0 -- vbuz1=vbuc1 lda #0 sta.z i // [5] phi from main main::@2 to main::@1 [phi:main/main::@2->main::@1] __b1_from_main: __b1_from___b2: // [5] phi (byte) main::i#2 = (byte) main::i#0 [phi:main/main::@2->main::@1#0] -- register_copy jmp __b1 // main::@1 __b1: // [6] (byte) sub1::i#0 ← (byte) main::i#2 -- vbuz1=vbuz2 lda.z i sta.z sub1.i // [7] call sub1 jsr sub1 // [8] (byte) sub1::return#0 ← (byte) sub1::return#1 -- vbuz1=vbuz2 lda.z sub1.return_1 sta.z sub1.return jmp __b2 // main::@2 __b2: // [9] (byte~) main::$0 ← (byte) sub1::return#0 -- vbuz1=vbuz2 lda.z sub1.return sta.z __0 // [10] *((const byte*) main::SCREEN + (byte) main::i#2) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z __0 ldy.z i sta SCREEN,y // [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [12] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #3 cmp.z i bne __b1_from___b2 jmp __breturn // main::@return __breturn: // [13] return rts } // sub1 // sub1(byte zeropage(6) i) sub1: { .label i = 6 .label return = 7 .label return_1 = 9 // [14] (byte) sub1::return#1 ← (byte) sub1::i#0 + (byte) sub1::i#0 -- vbuz1=vbuz2_plus_vbuz2 lda.z i asl sta.z return_1 jmp __breturn // sub1::@return __breturn: // [15] return rts } // File Data REGISTER UPLIFT POTENTIAL REGISTERS Statement [4] (byte) main::i#0 ← (byte) 0 [ main::i#0 ] ( main:2 [ main::i#0 ] ) always clobbers reg byte a Statement [10] *((const byte*) main::SCREEN + (byte) main::i#2) ← (byte~) main::$0 [ main::i#2 ] ( main:2 [ main::i#2 ] ) always clobbers reg byte y Statement [12] if((byte) main::i#1!=(byte) 3) goto main::@1 [ main::i#1 ] ( main:2 [ main::i#1 ] ) always clobbers reg byte a Statement [14] (byte) sub1::return#1 ← (byte) sub1::i#0 + (byte) sub1::i#0 [ sub1::return#1 ] ( main:2::sub1:7 [ main::i#2 sub1::return#1 ] ) always clobbers reg byte a Potential registers zp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] : zp ZP_BYTE:4 , Potential registers zp ZP_BYTE:6 [ sub1::i#0 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:7 [ sub1::return#0 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:8 [ main::$0 ] : zp ZP_BYTE:8 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:9 [ sub1::return#1 ] : zp ZP_BYTE:9 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES Uplift Scope [main] 28.17: zp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] 22: zp ZP_BYTE:8 [ main::$0 ] Uplift Scope [sub1] 22: zp ZP_BYTE:7 [ sub1::return#0 ] 15: zp ZP_BYTE:6 [ sub1::i#0 ] 4.33: zp ZP_BYTE:9 [ sub1::return#1 ] Uplift Scope [] Uplifting [main] best 545 combination zp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] reg byte a [ main::$0 ] Uplifting [sub1] best 419 combination reg byte a [ sub1::return#0 ] reg byte a [ sub1::i#0 ] reg byte a [ sub1::return#1 ] Uplifting [] best 419 combination Attempting to uplift remaining variables inzp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] Uplifting [main] best 419 combination zp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Demonstrates global directive reserving addresses on zeropage // Upstart .pc = $801 "Basic" :BasicUpstart(__bbegin) .pc = $80d "Program" // Global Constants & labels // @begin __bbegin: // [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: { .label SCREEN = $400 .label i = 4 // [4] (byte) main::i#0 ← (byte) 0 -- vbuz1=vbuc1 lda #0 sta.z i // [5] phi from main main::@2 to main::@1 [phi:main/main::@2->main::@1] __b1_from_main: __b1_from___b2: // [5] phi (byte) main::i#2 = (byte) main::i#0 [phi:main/main::@2->main::@1#0] -- register_copy jmp __b1 // main::@1 __b1: // [6] (byte) sub1::i#0 ← (byte) main::i#2 -- vbuaa=vbuz1 lda.z i // [7] call sub1 jsr sub1 // [8] (byte) sub1::return#0 ← (byte) sub1::return#1 jmp __b2 // main::@2 __b2: // [9] (byte~) main::$0 ← (byte) sub1::return#0 // [10] *((const byte*) main::SCREEN + (byte) main::i#2) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuaa ldy.z i sta SCREEN,y // [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [12] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #3 cmp.z i bne __b1_from___b2 jmp __breturn // main::@return __breturn: // [13] return rts } // sub1 // sub1(byte register(A) i) sub1: { // [14] (byte) sub1::return#1 ← (byte) sub1::i#0 + (byte) sub1::i#0 -- vbuaa=vbuaa_plus_vbuaa asl jmp __breturn // sub1::@return __breturn: // [15] return rts } // File Data ASSEMBLER OPTIMIZATIONS Removing instruction jmp __b1 Removing instruction jmp __bend Removing instruction jmp __b1 Removing instruction jmp __b2 Removing instruction jmp __breturn Removing instruction jmp __breturn Succesful ASM optimization Pass5NextJumpElimination Replacing label __bbegin with __b1 Replacing label __b1_from___b2 with __b1 Removing instruction __bbegin: Removing instruction __b1_from___bbegin: Removing instruction __bend_from___b1: Removing instruction __b1_from_main: Removing instruction __b1_from___b2: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction __bend: Removing instruction __b2: 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 __b1: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (void()) main() (byte~) main::$0 reg byte a 22.0 (label) main::@1 (label) main::@2 (label) main::@return (const byte*) main::SCREEN SCREEN = (byte*) 1024 (byte) main::i (byte) main::i#0 i zp ZP_BYTE:4 4.0 (byte) main::i#1 i zp ZP_BYTE:4 16.5 (byte) main::i#2 i zp ZP_BYTE:4 7.666666666666666 (byte()) sub1((byte) sub1::i) (label) sub1::@return (byte) sub1::i (byte) sub1::i#0 reg byte a 15.0 (byte) sub1::return (byte) sub1::return#0 reg byte a 22.0 (byte) sub1::return#1 reg byte a 4.333333333333333 zp ZP_BYTE:4 [ main::i#2 main::i#0 main::i#1 ] reg byte a [ sub1::i#0 ] reg byte a [ sub1::return#0 ] reg byte a [ main::$0 ] reg byte a [ sub1::return#1 ] FINAL ASSEMBLER Score: 314 // File Comments // Demonstrates global directive reserving addresses on zeropage // Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" // Global Constants & labels // @begin // [1] phi from @begin to @1 [phi:@begin->@1] // @1 // [2] call main // [3] phi from @1 to @end [phi:@1->@end] // @end // main main: { .label SCREEN = $400 .label i = 4 // for( volatile byte i : 0..2) // [4] (byte) main::i#0 ← (byte) 0 -- vbuz1=vbuc1 lda #0 sta.z i // [5] phi from main main::@2 to main::@1 [phi:main/main::@2->main::@1] // [5] phi (byte) main::i#2 = (byte) main::i#0 [phi:main/main::@2->main::@1#0] -- register_copy // main::@1 __b1: // sub1(i) // [6] (byte) sub1::i#0 ← (byte) main::i#2 -- vbuaa=vbuz1 lda.z i // [7] call sub1 jsr sub1 // [8] (byte) sub1::return#0 ← (byte) sub1::return#1 // main::@2 // [9] (byte~) main::$0 ← (byte) sub1::return#0 // SCREEN[i] = sub1(i) // [10] *((const byte*) main::SCREEN + (byte) main::i#2) ← (byte~) main::$0 -- pbuc1_derefidx_vbuz1=vbuaa ldy.z i sta SCREEN,y // for( volatile byte i : 0..2) // [11] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc.z i // [12] if((byte) main::i#1!=(byte) 3) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #3 cmp.z i bne __b1 // main::@return // } // [13] return rts } // sub1 // sub1(byte register(A) i) sub1: { // i+i // [14] (byte) sub1::return#1 ← (byte) sub1::i#0 + (byte) sub1::i#0 -- vbuaa=vbuaa_plus_vbuaa asl // sub1::@return // } // [15] return rts } // File Data