Fixing pointer array-indexing *((struct Point[2]) points + (number) 0) Fixing pointer array-indexing *((struct Point[2]) points + (number) 1) Fixing pointer array-indexing *((struct Point[2]) points + (byte) main::i) Created struct value member variable (byte) print::p_x Created struct value member variable (byte) print::p_y Converted struct value to member variables (struct Point) print::p Converted procedure struct value parameter to member unwinding (void()) print((byte) print::p_x , (byte) print::p_y) Adding struct value list initializer *((byte*) main::$5 + (number~) main::$2) ← (number) 1 Adding struct value list initializer *((byte*) main::$6 + (number~) main::$2) ← (number) 2 Adding struct value list initializer *((byte*) main::$7 + (number~) main::$3) ← (number) 3 Adding struct value list initializer *((byte*) main::$8 + (number~) main::$3) ← (number) 4 Converted procedure struct value parameter to member unwinding in call (void~) main::$0 ← call print *((byte*) main::$9 + (byte~) main::$4) *((byte*) main::$10 + (byte~) main::$4) Replacing struct member reference (struct Point) print::p.x with member unwinding reference (byte) print::p_x Replacing struct member reference (struct Point) print::p.y with member unwinding reference (byte) print::p_y Culled Empty Block (label) main::@2 Culled Empty Block (label) @1 CONTROL FLOW GRAPH SSA @begin: scope:[] from (byte*) SCREEN#0 ← ((byte*)) (number) $400 (byte) idx#0 ← (number) 0 (struct Point[2]) points#0 ← { fill( 2, 0) } to:@2 main: scope:[main] from @2 (byte) idx#14 ← phi( @2/(byte) idx#13 ) (number~) main::$2 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT (byte*) main::$5 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X *((byte*) main::$5 + (number~) main::$2) ← (number) 1 (byte*) main::$6 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y *((byte*) main::$6 + (number~) main::$2) ← (number) 2 (number~) main::$3 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT (byte*) main::$7 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X *((byte*) main::$7 + (number~) main::$3) ← (number) 3 (byte*) main::$8 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y *((byte*) main::$8 + (number~) main::$3) ← (number) 4 (byte) main::i#0 ← (byte) 0 to:main::@1 main::@1: scope:[main] from main main::@3 (byte) idx#12 ← phi( main/(byte) idx#14 main::@3/(byte) idx#1 ) (byte) main::i#2 ← phi( main/(byte) main::i#0 main::@3/(byte) main::i#1 ) (byte~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT (byte) print::p_x#0 ← *((byte*) main::$9 + (byte~) main::$4) (byte) print::p_y#0 ← *((byte*) main::$10 + (byte~) main::$4) call print to:main::@3 main::@3: scope:[main] from main::@1 (byte) main::i#3 ← phi( main::@1/(byte) main::i#2 ) (byte) idx#7 ← phi( main::@1/(byte) idx#5 ) (byte) idx#1 ← (byte) idx#7 (byte*) main::$9 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X (byte*) main::$10 ← (byte*)(struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y (byte) main::i#1 ← (byte) main::i#3 + rangenext(0,1) (bool~) main::$1 ← (byte) main::i#1 != rangelast(0,1) if((bool~) main::$1) goto main::@1 to:main::@return main::@return: scope:[main] from main::@3 (byte) idx#8 ← phi( main::@3/(byte) idx#1 ) (byte) idx#2 ← (byte) idx#8 return to:@return print: scope:[print] from main::@1 (byte) print::p_y#1 ← phi( main::@1/(byte) print::p_y#0 ) (byte) idx#9 ← phi( main::@1/(byte) idx#12 ) (byte) print::p_x#1 ← phi( main::@1/(byte) print::p_x#0 ) *((byte*) SCREEN#0 + (byte) idx#9) ← (byte) print::p_x#1 (byte) idx#3 ← ++ (byte) idx#9 *((byte*) SCREEN#0 + (byte) idx#3) ← (byte) print::p_y#1 (byte) idx#4 ← ++ (byte) idx#3 to:print::@return print::@return: scope:[print] from print (byte) idx#10 ← phi( print/(byte) idx#4 ) (byte) idx#5 ← (byte) idx#10 return to:@return @2: scope:[] from @begin (byte) idx#13 ← phi( @begin/(byte) idx#0 ) call main to:@3 @3: scope:[] from @2 (byte) idx#11 ← phi( @2/(byte) idx#2 ) (byte) idx#6 ← (byte) idx#11 to:@end @end: scope:[] from @3 SYMBOL TABLE SSA (label) @2 (label) @3 (label) @begin (label) @end (const byte) OFFSET_STRUCT_POINT_X = (byte) 0 (const byte) OFFSET_STRUCT_POINT_Y = (byte) 1 (byte) Point::x (byte) Point::y (byte*) SCREEN (byte*) SCREEN#0 (const byte) SIZEOF_STRUCT_POINT = (byte) 2 (byte) idx (byte) idx#0 (byte) idx#1 (byte) idx#10 (byte) idx#11 (byte) idx#12 (byte) idx#13 (byte) idx#14 (byte) idx#2 (byte) idx#3 (byte) idx#4 (byte) idx#5 (byte) idx#6 (byte) idx#7 (byte) idx#8 (byte) idx#9 (void()) main() (bool~) main::$1 (byte*) main::$10 (number~) main::$2 (number~) main::$3 (byte~) main::$4 (byte*) main::$5 (byte*) main::$6 (byte*) main::$7 (byte*) main::$8 (byte*) main::$9 (label) main::@1 (label) main::@3 (label) main::@return (byte) main::i (byte) main::i#0 (byte) main::i#1 (byte) main::i#2 (byte) main::i#3 (struct Point[2]) points (struct Point[2]) points#0 (void()) print((byte) print::p_x , (byte) print::p_y) (label) print::@return (struct Point) print::p (byte) print::p_x (byte) print::p_x#0 (byte) print::p_x#1 (byte) print::p_y (byte) print::p_y#0 (byte) print::p_y#1 Adding number conversion cast (unumber) 0 in (byte) idx#0 ← (number) 0 Adding number conversion cast (unumber) 0 in (number~) main::$2 ← (number) 0 * (const byte) SIZEOF_STRUCT_POINT Adding number conversion cast (unumber) main::$2 in (number~) main::$2 ← (unumber)(number) 0 * (const byte) SIZEOF_STRUCT_POINT Adding number conversion cast (unumber) 1 in *((byte*) main::$5 + (unumber~) main::$2) ← (number) 1 Adding number conversion cast (unumber) 2 in *((byte*) main::$6 + (unumber~) main::$2) ← (number) 2 Adding number conversion cast (unumber) 1 in (number~) main::$3 ← (number) 1 * (const byte) SIZEOF_STRUCT_POINT Adding number conversion cast (unumber) main::$3 in (number~) main::$3 ← (unumber)(number) 1 * (const byte) SIZEOF_STRUCT_POINT Adding number conversion cast (unumber) 3 in *((byte*) main::$7 + (unumber~) main::$3) ← (number) 3 Adding number conversion cast (unumber) 4 in *((byte*) main::$8 + (unumber~) main::$3) ← (number) 4 Successful SSA optimization PassNAddNumberTypeConversions Inlining cast (byte*) SCREEN#0 ← (byte*)(number) $400 Inlining cast (byte) idx#0 ← (unumber)(number) 0 Inlining cast *((byte*) main::$5 + (unumber~) main::$2) ← (unumber)(number) 1 Inlining cast *((byte*) main::$6 + (unumber~) main::$2) ← (unumber)(number) 2 Inlining cast *((byte*) main::$7 + (unumber~) main::$3) ← (unumber)(number) 3 Inlining cast *((byte*) main::$8 + (unumber~) main::$3) ← (unumber)(number) 4 Successful SSA optimization Pass2InlineCast Simplifying constant pointer cast (byte*) 1024 Simplifying constant integer cast 0 Simplifying constant integer cast 0 Simplifying constant integer cast 1 Simplifying constant integer cast 2 Simplifying constant integer cast 1 Simplifying constant integer cast 3 Simplifying constant integer cast 4 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 0 Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 2 Finalized unsigned number type (byte) 1 Finalized unsigned number type (byte) 3 Finalized unsigned number type (byte) 4 Successful SSA optimization PassNFinalizeNumberTypeConversions Inferred type updated to byte in (unumber~) main::$2 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT Inferred type updated to byte in (unumber~) main::$3 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT Alias (byte) main::i#2 = (byte) main::i#3 Alias (byte) idx#1 = (byte) idx#7 (byte) idx#8 (byte) idx#2 Alias (byte) idx#10 = (byte) idx#4 (byte) idx#5 Alias (byte) idx#0 = (byte) idx#13 Alias (byte) idx#11 = (byte) idx#6 Successful SSA optimization Pass2AliasElimination Identical Phi Values (byte) idx#14 (byte) idx#0 Identical Phi Values (byte) idx#1 (byte) idx#10 Identical Phi Values (byte) print::p_x#1 (byte) print::p_x#0 Identical Phi Values (byte) idx#9 (byte) idx#12 Identical Phi Values (byte) print::p_y#1 (byte) print::p_y#0 Identical Phi Values (byte) idx#11 (byte) idx#1 Successful SSA optimization Pass2IdenticalPhiElimination Simple Condition (bool~) main::$1 [26] if((byte) main::i#1!=rangelast(0,1)) goto main::@1 Successful SSA optimization Pass2ConditionalJumpSimplification Constant right-side identified [2] (struct Point[2]) points#0 ← { fill( 2, 0) } Constant right-side identified [4] (byte~) main::$2 ← (byte) 0 * (const byte) SIZEOF_STRUCT_POINT Constant right-side identified [9] (byte~) main::$3 ← (byte) 1 * (const byte) SIZEOF_STRUCT_POINT Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte*) SCREEN#0 = (byte*) 1024 Constant (const byte) idx#0 = 0 Constant (const struct Point[2]) points#0 = { fill( 2, 0) } Constant (const byte) main::$2 = 0*SIZEOF_STRUCT_POINT Constant (const byte) main::$3 = 1*SIZEOF_STRUCT_POINT Constant (const byte) main::i#0 = 0 Successful SSA optimization Pass2ConstantIdentification Constant value identified (byte*)points#0 in [5] (byte*) main::$5 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X Constant value identified (byte*)points#0 in [7] (byte*) main::$6 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Constant value identified (byte*)points#0 in [10] (byte*) main::$7 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X Constant value identified (byte*)points#0 in [12] (byte*) main::$8 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Constant value identified (byte*)points#0 in [22] (byte*) main::$9 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X Constant value identified (byte*)points#0 in [23] (byte*) main::$10 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantValues Resolved ranged next value [24] main::i#1 ← ++ main::i#2 to ++ Resolved ranged comparison value [26] if(main::i#1!=rangelast(0,1)) goto main::@1 to (number) 2 Simplifying constant evaluating to zero (byte) 0*(const byte) SIZEOF_STRUCT_POINT in Successful SSA optimization PassNSimplifyConstantZero Simplifying expression containing zero (byte*)points#0 in [5] (byte*) main::$5 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X Simplifying expression containing zero main::$5 in [6] *((byte*) main::$5 + (const byte) main::$2) ← (byte) 1 Simplifying expression containing zero main::$6 in [8] *((byte*) main::$6 + (const byte) main::$2) ← (byte) 2 Simplifying expression containing zero (byte*)points#0 in [10] (byte*) main::$7 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X Simplifying expression containing zero (byte*)points#0 in [22] (byte*) main::$9 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNSimplifyExpressionWithZero Eliminating unused constant (const byte) main::$2 Eliminating unused constant (const byte) OFFSET_STRUCT_POINT_X Successful SSA optimization PassNEliminateUnusedVars Adding number conversion cast (unumber) 2 in if((byte) main::i#1!=(number) 2) goto main::@1 Successful SSA optimization PassNAddNumberTypeConversions Simplifying constant integer cast 2 Successful SSA optimization PassNCastSimplification Finalized unsigned number type (byte) 2 Successful SSA optimization PassNFinalizeNumberTypeConversions Constant right-side identified [2] (byte*) main::$6 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Constant right-side identified [6] (byte*) main::$8 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Constant right-side identified [14] (byte*) main::$10 ← (byte*)(const struct Point[2]) points#0 + (const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte*) main::$5 = (byte*)points#0 Constant (const byte*) main::$6 = (byte*)points#0+OFFSET_STRUCT_POINT_Y Constant (const byte*) main::$7 = (byte*)points#0 Constant (const byte*) main::$8 = (byte*)points#0+OFFSET_STRUCT_POINT_Y Constant (const byte*) main::$9 = (byte*)points#0 Constant (const byte*) main::$10 = (byte*)points#0+OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantIdentification Rewriting multiplication to use shift [5] (byte~) main::$4 ← (byte) main::i#2 * (const byte) SIZEOF_STRUCT_POINT Successful SSA optimization Pass2MultiplyToShiftRewriting Inlining constant with var siblings (const byte) main::i#0 Inlining constant with var siblings (const byte) idx#0 Constant inlined main::$5 = (byte*)(const struct Point[2]) points#0 Constant inlined main::i#0 = (byte) 0 Constant inlined main::$6 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y Constant inlined main::$3 = (byte) 1*(const byte) SIZEOF_STRUCT_POINT Constant inlined main::$9 = (byte*)(const struct Point[2]) points#0 Constant inlined idx#0 = (byte) 0 Constant inlined main::$7 = (byte*)(const struct Point[2]) points#0 Constant inlined main::$10 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y Constant inlined main::$8 = (byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantInlining Consolidated array index constant in *((byte*)points#0+1*SIZEOF_STRUCT_POINT) Consolidated array index constant in *((byte*)points#0+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT) Successful SSA optimization Pass2ConstantAdditionElimination 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 print:13 Created 2 initial phi equivalence classes Coalesced [17] main::i#4 ← main::i#1 Coalesced [18] idx#15 ← idx#10 Coalesced down to 2 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() main: scope:[main] from @1 [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 1 [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 4 to:main::@1 main::@1: scope:[main] from main main::@2 [8] (byte) idx#12 ← phi( main/(byte) 0 main::@2/(byte) idx#10 ) [8] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 ) [9] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 [10] (byte) print::p_x#0 ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$4) [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) [12] call print to:main::@2 main::@2: scope:[main] from main::@1 [13] (byte) main::i#1 ← ++ (byte) main::i#2 [14] if((byte) main::i#1!=(byte) 2) goto main::@1 to:main::@return main::@return: scope:[main] from main::@2 [15] return to:@return print: scope:[print] from main::@1 [16] *((const byte*) SCREEN#0 + (byte) idx#12) ← (byte) print::p_x#0 [17] (byte) idx#3 ← ++ (byte) idx#12 [18] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte) print::p_y#0 [19] (byte) idx#10 ← ++ (byte) idx#3 to:print::@return print::@return: scope:[print] from print [20] return to:@return VARIABLE REGISTER WEIGHTS (byte) Point::x (byte) Point::y (byte*) SCREEN (byte) idx (byte) idx#10 2.6 (byte) idx#12 3.0 (byte) idx#3 3.0 (void()) main() (byte~) main::$4 16.5 (byte) main::i (byte) main::i#1 16.5 (byte) main::i#2 6.6000000000000005 (struct Point[2]) points (void()) print((byte) print::p_x , (byte) print::p_y) (struct Point) print::p (byte) print::p_x (byte) print::p_x#0 6.5 (byte) print::p_y (byte) print::p_y#0 4.333333333333333 Initial phi equivalence classes [ main::i#2 main::i#1 ] [ idx#12 idx#10 ] Added variable main::$4 to zero page equivalence class [ main::$4 ] Added variable print::p_x#0 to zero page equivalence class [ print::p_x#0 ] Added variable print::p_y#0 to zero page equivalence class [ print::p_y#0 ] Added variable idx#3 to zero page equivalence class [ idx#3 ] Complete equivalence classes [ main::i#2 main::i#1 ] [ idx#12 idx#10 ] [ main::$4 ] [ print::p_x#0 ] [ print::p_y#0 ] [ idx#3 ] Allocated zp ZP_BYTE:2 [ main::i#2 main::i#1 ] Allocated zp ZP_BYTE:3 [ idx#12 idx#10 ] Allocated zp ZP_BYTE:4 [ main::$4 ] Allocated zp ZP_BYTE:5 [ print::p_x#0 ] Allocated zp ZP_BYTE:6 [ print::p_y#0 ] Allocated zp ZP_BYTE:7 [ idx#3 ] INITIAL ASM Target platform is c64basic // File Comments // Demonstrates problem with passing struct array element as parameter to call // Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 .label SCREEN = $400 .label idx = 7 .label idx_10 = 3 .label idx_12 = 3 // @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 _4 = 4 .label i = 2 // [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 1 -- _deref_pbuc1=vbuc2 lda #1 sta points // [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 -- _deref_pbuc1=vbuc2 lda #2 sta points+OFFSET_STRUCT_POINT_Y // [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 -- _deref_pbuc1=vbuc2 lda #3 sta points+1*SIZEOF_STRUCT_POINT // [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 4 -- _deref_pbuc1=vbuc2 lda #4 sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT // [8] phi from main to main::@1 [phi:main->main::@1] b1_from_main: // [8] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #0 sta idx_12 // [8] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 lda #0 sta i jmp b1 // [8] phi from main::@2 to main::@1 [phi:main::@2->main::@1] b1_from_b2: // [8] phi (byte) idx#12 = (byte) idx#10 [phi:main::@2->main::@1#0] -- register_copy // [8] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy jmp b1 // main::@1 b1: // [9] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 -- vbuz1=vbuz2_rol_1 lda i asl sta _4 // [10] (byte) print::p_x#0 ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuz2 ldy _4 lda points,y sta print.p_x // [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuz2 ldy _4 lda points+OFFSET_STRUCT_POINT_Y,y sta print.p_y // [12] call print jsr print jmp b2 // main::@2 b2: // [13] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuz1=_inc_vbuz1 inc i // [14] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #2 cmp i bne b1_from_b2 jmp breturn // main::@return breturn: // [15] return rts } // print // print(byte zeropage(5) p_x, byte zeropage(6) p_y) print: { .label p_x = 5 .label p_y = 6 // [16] *((const byte*) SCREEN#0 + (byte) idx#12) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda p_x ldy idx_12 sta SCREEN,y // [17] (byte) idx#3 ← ++ (byte) idx#12 -- vbuz1=_inc_vbuz2 ldy idx_12 iny sty idx // [18] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte) print::p_y#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda p_y ldy idx sta SCREEN,y // [19] (byte) idx#10 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz2 ldy idx iny sty idx_10 jmp breturn // print::@return breturn: // [20] return rts } // File Data points: .fill 2*2, 0 REGISTER UPLIFT POTENTIAL REGISTERS Statement [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 4 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [9] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 [ main::i#2 idx#12 main::$4 ] ( main:2 [ main::i#2 idx#12 main::$4 ] ) always clobbers reg byte a Removing always clobbered register reg byte a as potential for zp ZP_BYTE:2 [ main::i#2 main::i#1 ] Removing always clobbered register reg byte a as potential for zp ZP_BYTE:3 [ idx#12 idx#10 ] Statement [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 4 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [9] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 [ main::i#2 idx#12 main::$4 ] ( main:2 [ main::i#2 idx#12 main::$4 ] ) always clobbers reg byte a Potential registers zp ZP_BYTE:2 [ main::i#2 main::i#1 ] : zp ZP_BYTE:2 , reg byte x , reg byte y , Potential registers zp ZP_BYTE:3 [ idx#12 idx#10 ] : zp ZP_BYTE:3 , reg byte x , reg byte y , Potential registers zp ZP_BYTE:4 [ main::$4 ] : zp ZP_BYTE:4 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:5 [ print::p_x#0 ] : zp ZP_BYTE:5 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:6 [ print::p_y#0 ] : zp ZP_BYTE:6 , reg byte a , reg byte x , reg byte y , Potential registers zp ZP_BYTE:7 [ idx#3 ] : zp ZP_BYTE:7 , reg byte a , reg byte x , reg byte y , REGISTER UPLIFT SCOPES Uplift Scope [main] 23.1: zp ZP_BYTE:2 [ main::i#2 main::i#1 ] 16.5: zp ZP_BYTE:4 [ main::$4 ] Uplift Scope [print] 6.5: zp ZP_BYTE:5 [ print::p_x#0 ] 4.33: zp ZP_BYTE:6 [ print::p_y#0 ] Uplift Scope [] 5.6: zp ZP_BYTE:3 [ idx#12 idx#10 ] 3: zp ZP_BYTE:7 [ idx#3 ] Uplift Scope [Point] Uplifting [main] best 614 combination reg byte x [ main::i#2 main::i#1 ] reg byte y [ main::$4 ] Uplifting [print] best 614 combination zp ZP_BYTE:5 [ print::p_x#0 ] zp ZP_BYTE:6 [ print::p_y#0 ] Uplifting [] best 605 combination zp ZP_BYTE:3 [ idx#12 idx#10 ] reg byte y [ idx#3 ] Uplifting [Point] best 605 combination Attempting to uplift remaining variables inzp ZP_BYTE:5 [ print::p_x#0 ] Uplifting [print] best 605 combination zp ZP_BYTE:5 [ print::p_x#0 ] Attempting to uplift remaining variables inzp ZP_BYTE:3 [ idx#12 idx#10 ] Uplifting [] best 605 combination zp ZP_BYTE:3 [ idx#12 idx#10 ] Attempting to uplift remaining variables inzp ZP_BYTE:6 [ print::p_y#0 ] Uplifting [print] best 605 combination zp ZP_BYTE:6 [ print::p_y#0 ] Allocated (was zp ZP_BYTE:3) zp ZP_BYTE:2 [ idx#12 idx#10 ] Allocated (was zp ZP_BYTE:5) zp ZP_BYTE:3 [ print::p_x#0 ] Allocated (was zp ZP_BYTE:6) zp ZP_BYTE:4 [ print::p_y#0 ] ASSEMBLER BEFORE OPTIMIZATION // File Comments // Demonstrates problem with passing struct array element as parameter to call // Upstart .pc = $801 "Basic" :BasicUpstart(bbegin) .pc = $80d "Program" // Global Constants & labels .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 .label SCREEN = $400 .label idx = 2 // @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: { // [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 1 -- _deref_pbuc1=vbuc2 lda #1 sta points // [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 -- _deref_pbuc1=vbuc2 lda #2 sta points+OFFSET_STRUCT_POINT_Y // [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 -- _deref_pbuc1=vbuc2 lda #3 sta points+1*SIZEOF_STRUCT_POINT // [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 4 -- _deref_pbuc1=vbuc2 lda #4 sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT // [8] phi from main to main::@1 [phi:main->main::@1] b1_from_main: // [8] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #0 sta idx // [8] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 ldx #0 jmp b1 // [8] phi from main::@2 to main::@1 [phi:main::@2->main::@1] b1_from_b2: // [8] phi (byte) idx#12 = (byte) idx#10 [phi:main::@2->main::@1#0] -- register_copy // [8] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy jmp b1 // main::@1 b1: // [9] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 txa asl tay // [10] (byte) print::p_x#0 ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points,y sta print.p_x // [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points+OFFSET_STRUCT_POINT_Y,y sta print.p_y // [12] call print jsr print jmp b2 // main::@2 b2: // [13] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx // [14] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #2 bne b1_from_b2 jmp breturn // main::@return breturn: // [15] return rts } // print // print(byte zeropage(3) p_x, byte zeropage(4) p_y) print: { .label p_x = 3 .label p_y = 4 // [16] *((const byte*) SCREEN#0 + (byte) idx#12) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda p_x ldy idx sta SCREEN,y // [17] (byte) idx#3 ← ++ (byte) idx#12 -- vbuyy=_inc_vbuz1 ldy idx iny // [18] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte) print::p_y#0 -- pbuc1_derefidx_vbuyy=vbuz1 lda p_y sta SCREEN,y // [19] (byte) idx#10 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuyy iny sty idx jmp breturn // print::@return breturn: // [20] return rts } // File Data points: .fill 2*2, 0 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 instruction ldx #0 with TAX Removing instruction ldy idx Succesful ASM optimization Pass5UnnecesaryLoadElimination Replacing label b1_from_b2 with b1 Removing instruction b1_from_bbegin: Removing instruction b1: Removing instruction bend_from_b1: Removing instruction b1_from_b2: Succesful ASM optimization Pass5RedundantLabelElimination Removing instruction bend: Removing instruction b1_from_main: 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 jmp b1 Succesful ASM optimization Pass5NextJumpElimination Removing instruction bbegin: Succesful ASM optimization Pass5UnusedLabelElimination FINAL SYMBOL TABLE (label) @1 (label) @begin (label) @end (const byte) OFFSET_STRUCT_POINT_Y OFFSET_STRUCT_POINT_Y = (byte) 1 (byte) Point::x (byte) Point::y (byte*) SCREEN (const byte*) SCREEN#0 SCREEN = (byte*) 1024 (const byte) SIZEOF_STRUCT_POINT SIZEOF_STRUCT_POINT = (byte) 2 (byte) idx (byte) idx#10 idx zp ZP_BYTE:2 2.6 (byte) idx#12 idx zp ZP_BYTE:2 3.0 (byte) idx#3 reg byte y 3.0 (void()) main() (byte~) main::$4 reg byte y 16.5 (label) main::@1 (label) main::@2 (label) main::@return (byte) main::i (byte) main::i#1 reg byte x 16.5 (byte) main::i#2 reg byte x 6.6000000000000005 (struct Point[2]) points (const struct Point[2]) points#0 points = { fill( 2, 0) } (void()) print((byte) print::p_x , (byte) print::p_y) (label) print::@return (struct Point) print::p (byte) print::p_x (byte) print::p_x#0 p_x zp ZP_BYTE:3 6.5 (byte) print::p_y (byte) print::p_y#0 p_y zp ZP_BYTE:4 4.333333333333333 reg byte x [ main::i#2 main::i#1 ] zp ZP_BYTE:2 [ idx#12 idx#10 ] reg byte y [ main::$4 ] zp ZP_BYTE:3 [ print::p_x#0 ] zp ZP_BYTE:4 [ print::p_y#0 ] reg byte y [ idx#3 ] FINAL ASSEMBLER Score: 467 // File Comments // Demonstrates problem with passing struct array element as parameter to call // Upstart .pc = $801 "Basic" :BasicUpstart(main) .pc = $80d "Program" // Global Constants & labels .const SIZEOF_STRUCT_POINT = 2 .const OFFSET_STRUCT_POINT_Y = 1 .label SCREEN = $400 .label idx = 2 // @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: { // points[0] = { 1, 2 } // [4] *((byte*)(const struct Point[2]) points#0) ← (byte) 1 -- _deref_pbuc1=vbuc2 lda #1 sta points // [5] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 -- _deref_pbuc1=vbuc2 lda #2 sta points+OFFSET_STRUCT_POINT_Y // points[1] = { 3, 4 } // [6] *((byte*)(const struct Point[2]) points#0+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 -- _deref_pbuc1=vbuc2 lda #3 sta points+1*SIZEOF_STRUCT_POINT // [7] *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 4 -- _deref_pbuc1=vbuc2 lda #4 sta points+OFFSET_STRUCT_POINT_Y+1*SIZEOF_STRUCT_POINT // [8] phi from main to main::@1 [phi:main->main::@1] // [8] phi (byte) idx#12 = (byte) 0 [phi:main->main::@1#0] -- vbuz1=vbuc1 lda #0 sta idx // [8] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuxx=vbuc1 tax // [8] phi from main::@2 to main::@1 [phi:main::@2->main::@1] // [8] phi (byte) idx#12 = (byte) idx#10 [phi:main::@2->main::@1#0] -- register_copy // [8] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#1] -- register_copy // main::@1 b1: // print(points[i]) // [9] (byte~) main::$4 ← (byte) main::i#2 << (byte) 1 -- vbuyy=vbuxx_rol_1 txa asl tay // [10] (byte) print::p_x#0 ← *((byte*)(const struct Point[2]) points#0 + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points,y sta print.p_x // [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points#0+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points+OFFSET_STRUCT_POINT_Y,y sta print.p_y // [12] call print jsr print // main::@2 // for ( char i: 0..1) // [13] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuxx=_inc_vbuxx inx // [14] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuxx_neq_vbuc1_then_la1 cpx #2 bne b1 // main::@return // } // [15] return rts } // print // print(byte zeropage(3) p_x, byte zeropage(4) p_y) print: { .label p_x = 3 .label p_y = 4 // SCREEN[idx++] = p.x // [16] *((const byte*) SCREEN#0 + (byte) idx#12) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda p_x ldy idx sta SCREEN,y // SCREEN[idx++] = p.x; // [17] (byte) idx#3 ← ++ (byte) idx#12 -- vbuyy=_inc_vbuz1 iny // SCREEN[idx++] = p.y // [18] *((const byte*) SCREEN#0 + (byte) idx#3) ← (byte) print::p_y#0 -- pbuc1_derefidx_vbuyy=vbuz1 lda p_y sta SCREEN,y // SCREEN[idx++] = p.y; // [19] (byte) idx#10 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuyy iny sty idx // print::@return // } // [20] return rts } // File Data points: .fill 2*2, 0