Adding pointer type conversion cast (byte*) SCREEN in (byte*) SCREEN ← (number) $400 Identified constant variable (byte*) SCREEN Culled Empty Block (label) main::@8 CONTROL FLOW GRAPH SSA @begin: scope:[] from (byte*) SCREEN#0 ← ((byte*)) (number) $400 to:@1 main: scope:[main] from @1 (byte) main::i#0 ← (byte) 0 to:main::@1 main::@1: scope:[main] from main main::@3 (byte) main::i#4 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 ) (byte) main::j#0 ← (byte) 0 to:main::@2 main::@2: scope:[main] from main::@1 main::@2 (byte) main::i#2 ← phi( main::@1/(byte) main::i#4 main::@2/(byte) main::i#2 ) (byte) main::j#2 ← phi( main::@1/(byte) main::j#0 main::@2/(byte) main::j#1 ) *((byte*) SCREEN#0 + (byte) main::i#2) ← (byte) main::j#2 (byte) main::j#1 ← (byte) main::j#2 + rangenext(0,$64) (bool~) main::$0 ← (byte) main::j#1 != rangelast(0,$64) if((bool~) main::$0) goto main::@2 to:main::@3 main::@3: scope:[main] from main::@2 (byte) main::i#3 ← phi( main::@2/(byte) main::i#2 ) (byte) main::i#1 ← (byte) main::i#3 + rangenext(0,$64) (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,$64) if((bool~) main::$1) goto main::@1 to:main::@4 main::@4: scope:[main] from main::@3 (byte) main::k#0 ← (byte) 0 to:main::@5 main::@5: scope:[main] from main::@4 main::@7 (byte) main::k#4 ← phi( main::@4/(byte) main::k#0 main::@7/(byte) main::k#1 ) (byte) main::l#0 ← (byte) 0 to:main::@6 main::@6: scope:[main] from main::@5 main::@6 (byte) main::k#2 ← phi( main::@5/(byte) main::k#4 main::@6/(byte) main::k#2 ) (byte) main::l#2 ← phi( main::@5/(byte) main::l#0 main::@6/(byte) main::l#1 ) asm { eor#$55 tax } *((byte*) SCREEN#0 + (byte) main::k#2) ← (byte) main::l#2 (byte) main::l#1 ← (byte) main::l#2 + rangenext(0,$64) (bool~) main::$2 ← (byte) main::l#1 != rangelast(0,$64) if((bool~) main::$2) goto main::@6 to:main::@7 main::@7: scope:[main] from main::@6 (byte) main::k#3 ← phi( main::@6/(byte) main::k#2 ) (byte) main::k#1 ← (byte) main::k#3 + rangenext(0,$64) (bool~) main::$3 ← (byte) main::k#1 != rangelast(0,$64) if((bool~) main::$3) goto main::@5 to:main::@return main::@return: scope:[main] from main::@7 return to:@return @1: scope:[] from @begin call main to:@2 @2: scope:[] from @1 to:@end @end: scope:[] from @2 SYMBOL TABLE SSA (label) @1 (label) @2 (label) @begin (label) @end (byte*) SCREEN (byte*) SCREEN#0 (void()) main() (bool~) main::$0 (bool~) main::$1 (bool~) main::$2 (bool~) main::$3 (label) main::@1 (label) main::@2 (label) main::@3 (label) main::@4 (label) main::@5 (label) main::@6 (label) main::@7 (label) main::@return (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::j (byte) main::j#0 (byte) main::j#1 (byte) main::j#2 (byte) main::k (byte) main::k#0 (byte) main::k#1 (byte) main::k#2 (byte) main::k#3 (byte) main::k#4 (byte) main::l (byte) main::l#0 (byte) main::l#1 (byte) main::l#2 Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 Successful SSA optimization Pass2InlineCast Simplifying constant pointer cast (byte*) 1024 Successful SSA optimization PassNCastSimplification Alias (byte) main::i#2 = (byte) main::i#3 Alias (byte) main::k#2 = (byte) main::k#3 Successful SSA optimization Pass2AliasElimination Self Phi Eliminated (byte) main::i#2 Self Phi Eliminated (byte) main::k#2 Successful SSA optimization Pass2SelfPhiElimination Identical Phi Values (byte) main::i#2 (byte) main::i#4 Identical Phi Values (byte) main::k#2 (byte) main::k#4 Successful SSA optimization Pass2IdenticalPhiElimination Simple Condition (bool~) main::$0 [8] if((byte) main::j#1!=rangelast(0,$64)) goto main::@2 Simple Condition (bool~) main::$1 [12] if((byte) main::i#1!=rangelast(0,$64)) goto main::@1 Simple Condition (bool~) main::$2 [21] if((byte) main::l#1!=rangelast(0,$64)) goto main::@6 Simple Condition (bool~) main::$3 [25] if((byte) main::k#1!=rangelast(0,$64)) goto main::@5 Successful SSA optimization Pass2ConditionalJumpSimplification Constant (const byte*) SCREEN#0 = (byte*) 1024 Constant (const byte) main::i#0 = 0 Constant (const byte) main::j#0 = 0 Constant (const byte) main::k#0 = 0 Constant (const byte) main::l#0 = 0 Successful SSA optimization Pass2ConstantIdentification Resolved ranged next value [6] main::j#1 ← ++ main::j#2 to ++ Resolved ranged comparison value [8] if(main::j#1!=rangelast(0,$64)) goto main::@2 to (number) $65 Resolved ranged next value [10] main::i#1 ← ++ main::i#4 to ++ Resolved ranged comparison value [12] if(main::i#1!=rangelast(0,$64)) goto main::@1 to (number) $65 Resolved ranged next value [19] main::l#1 ← ++ main::l#2 to ++ Resolved ranged comparison value [21] if(main::l#1!=rangelast(0,$64)) goto main::@6 to (number) $65 Resolved ranged next value [23] main::k#1 ← ++ main::k#4 to ++ Resolved ranged comparison value [25] if(main::k#1!=rangelast(0,$64)) goto main::@5 to (number) $65 Adding number conversion cast (unumber) $65 in if((byte) main::j#1!=(number) $65) goto main::@2 Adding number conversion cast (unumber) $65 in if((byte) main::i#1!=(number) $65) goto main::@1 Adding number conversion cast (unumber) $65 in if((byte) main::l#1!=(number) $65) goto main::@6 Adding number conversion cast (unumber) $65 in if((byte) main::k#1!=(number) $65) goto main::@5 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant integer cast $65 Simplifying constant integer cast $65 Simplifying constant integer cast $65 Simplifying constant integer cast $65 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) $65 Finalized unsigned number type (byte) $65 Finalized unsigned number type (byte) $65 Finalized unsigned number type (byte) $65 Successful SSA optimization PassNFinalizeNumberTypeConversions Inlining constant with var siblings (const byte) main::i#0 Inlining constant with var siblings (const byte) main::j#0 Inlining constant with var siblings (const byte) main::k#0 Inlining constant with var siblings (const byte) main::l#0 Constant inlined main::i#0 = (byte) 0 Constant inlined main::k#0 = (byte) 0 Constant inlined main::j#0 = (byte) 0 Constant inlined main::l#0 = (byte) 0 Successful SSA optimization Pass2ConstantInlining Added new block during phi lifting main::@9(between main::@3 and main::@1) Added new block during phi lifting main::@10(between main::@2 and main::@2) Added new block during phi lifting main::@11(between main::@7 and main::@5) Added new block during phi lifting main::@12(between main::@6 and main::@6) Adding NOP phi() at start of @begin Adding NOP phi() at start of @1 Adding NOP phi() at start of @2 Adding NOP phi() at start of @end Adding NOP phi() at start of main Adding NOP phi() at start of main::@4 CALL GRAPH Calls in [] to main:2 Created 4 initial phi equivalence classes Coalesced [23] main::k#5 ← main::k#1 Coalesced [24] main::l#3 ← main::l#1 Coalesced [25] main::i#5 ← main::i#1 Coalesced [26] main::j#3 ← main::j#1 Coalesced down to 4 phi equivalence classes Culled Empty Block (label) @2 Culled Empty Block (label) main::@4 Culled Empty Block (label) main::@11 Culled Empty Block (label) main::@12 Culled Empty Block (label) main::@9 Culled Empty Block (label) main::@10 Renumbering block main::@5 to main::@4 Renumbering block main::@6 to main::@5 Renumbering block main::@7 to main::@6 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 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] phi() to:main::@1 main::@1: scope:[main] from main main::@3 [5] (byte) main::i#4 ← phi( main/(byte) 0 main::@3/(byte) main::i#1 ) to:main::@2 main::@2: scope:[main] from main::@1 main::@2 [6] (byte) main::j#2 ← phi( main::@1/(byte) 0 main::@2/(byte) main::j#1 ) [7] *((const byte*) SCREEN#0 + (byte) main::i#4) ← (byte) main::j#2 [8] (byte) main::j#1 ← ++ (byte) main::j#2 [9] if((byte) main::j#1!=(byte) $65) goto main::@2 to:main::@3 main::@3: scope:[main] from main::@2 [10] (byte) main::i#1 ← ++ (byte) main::i#4 [11] if((byte) main::i#1!=(byte) $65) goto main::@1 to:main::@4 main::@4: scope:[main] from main::@3 main::@6 [12] (byte) main::k#4 ← phi( main::@3/(byte) 0 main::@6/(byte) main::k#1 ) to:main::@5 main::@5: scope:[main] from main::@4 main::@5 [13] (byte) main::l#2 ← phi( main::@4/(byte) 0 main::@5/(byte) main::l#1 ) asm { eor#$55 tax } [15] *((const byte*) SCREEN#0 + (byte) main::k#4) ← (byte) main::l#2 [16] (byte) main::l#1 ← ++ (byte) main::l#2 [17] if((byte) main::l#1!=(byte) $65) goto main::@5 to:main::@6 main::@6: scope:[main] from main::@5 [18] (byte) main::k#1 ← ++ (byte) main::k#4 [19] if((byte) main::k#1!=(byte) $65) goto main::@4 to:main::@return main::@return: scope:[main] from main::@6 [20] return to:@return VARIABLE REGISTER WEIGHTS (byte*) SCREEN (void()) main() (byte) main::i (byte) main::i#1 16.5 (byte) main::i#4 24.599999999999998 (byte) main::j (byte) main::j#1 151.5 (byte) main::j#2 151.5 (byte) main::k (byte) main::k#1 16.5 (byte) main::k#4 20.499999999999996 (byte) main::l (byte) main::l#1 151.5 (byte) main::l#2 101.0 Initial phi equivalence classes [ main::i#4 main::i#1 ] [ main::j#2 main::j#1 ] [ main::k#4 main::k#1 ] [ main::l#2 main::l#1 ] Complete equivalence classes [ main::i#4 main::i#1 ] [ main::j#2 main::j#1 ] [ main::k#4 main::k#1 ] [ main::l#2 main::l#1 ] Allocated zp ZP_BYTE:2 [ main::i#4 main::i#1 ] Allocated zp ZP_BYTE:3 [ main::j#2 main::j#1 ] Allocated zp ZP_BYTE:4 [ main::k#4 main::k#1 ] Allocated zp ZP_BYTE:5 [ main::l#2 main::l#1 ] INITIAL ASM //SEG0 File Comments // Tests that inline ASM clobbering is taken into account when assigning registers //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels .label SCREEN = $400 //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 //SEG7 [4] phi from @1 to main [phi:@1->main] main_from_b1: jsr main //SEG8 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend //SEG9 @end bend: //SEG10 main main: { .label j = 3 .label i = 2 .label l = 5 .label k = 4 //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] b1_from_main: //SEG12 [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #0 sta i jmp b1 // First loop with no clobber //SEG13 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] b1_from_b3: //SEG14 [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy jmp b1 //SEG15 main::@1 b1: //SEG16 [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] b2_from_b1: //SEG17 [6] phi (byte) main::j#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuz1=vbuc1 lda #0 sta j jmp b2 //SEG18 [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] b2_from_b2: //SEG19 [6] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@2->main::@2#0] -- register_copy jmp b2 //SEG20 main::@2 b2: //SEG21 [7] *((const byte*) SCREEN#0 + (byte) main::i#4) ← (byte) main::j#2 -- pbuc1_derefidx_vbuz1=vbuz2 lda j ldy i sta SCREEN,y //SEG22 [8] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuz1=_inc_vbuz1 inc j //SEG23 [9] if((byte) main::j#1!=(byte) $65) goto main::@2 -- vbuz1_neq_vbuc1_then_la1 lda #$65 cmp j bne b2_from_b2 jmp b3 //SEG24 main::@3 b3: //SEG25 [10] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuz1=_inc_vbuz1 inc i //SEG26 [11] if((byte) main::i#1!=(byte) $65) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #$65 cmp i bne b1_from_b3 //SEG27 [12] phi from main::@3 to main::@4 [phi:main::@3->main::@4] b4_from_b3: //SEG28 [12] phi (byte) main::k#4 = (byte) 0 [phi:main::@3->main::@4#0] -- vbuz1=vbuc1 lda #0 sta k jmp b4 // Then loop with clobbering A&X //SEG29 [12] phi from main::@6 to main::@4 [phi:main::@6->main::@4] b4_from_b6: //SEG30 [12] phi (byte) main::k#4 = (byte) main::k#1 [phi:main::@6->main::@4#0] -- register_copy jmp b4 //SEG31 main::@4 b4: //SEG32 [13] phi from main::@4 to main::@5 [phi:main::@4->main::@5] b5_from_b4: //SEG33 [13] phi (byte) main::l#2 = (byte) 0 [phi:main::@4->main::@5#0] -- vbuz1=vbuc1 lda #0 sta l jmp b5 //SEG34 [13] phi from main::@5 to main::@5 [phi:main::@5->main::@5] b5_from_b5: //SEG35 [13] phi (byte) main::l#2 = (byte) main::l#1 [phi:main::@5->main::@5#0] -- register_copy jmp b5 //SEG36 main::@5 b5: //SEG37 asm { eor#$55 tax } eor #$55 tax //SEG38 [15] *((const byte*) SCREEN#0 + (byte) main::k#4) ← (byte) main::l#2 -- pbuc1_derefidx_vbuz1=vbuz2 lda l ldy k sta SCREEN,y //SEG39 [16] (byte) main::l#1 ← ++ (byte) main::l#2 -- vbuz1=_inc_vbuz1 inc l //SEG40 [17] if((byte) main::l#1!=(byte) $65) goto main::@5 -- vbuz1_neq_vbuc1_then_la1 lda #$65 cmp l bne b5_from_b5 jmp b6 //SEG41 main::@6 b6: //SEG42 [18] (byte) main::k#1 ← ++ (byte) main::k#4 -- vbuz1=_inc_vbuz1 inc k //SEG43 [19] if((byte) main::k#1!=(byte) $65) goto main::@4 -- vbuz1_neq_vbuc1_then_la1 lda #$65 cmp k bne b4_from_b6 jmp breturn //SEG44 main::@return breturn: //SEG45 [20] return rts } REGISTER UPLIFT POTENTIAL REGISTERS Statement asm { eor#$55 tax } always clobbers reg byte a reg byte x Removing always clobbered register reg byte a as potential for zp ZP_BYTE:4 [ main::k#4 main::k#1 ] Removing always clobbered register reg byte x as potential for zp ZP_BYTE:4 [ main::k#4 main::k#1 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:5 [ main::l#2 main::l#1 ] Removing always clobbered register reg byte x as potential for zp ZP_BYTE:5 [ main::l#2 main::l#1 ] Statement [15] *((const byte*) SCREEN#0 + (byte) main::k#4) ← (byte) main::l#2 [ main::k#4 main::l#2 ] ( main:2 [ main::k#4 main::l#2 ] ) always clobbers reg byte a Statement asm { eor#$55 tax } always clobbers reg byte a reg byte x Statement [15] *((const byte*) SCREEN#0 + (byte) main::k#4) ← (byte) main::l#2 [ main::k#4 main::l#2 ] ( main:2 [ main::k#4 main::l#2 ] ) always clobbers reg byte a Potential registers zp ZP_BYTE:2 [ main::i#4 main::i#1 ] : zp ZP_BYTE:2 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:3 [ main::j#2 main::j#1 ] : zp ZP_BYTE:3 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:4 [ main::k#4 main::k#1 ] : zp ZP_BYTE:4 , reg byte y , Potential registers zp ZP_BYTE:5 [ main::l#2 main::l#1 ] : zp ZP_BYTE:5 , reg byte y , REGISTER UPLIFT SCOPES Uplift Scope [main] 303: zp ZP_BYTE:3 [ main::j#2 main::j#1 ] 252.5: zp ZP_BYTE:5 [ main::l#2 main::l#1 ] 41.1: zp ZP_BYTE:2 [ main::i#4 main::i#1 ] 37: zp ZP_BYTE:4 [ main::k#4 main::k#1 ] Uplift Scope [] Uplifting [main] best 6638 combination reg byte a [ main::j#2 main::j#1 ] zp ZP_BYTE:5 [ main::l#2 main::l#1 ] reg byte x [ main::i#4 main::i#1 ] reg byte y [ main::k#4 main::k#1 ] Uplifting [] best 6638 combination Attempting to uplift remaining variables inzp ZP_BYTE:5 [ main::l#2 main::l#1 ] Uplifting [main] best 6638 combination zp ZP_BYTE:5 [ main::l#2 main::l#1 ] Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:2 [ main::l#2 main::l#1 ] ASSEMBLER BEFORE OPTIMIZATION //SEG0 File Comments // Tests that inline ASM clobbering is taken into account when assigning registers //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" //SEG2 Global Constants & labels .label SCREEN = $400 //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 //SEG7 [4] phi from @1 to main [phi:@1->main] main_from_b1: jsr main //SEG8 [3] phi from @1 to @end [phi:@1->@end] bend_from_b1: jmp bend //SEG9 @end bend: //SEG10 main main: { .label l = 2 //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] b1_from_main: //SEG12 [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 ldx #0 jmp b1 // First loop with no clobber //SEG13 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] b1_from_b3: //SEG14 [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy jmp b1 //SEG15 main::@1 b1: //SEG16 [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] b2_from_b1: //SEG17 [6] phi (byte) main::j#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuaa=vbuc1 lda #0 jmp b2 //SEG18 [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] b2_from_b2: //SEG19 [6] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@2->main::@2#0] -- register_copy jmp b2 //SEG20 main::@2 b2: //SEG21 [7] *((const byte*) SCREEN#0 + (byte) main::i#4) ← (byte) main::j#2 -- pbuc1_derefidx_vbuxx=vbuaa sta SCREEN,x //SEG22 [8] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuaa=_inc_vbuaa clc adc #1 //SEG23 [9] if((byte) main::j#1!=(byte) $65) goto main::@2 -- vbuaa_neq_vbuc1_then_la1 cmp #$65 bne b2_from_b2 jmp b3 //SEG24 main::@3 b3: //SEG25 [10] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx inx //SEG26 [11] if((byte) main::i#1!=(byte) $65) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #$65 bne b1_from_b3 //SEG27 [12] phi from main::@3 to main::@4 [phi:main::@3->main::@4] b4_from_b3: //SEG28 [12] phi (byte) main::k#4 = (byte) 0 [phi:main::@3->main::@4#0] -- vbuyy=vbuc1 ldy #0 jmp b4 // Then loop with clobbering A&X //SEG29 [12] phi from main::@6 to main::@4 [phi:main::@6->main::@4] b4_from_b6: //SEG30 [12] phi (byte) main::k#4 = (byte) main::k#1 [phi:main::@6->main::@4#0] -- register_copy jmp b4 //SEG31 main::@4 b4: //SEG32 [13] phi from main::@4 to main::@5 [phi:main::@4->main::@5] b5_from_b4: //SEG33 [13] phi (byte) main::l#2 = (byte) 0 [phi:main::@4->main::@5#0] -- vbuz1=vbuc1 lda #0 sta l jmp b5 //SEG34 [13] phi from main::@5 to main::@5 [phi:main::@5->main::@5] b5_from_b5: //SEG35 [13] phi (byte) main::l#2 = (byte) main::l#1 [phi:main::@5->main::@5#0] -- register_copy jmp b5 //SEG36 main::@5 b5: //SEG37 asm { eor#$55 tax } eor #$55 tax //SEG38 [15] *((const byte*) SCREEN#0 + (byte) main::k#4) ← (byte) main::l#2 -- pbuc1_derefidx_vbuyy=vbuz1 lda l sta SCREEN,y //SEG39 [16] (byte) main::l#1 ← ++ (byte) main::l#2 -- vbuz1=_inc_vbuz1 inc l //SEG40 [17] if((byte) main::l#1!=(byte) $65) goto main::@5 -- vbuz1_neq_vbuc1_then_la1 lda #$65 cmp l bne b5_from_b5 jmp b6 //SEG41 main::@6 b6: //SEG42 [18] (byte) main::k#1 ← ++ (byte) main::k#4 -- vbuyy=_inc_vbuyy iny //SEG43 [19] if((byte) main::k#1!=(byte) $65) goto main::@4 -- vbuyy_neq_vbuc1_then_la1 cpy #$65 bne b4_from_b6 jmp breturn //SEG44 main::@return breturn: //SEG45 [20] return rts } ASSEMBLER OPTIMIZATIONS Removing instruction jmp b1 Removing instruction jmp bend Removing instruction jmp b1 Removing instruction jmp b2 Removing instruction jmp b3 Removing instruction jmp b4 Removing instruction jmp b5 Removing instruction jmp b6 Removing instruction jmp breturn Succesful ASM optimization Pass5NextJumpElimination Replacing label b2_from_b2 with b2 Replacing label b1_from_b3 with b1 Replacing label b5_from_b5 with b5 Replacing label b4_from_b6 with b4 Removing instruction b1_from_bbegin: Removing instruction b1: Removing instruction main_from_b1: Removing instruction bend_from_b1: Removing instruction b1_from_b3: Removing instruction b2_from_b1: Removing instruction b2_from_b2: Removing instruction b4_from_b6: Removing instruction b5_from_b4: Removing instruction b5_from_b5: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: Removing instruction b1_from_main: Removing instruction b3: Removing instruction b4_from_b3: Removing instruction b6: Removing instruction breturn: Succesful ASM optimization Pass5UnusedLabelElimination Updating BasicUpstart to call main directly Removing instruction jsr main Succesful ASM optimization Pass5SkipBegin Removing instruction jmp b1 Removing instruction jmp b2 Removing instruction jmp b4 Removing instruction jmp b5 Succesful ASM optimization Pass5NextJumpElimination Removing instruction bbegin: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (byte*) SCREEN (const byte*) SCREEN#0 SCREEN = (byte*) 1024 (void()) main() (label) main::@1 (label) main::@2 (label) main::@3 (label) main::@4 (label) main::@5 (label) main::@6 (label) main::@return (byte) main::i (byte) main::i#1 reg byte x 16.5 (byte) main::i#4 reg byte x 24.599999999999998 (byte) main::j (byte) main::j#1 reg byte a 151.5 (byte) main::j#2 reg byte a 151.5 (byte) main::k (byte) main::k#1 reg byte y 16.5 (byte) main::k#4 reg byte y 20.499999999999996 (byte) main::l (byte) main::l#1 l zp ZP_BYTE:2 151.5 (byte) main::l#2 l zp ZP_BYTE:2 101.0 reg byte x [ main::i#4 main::i#1 ] reg byte a [ main::j#2 main::j#1 ] reg byte y [ main::k#4 main::k#1 ] zp ZP_BYTE:2 [ main::l#2 main::l#1 ] FINAL ASSEMBLER Score: 4676 //SEG0 File Comments // Tests that inline ASM clobbering is taken into account when assigning registers //SEG1 Basic Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" //SEG2 Global Constants & labels .label SCREEN = $400 //SEG3 @begin //SEG4 [1] phi from @begin to @1 [phi:@begin->@1] //SEG5 @1 //SEG6 [2] call main //SEG7 [4] phi from @1 to main [phi:@1->main] //SEG8 [3] phi from @1 to @end [phi:@1->@end] //SEG9 @end //SEG10 main main: { .label l = 2 //SEG11 [5] phi from main to main::@1 [phi:main->main::@1] //SEG12 [5] phi (byte) main::i#4 = (byte) 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 ldx #0 // First loop with no clobber //SEG13 [5] phi from main::@3 to main::@1 [phi:main::@3->main::@1] //SEG14 [5] phi (byte) main::i#4 = (byte) main::i#1 [phi:main::@3->main::@1#0] -- register_copy //SEG15 main::@1 b1: //SEG16 [6] phi from main::@1 to main::@2 [phi:main::@1->main::@2] //SEG17 [6] phi (byte) main::j#2 = (byte) 0 [phi:main::@1->main::@2#0] -- vbuaa=vbuc1 lda #0 //SEG18 [6] phi from main::@2 to main::@2 [phi:main::@2->main::@2] //SEG19 [6] phi (byte) main::j#2 = (byte) main::j#1 [phi:main::@2->main::@2#0] -- register_copy //SEG20 main::@2 b2: //SEG21 [7] *((const byte*) SCREEN#0 + (byte) main::i#4) ← (byte) main::j#2 -- pbuc1_derefidx_vbuxx=vbuaa sta SCREEN,x //SEG22 [8] (byte) main::j#1 ← ++ (byte) main::j#2 -- vbuaa=_inc_vbuaa clc adc #1 //SEG23 [9] if((byte) main::j#1!=(byte) $65) goto main::@2 -- vbuaa_neq_vbuc1_then_la1 cmp #$65 bne b2 //SEG24 main::@3 //SEG25 [10] (byte) main::i#1 ← ++ (byte) main::i#4 -- vbuxx=_inc_vbuxx inx //SEG26 [11] if((byte) main::i#1!=(byte) $65) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #$65 bne b1 //SEG27 [12] phi from main::@3 to main::@4 [phi:main::@3->main::@4] //SEG28 [12] phi (byte) main::k#4 = (byte) 0 [phi:main::@3->main::@4#0] -- vbuyy=vbuc1 ldy #0 // Then loop with clobbering A&X //SEG29 [12] phi from main::@6 to main::@4 [phi:main::@6->main::@4] //SEG30 [12] phi (byte) main::k#4 = (byte) main::k#1 [phi:main::@6->main::@4#0] -- register_copy //SEG31 main::@4 b4: //SEG32 [13] phi from main::@4 to main::@5 [phi:main::@4->main::@5] //SEG33 [13] phi (byte) main::l#2 = (byte) 0 [phi:main::@4->main::@5#0] -- vbuz1=vbuc1 lda #0 sta l //SEG34 [13] phi from main::@5 to main::@5 [phi:main::@5->main::@5] //SEG35 [13] phi (byte) main::l#2 = (byte) main::l#1 [phi:main::@5->main::@5#0] -- register_copy //SEG36 main::@5 b5: //SEG37 asm { eor#$55 tax } eor #$55 tax //SEG38 [15] *((const byte*) SCREEN#0 + (byte) main::k#4) ← (byte) main::l#2 -- pbuc1_derefidx_vbuyy=vbuz1 lda l sta SCREEN,y //SEG39 [16] (byte) main::l#1 ← ++ (byte) main::l#2 -- vbuz1=_inc_vbuz1 inc l //SEG40 [17] if((byte) main::l#1!=(byte) $65) goto main::@5 -- vbuz1_neq_vbuc1_then_la1 lda #$65 cmp l bne b5 //SEG41 main::@6 //SEG42 [18] (byte) main::k#1 ← ++ (byte) main::k#4 -- vbuyy=_inc_vbuyy iny //SEG43 [19] if((byte) main::k#1!=(byte) $65) goto main::@4 -- vbuyy_neq_vbuc1_then_la1 cpy #$65 bne b4 //SEG44 main::@return //SEG45 [20] return rts }