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 ← ((byte*)) (number) $400 (byte) idx#0 ← (number) 0 (struct Point[2]) points ← { fill( 2, 0) } to:@2 (void()) main() 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 + (const byte) OFFSET_STRUCT_POINT_X *((byte*) main::$5 + (number~) main::$2) ← (number) 1 (byte*) main::$6 ← (byte*)(struct Point[2]) points + (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 + (const byte) OFFSET_STRUCT_POINT_X *((byte*) main::$7 + (number~) main::$3) ← (number) 3 (byte*) main::$8 ← (byte*)(struct Point[2]) points + (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 + (const byte) OFFSET_STRUCT_POINT_X (byte*) main::$10 ← (byte*)(struct Point[2]) points + (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 (void()) print((byte) print::p_x , (byte) print::p_y) 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 + (byte) idx#9) ← (byte) print::p_x#1 (byte) idx#3 ← ++ (byte) idx#9 *((byte*) SCREEN + (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 (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 (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 ← (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 ← { 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 = (byte*) 1024 Constant (const byte) idx#0 = 0 Constant (const struct Point[2]) points = { 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 in [5] (byte*) main::$5 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_X Constant value identified (byte*)points in [7] (byte*) main::$6 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_Y Constant value identified (byte*)points in [10] (byte*) main::$7 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_X Constant value identified (byte*)points in [12] (byte*) main::$8 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_Y Constant value identified (byte*)points in [22] (byte*) main::$9 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_X Constant value identified (byte*)points in [23] (byte*) main::$10 ← (byte*)(const struct Point[2]) points + (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 in [5] (byte*) main::$5 ← (byte*)(const struct Point[2]) points + (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 in [10] (byte*) main::$7 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_X Simplifying expression containing zero (byte*)points in [22] (byte*) main::$9 ← (byte*)(const struct Point[2]) points + (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 + (const byte) OFFSET_STRUCT_POINT_Y Constant right-side identified [6] (byte*) main::$8 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_Y Constant right-side identified [14] (byte*) main::$10 ← (byte*)(const struct Point[2]) points + (const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantRValueConsolidation Constant (const byte*) main::$5 = (byte*)points Constant (const byte*) main::$6 = (byte*)points+OFFSET_STRUCT_POINT_Y Constant (const byte*) main::$7 = (byte*)points Constant (const byte*) main::$8 = (byte*)points+OFFSET_STRUCT_POINT_Y Constant (const byte*) main::$9 = (byte*)points Constant (const byte*) main::$10 = (byte*)points+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 Constant inlined main::i#0 = (byte) 0 Constant inlined main::$6 = (byte*)(const struct Point[2]) points+(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 Constant inlined idx#0 = (byte) 0 Constant inlined main::$7 = (byte*)(const struct Point[2]) points Constant inlined main::$10 = (byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y Constant inlined main::$8 = (byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y Successful SSA optimization Pass2ConstantInlining Consolidated array index constant in *((byte*)points+1*SIZEOF_STRUCT_POINT) Consolidated array index constant in *((byte*)points+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() (void()) main() main: scope:[main] from @1 [4] *((byte*)(const struct Point[2]) points) ← (byte) 1 [5] *((byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 [6] *((byte*)(const struct Point[2]) points+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 [7] *((byte*)(const struct Point[2]) points+(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 + (byte~) main::$4) [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points+(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 (void()) print((byte) print::p_x , (byte) print::p_y) print: scope:[print] from main::@1 [16] *((const byte*) SCREEN + (byte) idx#12) ← (byte) print::p_x#0 [17] (byte) idx#3 ← ++ (byte) idx#12 [18] *((const byte*) SCREEN + (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) 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 (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 / MOS6502X // 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) ← (byte) 1 -- _deref_pbuc1=vbuc2 lda #1 sta points // [5] *((byte*)(const struct Point[2]) points+(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+(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+(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.z idx_12 // [8] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#1] -- vbuz1=vbuc1 lda #0 sta.z 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.z i asl sta.z __4 // [10] (byte) print::p_x#0 ← *((byte*)(const struct Point[2]) points + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuz2 ldy.z __4 lda points,y sta.z print.p_x // [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuz2 ldy.z __4 lda points+OFFSET_STRUCT_POINT_Y,y sta.z 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.z i // [14] if((byte) main::i#1!=(byte) 2) goto main::@1 -- vbuz1_neq_vbuc1_then_la1 lda #2 cmp.z 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 + (byte) idx#12) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z p_x ldy.z idx_12 sta SCREEN,y // [17] (byte) idx#3 ← ++ (byte) idx#12 -- vbuz1=_inc_vbuz2 ldy.z idx_12 iny sty.z idx // [18] *((const byte*) SCREEN + (byte) idx#3) ← (byte) print::p_y#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z p_y ldy.z idx sta SCREEN,y // [19] (byte) idx#10 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuz2 ldy.z idx iny sty.z 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) ← (byte) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [5] *((byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [6] *((byte*)(const struct Point[2]) points+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] *((byte*)(const struct Point[2]) points+(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) ← (byte) 1 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [5] *((byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y) ← (byte) 2 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [6] *((byte*)(const struct Point[2]) points+(byte) 1*(const byte) SIZEOF_STRUCT_POINT) ← (byte) 3 [ ] ( main:2 [ ] ) always clobbers reg byte a Statement [7] *((byte*)(const struct Point[2]) points+(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) ← (byte) 1 -- _deref_pbuc1=vbuc2 lda #1 sta points // [5] *((byte*)(const struct Point[2]) points+(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+(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+(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.z 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 + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points,y sta.z print.p_x // [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points+OFFSET_STRUCT_POINT_Y,y sta.z 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 + (byte) idx#12) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z p_x ldy.z idx sta SCREEN,y // [17] (byte) idx#3 ← ++ (byte) idx#12 -- vbuyy=_inc_vbuz1 ldy.z idx iny // [18] *((const byte*) SCREEN + (byte) idx#3) ← (byte) print::p_y#0 -- pbuc1_derefidx_vbuyy=vbuz1 lda.z p_y sta SCREEN,y // [19] (byte) idx#10 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuyy iny sty.z 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.z idx Succesful ASM optimization Pass5UnnecesaryLoadElimination 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___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 __b1: 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 (const byte*) SCREEN 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 (const struct Point[2]) points 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) ← (byte) 1 -- _deref_pbuc1=vbuc2 lda #1 sta points // [5] *((byte*)(const struct Point[2]) points+(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+(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+(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.z 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 + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points,y sta.z print.p_x // [11] (byte) print::p_y#0 ← *((byte*)(const struct Point[2]) points+(const byte) OFFSET_STRUCT_POINT_Y + (byte~) main::$4) -- vbuz1=pbuc1_derefidx_vbuyy lda points+OFFSET_STRUCT_POINT_Y,y sta.z 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 + (byte) idx#12) ← (byte) print::p_x#0 -- pbuc1_derefidx_vbuz1=vbuz2 lda.z p_x ldy.z 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 + (byte) idx#3) ← (byte) print::p_y#0 -- pbuc1_derefidx_vbuyy=vbuz1 lda.z p_y sta SCREEN,y // SCREEN[idx++] = p.y; // [19] (byte) idx#10 ← ++ (byte) idx#3 -- vbuz1=_inc_vbuyy iny sty.z idx // print::@return // } // [20] return rts } // File Data points: .fill 2*2, 0